Skip to content

Commit c39dda0

Browse files
Stanislav Kinsburskiiliuw
authored andcommitted
mshv: Add refcount and locking to mem regions
Introduce kref-based reference counting and spinlock protection for memory regions in Hyper-V partition management. This change improves memory region lifecycle management and ensures thread-safe access to the region list. Previously, the regions list was protected by the partition mutex. However, this approach is too heavy for frequent fault and invalidation operations. Finer grained locking is now used to improve efficiency and concurrency. This is a precursor to supporting movable memory regions. Fault and invalidation handling for movable regions will require safe traversal of the region list and holding a region reference while performing invalidation or fault operations. Signed-off-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com> Signed-off-by: Wei Liu <wei.liu@kernel.org>
1 parent abceb42 commit c39dda0

3 files changed

Lines changed: 45 additions & 12 deletions

File tree

drivers/hv/mshv_regions.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Authors: Microsoft Linux virtualization team
88
*/
99

10+
#include <linux/kref.h>
1011
#include <linux/mm.h>
1112
#include <linux/vmalloc.h>
1213

@@ -154,6 +155,8 @@ struct mshv_mem_region *mshv_region_create(u64 guest_pfn, u64 nr_pages,
154155
if (!is_mmio)
155156
region->flags.range_pinned = true;
156157

158+
kref_init(&region->refcount);
159+
157160
return region;
158161
}
159162

@@ -311,13 +314,13 @@ static int mshv_region_unmap(struct mshv_mem_region *region)
311314
mshv_region_chunk_unmap);
312315
}
313316

314-
void mshv_region_destroy(struct mshv_mem_region *region)
317+
static void mshv_region_destroy(struct kref *ref)
315318
{
319+
struct mshv_mem_region *region =
320+
container_of(ref, struct mshv_mem_region, refcount);
316321
struct mshv_partition *partition = region->partition;
317322
int ret;
318323

319-
hlist_del(&region->hnode);
320-
321324
if (mshv_partition_encrypted(partition)) {
322325
ret = mshv_region_share(region);
323326
if (ret) {
@@ -334,3 +337,13 @@ void mshv_region_destroy(struct mshv_mem_region *region)
334337

335338
vfree(region);
336339
}
340+
341+
void mshv_region_put(struct mshv_mem_region *region)
342+
{
343+
kref_put(&region->refcount, mshv_region_destroy);
344+
}
345+
346+
int mshv_region_get(struct mshv_mem_region *region)
347+
{
348+
return kref_get_unless_zero(&region->refcount);
349+
}

drivers/hv/mshv_root.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ do { \
7272

7373
struct mshv_mem_region {
7474
struct hlist_node hnode;
75+
struct kref refcount;
7576
u64 nr_pages;
7677
u64 start_gfn;
7778
u64 start_uaddr;
@@ -97,6 +98,8 @@ struct mshv_partition {
9798
u64 pt_id;
9899
refcount_t pt_ref_count;
99100
struct mutex pt_mutex;
101+
102+
spinlock_t pt_mem_regions_lock;
100103
struct hlist_head pt_mem_regions; // not ordered
101104

102105
u32 pt_vp_count;
@@ -319,6 +322,7 @@ int mshv_region_unshare(struct mshv_mem_region *region);
319322
int mshv_region_map(struct mshv_mem_region *region);
320323
void mshv_region_invalidate(struct mshv_mem_region *region);
321324
int mshv_region_pin(struct mshv_mem_region *region);
322-
void mshv_region_destroy(struct mshv_mem_region *region);
325+
void mshv_region_put(struct mshv_mem_region *region);
326+
int mshv_region_get(struct mshv_mem_region *region);
323327

324328
#endif /* _MSHV_ROOT_H_ */

drivers/hv/mshv_root_main.c

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,13 +1086,15 @@ static int mshv_partition_create_region(struct mshv_partition *partition,
10861086
u64 nr_pages = HVPFN_DOWN(mem->size);
10871087

10881088
/* Reject overlapping regions */
1089+
spin_lock(&partition->pt_mem_regions_lock);
10891090
hlist_for_each_entry(rg, &partition->pt_mem_regions, hnode) {
10901091
if (mem->guest_pfn + nr_pages <= rg->start_gfn ||
10911092
rg->start_gfn + rg->nr_pages <= mem->guest_pfn)
10921093
continue;
1093-
1094+
spin_unlock(&partition->pt_mem_regions_lock);
10941095
return -EEXIST;
10951096
}
1097+
spin_unlock(&partition->pt_mem_regions_lock);
10961098

10971099
rg = mshv_region_create(mem->guest_pfn, nr_pages,
10981100
mem->userspace_addr, mem->flags,
@@ -1224,8 +1226,9 @@ mshv_map_user_memory(struct mshv_partition *partition,
12241226
if (ret)
12251227
goto errout;
12261228

1227-
/* Install the new region */
1229+
spin_lock(&partition->pt_mem_regions_lock);
12281230
hlist_add_head(&region->hnode, &partition->pt_mem_regions);
1231+
spin_unlock(&partition->pt_mem_regions_lock);
12291232

12301233
return 0;
12311234

@@ -1244,17 +1247,27 @@ mshv_unmap_user_memory(struct mshv_partition *partition,
12441247
if (!(mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP)))
12451248
return -EINVAL;
12461249

1250+
spin_lock(&partition->pt_mem_regions_lock);
1251+
12471252
region = mshv_partition_region_by_gfn(partition, mem.guest_pfn);
1248-
if (!region)
1249-
return -EINVAL;
1253+
if (!region) {
1254+
spin_unlock(&partition->pt_mem_regions_lock);
1255+
return -ENOENT;
1256+
}
12501257

12511258
/* Paranoia check */
12521259
if (region->start_uaddr != mem.userspace_addr ||
12531260
region->start_gfn != mem.guest_pfn ||
1254-
region->nr_pages != HVPFN_DOWN(mem.size))
1261+
region->nr_pages != HVPFN_DOWN(mem.size)) {
1262+
spin_unlock(&partition->pt_mem_regions_lock);
12551263
return -EINVAL;
1264+
}
1265+
1266+
hlist_del(&region->hnode);
12561267

1257-
mshv_region_destroy(region);
1268+
spin_unlock(&partition->pt_mem_regions_lock);
1269+
1270+
mshv_region_put(region);
12581271

12591272
return 0;
12601273
}
@@ -1657,8 +1670,10 @@ static void destroy_partition(struct mshv_partition *partition)
16571670
remove_partition(partition);
16581671

16591672
hlist_for_each_entry_safe(region, n, &partition->pt_mem_regions,
1660-
hnode)
1661-
mshv_region_destroy(region);
1673+
hnode) {
1674+
hlist_del(&region->hnode);
1675+
mshv_region_put(region);
1676+
}
16621677

16631678
/* Withdraw and free all pages we deposited */
16641679
hv_call_withdraw_memory(U64_MAX, NUMA_NO_NODE, partition->pt_id);
@@ -1856,6 +1871,7 @@ mshv_ioctl_create_partition(void __user *user_arg, struct device *module_dev)
18561871

18571872
INIT_HLIST_HEAD(&partition->pt_devices);
18581873

1874+
spin_lock_init(&partition->pt_mem_regions_lock);
18591875
INIT_HLIST_HEAD(&partition->pt_mem_regions);
18601876

18611877
mshv_eventfd_init(partition);

0 commit comments

Comments
 (0)