Skip to content

Commit 6538b62

Browse files
mdrothsean-jc
authored andcommitted
KVM: guest_memfd: Remove partial hugepage handling from kvm_gmem_populate()
kvm_gmem_populate(), and the associated post-populate callbacks, have some limited support for dealing with guests backed by hugepages by passing the order information along to each post-populate callback and iterating through the pages passed to kvm_gmem_populate() in hugepage-chunks. However, guest_memfd doesn't yet support hugepages, and in most cases additional changes in the kvm_gmem_populate() path would also be needed to actually allow for this functionality. This makes the existing code unnecessarily complex, and makes changes difficult to work through upstream due to theoretical impacts on hugepage support that can't be considered properly without an actual hugepage implementation to reference. So for now, remove what's there so changes for things like in-place conversion can be implemented/reviewed more efficiently. Suggested-by: Vishal Annapurve <vannapurve@google.com> Co-developed-by: Vishal Annapurve <vannapurve@google.com> Signed-off-by: Vishal Annapurve <vannapurve@google.com> Tested-by: Vishal Annapurve <vannapurve@google.com> Tested-by: Kai Huang <kai.huang@intel.com> Signed-off-by: Michael Roth <michael.roth@amd.com> Tested-by: Yan Zhao <yan.y.zhao@intel.com> Reviewed-by: Yan Zhao <yan.y.zhao@intel.com> Link: https://patch.msgid.link/20260108214622.1084057-3-michael.roth@amd.com [sean: check for !IS_ERR() before checking folio_order()] Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 60b590d commit 6538b62

4 files changed

Lines changed: 56 additions & 72 deletions

File tree

arch/x86/kvm/svm/sev.c

Lines changed: 37 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2267,67 +2267,53 @@ struct sev_gmem_populate_args {
22672267
int fw_error;
22682268
};
22692269

2270-
static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn_start, kvm_pfn_t pfn,
2271-
void __user *src, int order, void *opaque)
2270+
static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
2271+
void __user *src, void *opaque)
22722272
{
22732273
struct sev_gmem_populate_args *sev_populate_args = opaque;
2274+
struct sev_data_snp_launch_update fw_args = {0};
22742275
struct kvm_sev_info *sev = to_kvm_sev_info(kvm);
2275-
int n_private = 0, ret, i;
2276-
int npages = (1 << order);
2277-
gfn_t gfn;
2276+
bool assigned = false;
2277+
int level;
2278+
int ret;
22782279

22792280
if (WARN_ON_ONCE(sev_populate_args->type != KVM_SEV_SNP_PAGE_TYPE_ZERO && !src))
22802281
return -EINVAL;
22812282

2282-
for (gfn = gfn_start, i = 0; gfn < gfn_start + npages; gfn++, i++) {
2283-
struct sev_data_snp_launch_update fw_args = {0};
2284-
bool assigned = false;
2285-
int level;
2286-
2287-
ret = snp_lookup_rmpentry((u64)pfn + i, &assigned, &level);
2288-
if (ret || assigned) {
2289-
pr_debug("%s: Failed to ensure GFN 0x%llx RMP entry is initial shared state, ret: %d assigned: %d\n",
2290-
__func__, gfn, ret, assigned);
2291-
ret = ret ? -EINVAL : -EEXIST;
2292-
goto err;
2293-
}
2283+
ret = snp_lookup_rmpentry((u64)pfn, &assigned, &level);
2284+
if (ret || assigned) {
2285+
pr_debug("%s: Failed to ensure GFN 0x%llx RMP entry is initial shared state, ret: %d assigned: %d\n",
2286+
__func__, gfn, ret, assigned);
2287+
ret = ret ? -EINVAL : -EEXIST;
2288+
goto out;
2289+
}
22942290

2295-
if (src) {
2296-
void *vaddr = kmap_local_pfn(pfn + i);
2291+
if (src) {
2292+
void *vaddr = kmap_local_pfn(pfn);
22972293

2298-
if (copy_from_user(vaddr, src + i * PAGE_SIZE, PAGE_SIZE)) {
2299-
kunmap_local(vaddr);
2300-
ret = -EFAULT;
2301-
goto err;
2302-
}
2294+
if (copy_from_user(vaddr, src, PAGE_SIZE)) {
23032295
kunmap_local(vaddr);
2296+
ret = -EFAULT;
2297+
goto out;
23042298
}
2305-
2306-
ret = rmp_make_private(pfn + i, gfn << PAGE_SHIFT, PG_LEVEL_4K,
2307-
sev_get_asid(kvm), true);
2308-
if (ret)
2309-
goto err;
2310-
2311-
n_private++;
2312-
2313-
fw_args.gctx_paddr = __psp_pa(sev->snp_context);
2314-
fw_args.address = __sme_set(pfn_to_hpa(pfn + i));
2315-
fw_args.page_size = PG_LEVEL_TO_RMP(PG_LEVEL_4K);
2316-
fw_args.page_type = sev_populate_args->type;
2317-
2318-
ret = __sev_issue_cmd(sev_populate_args->sev_fd, SEV_CMD_SNP_LAUNCH_UPDATE,
2319-
&fw_args, &sev_populate_args->fw_error);
2320-
if (ret)
2321-
goto fw_err;
2299+
kunmap_local(vaddr);
23222300
}
23232301

2324-
return 0;
2302+
ret = rmp_make_private(pfn, gfn << PAGE_SHIFT, PG_LEVEL_4K,
2303+
sev_get_asid(kvm), true);
2304+
if (ret)
2305+
goto out;
2306+
2307+
fw_args.gctx_paddr = __psp_pa(sev->snp_context);
2308+
fw_args.address = __sme_set(pfn_to_hpa(pfn));
2309+
fw_args.page_size = PG_LEVEL_TO_RMP(PG_LEVEL_4K);
2310+
fw_args.page_type = sev_populate_args->type;
23252311

2326-
fw_err:
2312+
ret = __sev_issue_cmd(sev_populate_args->sev_fd, SEV_CMD_SNP_LAUNCH_UPDATE,
2313+
&fw_args, &sev_populate_args->fw_error);
23272314
/*
23282315
* If the firmware command failed handle the reclaim and cleanup of that
2329-
* PFN specially vs. prior pages which can be cleaned up below without
2330-
* needing to reclaim in advance.
2316+
* PFN before reporting an error.
23312317
*
23322318
* Additionally, when invalid CPUID function entries are detected,
23332319
* firmware writes the expected values into the page and leaves it
@@ -2337,26 +2323,20 @@ static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn_start, kvm_pfn_t pf
23372323
* information to provide information on which CPUID leaves/fields
23382324
* failed CPUID validation.
23392325
*/
2340-
if (!snp_page_reclaim(kvm, pfn + i) &&
2326+
if (ret && !snp_page_reclaim(kvm, pfn) &&
23412327
sev_populate_args->type == KVM_SEV_SNP_PAGE_TYPE_CPUID &&
23422328
sev_populate_args->fw_error == SEV_RET_INVALID_PARAM) {
2343-
void *vaddr = kmap_local_pfn(pfn + i);
2329+
void *vaddr = kmap_local_pfn(pfn);
23442330

2345-
if (copy_to_user(src + i * PAGE_SIZE, vaddr, PAGE_SIZE))
2331+
if (copy_to_user(src, vaddr, PAGE_SIZE))
23462332
pr_debug("Failed to write CPUID page back to userspace\n");
23472333

23482334
kunmap_local(vaddr);
23492335
}
23502336

2351-
/* pfn + i is hypervisor-owned now, so skip below cleanup for it. */
2352-
n_private--;
2353-
2354-
err:
2355-
pr_debug("%s: exiting with error ret %d (fw_error %d), restoring %d gmem PFNs to shared.\n",
2356-
__func__, ret, sev_populate_args->fw_error, n_private);
2357-
for (i = 0; i < n_private; i++)
2358-
kvm_rmp_make_shared(kvm, pfn + i, PG_LEVEL_4K);
2359-
2337+
out:
2338+
pr_debug("%s: exiting with return code %d (fw_error %d)\n",
2339+
__func__, ret, sev_populate_args->fw_error);
23602340
return ret;
23612341
}
23622342

arch/x86/kvm/vmx/tdx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3118,7 +3118,7 @@ struct tdx_gmem_post_populate_arg {
31183118
};
31193119

31203120
static int tdx_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
3121-
void __user *src, int order, void *_arg)
3121+
void __user *src, void *_arg)
31223122
{
31233123
struct tdx_gmem_post_populate_arg *arg = _arg;
31243124
struct kvm_tdx *kvm_tdx = to_kvm_tdx(kvm);

include/linux/kvm_host.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2581,7 +2581,7 @@ int kvm_arch_gmem_prepare(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, int max_ord
25812581
* Returns the number of pages that were populated.
25822582
*/
25832583
typedef int (*kvm_gmem_populate_cb)(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
2584-
void __user *src, int order, void *opaque);
2584+
void __user *src, void *opaque);
25852585

25862586
long kvm_gmem_populate(struct kvm *kvm, gfn_t gfn, void __user *src, long npages,
25872587
kvm_gmem_populate_cb post_populate, void *opaque);

virt/kvm/guest_memfd.c

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,15 @@ static struct folio *kvm_gmem_get_folio(struct inode *inode, pgoff_t index)
151151
mapping_gfp_mask(inode->i_mapping), policy);
152152
mpol_cond_put(policy);
153153

154+
/*
155+
* External interfaces like kvm_gmem_get_pfn() support dealing
156+
* with hugepages to a degree, but internally, guest_memfd currently
157+
* assumes that all folios are order-0 and handling would need
158+
* to be updated for anything otherwise (e.g. page-clearing
159+
* operations).
160+
*/
161+
WARN_ON_ONCE(!IS_ERR(folio) && folio_order(folio));
162+
154163
return folio;
155164
}
156165

@@ -829,7 +838,7 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long
829838
struct kvm_memory_slot *slot;
830839
void __user *p;
831840

832-
int ret = 0, max_order;
841+
int ret = 0;
833842
long i;
834843

835844
lockdep_assert_held(&kvm->slots_lock);
@@ -848,7 +857,7 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long
848857
filemap_invalidate_lock(file->f_mapping);
849858

850859
npages = min_t(ulong, slot->npages - (start_gfn - slot->base_gfn), npages);
851-
for (i = 0; i < npages; i += (1 << max_order)) {
860+
for (i = 0; i < npages; i++) {
852861
struct folio *folio;
853862
gfn_t gfn = start_gfn + i;
854863
pgoff_t index = kvm_gmem_get_index(slot, gfn);
@@ -860,7 +869,7 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long
860869
break;
861870
}
862871

863-
folio = __kvm_gmem_get_pfn(file, slot, index, &pfn, &is_prepared, &max_order);
872+
folio = __kvm_gmem_get_pfn(file, slot, index, &pfn, &is_prepared, NULL);
864873
if (IS_ERR(folio)) {
865874
ret = PTR_ERR(folio);
866875
break;
@@ -874,20 +883,15 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long
874883
}
875884

876885
folio_unlock(folio);
877-
WARN_ON(!IS_ALIGNED(gfn, 1 << max_order) ||
878-
(npages - i) < (1 << max_order));
879886

880887
ret = -EINVAL;
881-
while (!kvm_range_has_memory_attributes(kvm, gfn, gfn + (1 << max_order),
882-
KVM_MEMORY_ATTRIBUTE_PRIVATE,
883-
KVM_MEMORY_ATTRIBUTE_PRIVATE)) {
884-
if (!max_order)
885-
goto put_folio_and_exit;
886-
max_order--;
887-
}
888+
if (!kvm_range_has_memory_attributes(kvm, gfn, gfn + 1,
889+
KVM_MEMORY_ATTRIBUTE_PRIVATE,
890+
KVM_MEMORY_ATTRIBUTE_PRIVATE))
891+
goto put_folio_and_exit;
888892

889893
p = src ? src + i * PAGE_SIZE : NULL;
890-
ret = post_populate(kvm, gfn, pfn, p, max_order, opaque);
894+
ret = post_populate(kvm, gfn, pfn, p, opaque);
891895
if (!ret)
892896
kvm_gmem_mark_prepared(folio);
893897

0 commit comments

Comments
 (0)