All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Michael Roth <michael.roth@amd.com>
Cc: Ackerley Tng <ackerleytng@google.com>,
	aik@amd.com, andrew.jones@linux.dev,  binbin.wu@linux.intel.com,
	brauner@kernel.org, chao.p.peng@linux.intel.com,
	 david@kernel.org, jmattson@google.com, jthoughton@google.com,
	 oupton@kernel.org, pankaj.gupta@amd.com, qperret@google.com,
	 rick.p.edgecombe@intel.com, rientjes@google.com,
	shivankg@amd.com,  steven.price@arm.com, willy@infradead.org,
	wyihan@google.com,  yan.y.zhao@intel.com, forkloop@google.com,
	pratyush@kernel.org,  suzuki.poulose@arm.com,
	aneesh.kumar@kernel.org, liam@infradead.org,
	 Paolo Bonzini <pbonzini@redhat.com>,
	Thomas Gleixner <tglx@kernel.org>, Ingo Molnar <mingo@redhat.com>,
	 Borislav Petkov <bp@alien8.de>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	x86@kernel.org,  "H. Peter Anvin" <hpa@zytor.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	 Masami Hiramatsu <mhiramat@kernel.org>,
	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	 Jonathan Corbet <corbet@lwn.net>,
	Shuah Khan <skhan@linuxfoundation.org>,
	 Shuah Khan <shuah@kernel.org>,
	Vishal Annapurve <vannapurve@google.com>,
	 Andrew Morton <akpm@linux-foundation.org>,
	Chris Li <chrisl@kernel.org>,  Kairui Song <kasong@tencent.com>,
	Kemeng Shi <shikemeng@huaweicloud.com>,
	 Nhat Pham <nphamcs@gmail.com>, Barry Song <baohua@kernel.org>,
	 Axel Rasmussen <axelrasmussen@google.com>,
	Yuanchu Xie <yuanchu@google.com>,  Wei Xu <weixugc@google.com>,
	Youngjun Park <youngjun.park@lge.com>,
	 Qi Zheng <qi.zheng@linux.dev>,
	Shakeel Butt <shakeel.butt@linux.dev>,
	 Kiryl Shutsemau <kas@kernel.org>,
	Baoquan He <baoquan.he@linux.dev>, Jason Gunthorpe <jgg@ziepe.ca>,
	 John Hubbard <jhubbard@nvidia.com>, Peter Xu <peterx@redhat.com>,
	tarunsahu@google.com,  Fuad Tabba <fuad.tabba@linux.dev>,
	Vlastimil Babka <vbabka@kernel.org>,
	kvm@vger.kernel.org,  linux-kernel@vger.kernel.org,
	linux-trace-kernel@vger.kernel.org,  linux-doc@vger.kernel.org,
	linux-kselftest@vger.kernel.org,  linux-mm@kvack.org,
	linux-coco@lists.linux.dev
Subject: Re: [PATCH v11 15/46] KVM: guest_memfd: Call arch make_shared callback for to-shared conversion
Date: Wed, 26 Aug 2026 15:33:43 -0700	[thread overview]
Message-ID: <ao9px1j7CLYXMiGP@google.com> (raw)
In-Reply-To: <mtbqvvvpwbzybgy6z47lwui6ag53kyubub3hkczui7u72zxesl@lnwsglrgwl5p>

On Wed, Aug 26, 2026, Michael Roth wrote:
> On Wed, Aug 26, 2026 at 12:44:40PM -0700, Sean Christopherson wrote:
> > On Wed, Aug 26, 2026, Ackerley Tng wrote:
> > > Omit support for calling the arch hook to make private, since SNP, the only
> > > implementer of the arch make-private hook today, would actually prefer
> > > making private only just before faulting memory into the NPTs.
> > > 
> > > Calling the make-private arch hook would require iterating both bindings
> > > and the filemap to find the intersection of bindings and allocated
> > > folios.
> > 
> > Why would KVM need to iterate over the bindings?  Only the RMP needs to be updated,
> > whether or not the RMP is currently reachable is irrelevant, no?
> > 
> > Subsequent calls to kvm_arch_gmem_make_private() from kvm_gmem_get_pfn() would be
> > superfluous, but that's already possible, e.g. if an NPT mappings is removed for
> > whatever reason.
> > 
> > > On top of that, SNP would need to figure out whether to actually
> > > make private based on whether the memory is about to be faulted, or
> > > whether it is a conversion.
> > 
> > This is a non-issue, no?  As above, sev_gmem_make_private() already bails early
> > if the page is already assigned in the RMP.
> > 
> > I don't care terribly about how SNP handles this, but I do want accurate reasoning
> > and justification so that if/when we revisit any of this in the future, we can make
> > informed decisions.  Because unless I'm missing something, this is an optimization
> > choice (eager vs. lazy to-private conversions), not a complexity tradeoff, and it's
> > not clear to me how we decided the lazy approach would provide better performance.
> 
> I'm not sure it was discussed in this context, but there was some past
> discussion around preallocation (i.e. "should we call make-private arch
> hooks at allocation time to allow for faster boot for prealloc guests"
> and then that ran into the TDX side of things where that would
> necessarily entail pre-mapping into the sEPT as well, so
> KVM_PRE_FAULT_MEMORY ended up being the interface we adopted for this
> purpose.
> 
> Since then, KVM_PRE_FAULT_MEMORY was added on the QEMU side and gets
> called after all conversions for both SNP/TDX, and even without
> preallocation it's a decent performance boost to SNP. If we were to
> switch to pre-calling the make-private arch hook then the
> KVM_PRE_FAULT_MEMORY call because partly redundant and in practice we'd
> probably see a small performance loss.
> 
> So there's real performance differences here but it's sort of been
> addressed through a solution that offers additional performance
> benefits on top so there's no longer as much to be gained here I think.

Or another way to look at it, eager conversion would allow QEMU to drop its
workaround.

To be clear, I'm a-ok with the code as-is, I just want to make sure we document
exactly why we're choosing this implementation.

> But I guess that's a moot point...
> 
> > 
> > > Calling the make-shared arch hook and not the make-private arch hook does
> > > leak SNP-specific details into guest_memfd (as in, why only make-shared
> > > during conversions but not make-private?), but the additional complexity is
> > > not worth taking on until guest_memfd has a user actually requiring an arch
> > > make-private call.
> > 
> > ...
> > 
> > > +#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_CONVERT
> > > +static void kvm_gmem_make_shared(struct inode *inode, pgoff_t start, pgoff_t end)
> > > +{
> > > +	struct folio_batch fbatch;
> > > +	pgoff_t next = start;
> > > +	int i;
> > > +
> > > +	folio_batch_init(&fbatch);
> > > +	while (filemap_get_folios(inode->i_mapping, &next, end - 1, &fbatch)) {
> > > +		for (i = 0; i < folio_batch_count(&fbatch); ++i) {
> > > +			struct folio *folio = fbatch.folios[i];
> > > +			pgoff_t start_index, end_index;
> > > +			kvm_pfn_t start_pfn;
> > > +			kvm_pfn_t nr_pages;
> > > +
> > > +			start_index = max(start, folio->index);
> > > +			end_index = min(end, folio_next_index(folio));
> > > +			/*
> > > +			 * end_index is either in folio or points to
> > > +			 * the first page of the next folio. Hence,
> > > +			 * all pages in range [start_index, end_index)
> > > +			 * are contiguous.
> > > +			 */
> > > +			start_pfn = folio_file_pfn(folio, start_index);
> > > +			nr_pages = end_index - start_index;
> > > +
> > > +			kvm_arch_gmem_make_shared(start_pfn, nr_pages);
> > > +		}
> > > +
> > > +		folio_batch_release(&fbatch);
> > > +		cond_resched();
> > > +	}
> > > +}
> > > +#else
> > > +static void kvm_gmem_make_shared(struct inode *inode, pgoff_t start, pgoff_t end) {}
> > > +#endif
> > > +
> > >  static int __kvm_gmem_set_attributes(struct inode *inode, pgoff_t start,
> > >  				     size_t nr_pages, uint64_t attrs,
> > >  				     pgoff_t *err_index)
> > > @@ -624,7 +661,12 @@ static int __kvm_gmem_set_attributes(struct inode *inode, pgoff_t start,
> > >  
> > >  	filter = to_private ? KVM_FILTER_SHARED : KVM_FILTER_PRIVATE;
> > >  	kvm_gmem_invalidate_start(inode, start, end, filter);
> > > +
> > > +	if (!to_private && kvm_arch_has_gmem_convert())
> > > +		kvm_gmem_make_shared(inode, start, end);
> > > +
> > >  	mas_store_prealloc(&mas, xa_mk_value(attrs));
> > > +
> > >  	kvm_gmem_invalidate_end(inode, start, end);
> > 
> > The real reason I responded...
> > 
> > Thinking about the Secure AVIC mess made me realize zapping NPTs for SNP VMs isn't
> > strictly necessary in this path.  The PFN isn't changing, just the attributes, and
> > that's (obviously) tracked in the RMP.  KVM doesn't need to zap SPTEs to induce a
> > fault, because the mismatched C-bit vs. RMP status will cause an #NPF(RMP), and
> > AFAICT kvm_mmu_page_fault() will do the right thing.  A misbehaving guest could
> > continue to access the shared data (assuming we stick with lazy conversions), but
> > that should be fine?  E.g. it's not really any different than implicit conversions.
> 
> I think this should work in theory...
> 
> zapping NPTs means the vCPUs will keep retrying until they get the page first
> vCPU that faulted is trying to grab from gmem. If we don't zap, then they will
> instead be racing with the first vCPU, and if they lose they will be
> generating implicit page faults that trigger conversions back to shared,

Why would they trigger conversions back to shared?  Assuming the guest isn't
being silly and accessing the memory with C-bit=0, the #NPF will be tagged ENC
and KVM will treat it as a private access.

	if (is_sev_snp_guest(vcpu) && (error_code & PFERR_GUEST_ENC_MASK))
		error_code |= PFERR_PRIVATE_ACCESS;

kvm_mmu_faultin_pfn() will see "fault->is_private == kvm_is_private_gfn()" as
true, i.e. won't kick out to userspace.  Same for __kvm_mmu_faultin_pfn(), which
will call into kvm_mmu_faultin_pfn_gmem() => kvm_gmem_get_pfn(), see that the
gfn is private, and call kvm_arch_gmem_make_private() as needed.

I don't see how #NPFs due to the RMP being SHARED would be handled differently
than !PRESENT #NPFs.

> and most likely the first vCPU will re-trigger an implicit shared->private
> conversion when it does PVALIDATE. Worst case, the guest fails PVALIDATE
> due to racing with itself.
> 
> It's a bit chaotic, but it shouldn't break anything other than the guest, and
> it's only something we'd generally expect for buggy/malicious guests anyway.
> 
> However...
> 
> > 
> > In other words, couldn't we do this (as an on-top optimization)?  The only wrinkle
> > I can think of is that it could delay reconstituion of a hugepage, especially if
> > we opted for eager conversion (because the guest wouldn't hit #NPFs to trigger the
> > hugepage promotion).
> > 
> > diff --git arch/x86/kvm/mmu/mmu.c arch/x86/kvm/mmu/mmu.c
> > index 62f751952ad8..61f3e270ab61 100644
> > --- arch/x86/kvm/mmu/mmu.c
> > +++ arch/x86/kvm/mmu/mmu.c
> > @@ -1670,6 +1670,7 @@ static bool __kvm_rmap_zap_gfn_range(struct kvm *kvm,
> >  
> >  bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
> >  {
> > +       unsigned long shared_private =  KVM_FILTER_SHARED | KVM_FILTER_PRIVATE;
> >         bool flush = false;
> >  
> >         /*
> > @@ -1683,6 +1684,10 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
> >         lockdep_assert_once(kvm->mmu_invalidate_in_progress ||
> >                             lockdep_is_held(&kvm->slots_lock));
> >  
> > +       if (gmem_in_place_conversion && !kvm_has_mirrored_tdp(kvm) &&
> > +           ((range->attr_filter & shared_private) != shared_private))
> > +               return false;
> > +
> 
> This path would also trigger for hole-punching, where we would want to
> zap the NPT entries. So we might need to adjust the logic for more than
> just shared vs. private to account for that.

No, because PUNCH_HOLE uses kvm_gmem_get_all_gfns_filter(), which does:

	if (gmem_in_place_conversion)
		return KVM_FILTER_SHARED | KVM_FILTER_PRIVATE;

i.e. won't get short-circuited.  Though I agree with the implication that this
is super fragile/subtle.



  reply	other threads:[~2026-08-26 22:33 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-26  9:17 [PATCH v11 00/46] guest_memfd: In-place conversion support Ackerley Tng
2026-08-26  9:17 ` [PATCH v11 01/46] KVM: guest_memfd: Optimize away conversion overheads via dead-code elimination Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 02/46] KVM: guest_memfd: Use kvm_mem_is_private() when populating guest_memfd memory Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 03/46] KVM: guest_memfd: Introduce per-gmem attributes, use to guard user mappings Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 04/46] KVM: Rename KVM_GENERIC_MEMORY_ATTRIBUTES to KVM_VM_MEMORY_ATTRIBUTES Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 05/46] KVM: Enumerate support for PRIVATE memory iff kvm_arch_has_private_mem is defined Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 06/46] KVM: Rename memory attribute APIs to prepare for in-place gmem conversion Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 07/46] KVM: Rename kvm_mem_is_private() to kvm_is_private_gfn() Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 08/46] KVM: Provide generic interface for checking memory private/shared status Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 09/46] KVM: guest_memfd: Stub in ability to enable in-place shared<=>private conversion Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 10/46] KVM: Consolidate private memory and guest_memfd ifdeffery in kvm_host.h Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 11/46] KVM: guest_memfd: Invalidate both SHARED and PRIVATE mappings for in-place conversions Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 12/46] KVM: guest_memfd: Pass mapping type filter to invalidation helper Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 13/46] KVM: guest_memfd: Add base support for KVM_SET_MEMORY_ATTRIBUTES2 Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 14/46] KVM: guest_memfd: Ensure pages are not in use before conversion Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 15/46] KVM: guest_memfd: Call arch make_shared callback for to-shared conversion Ackerley Tng
2026-08-26 19:44   ` Sean Christopherson
2026-08-26 22:17     ` Michael Roth
2026-08-26 22:33       ` Sean Christopherson [this message]
2026-08-26 23:47         ` Michael Roth
2026-08-27 20:54           ` Sean Christopherson
2026-08-28  4:19     ` Ackerley Tng
2026-08-28 14:57       ` Sean Christopherson
2026-08-26  9:18 ` [PATCH v11 16/46] KVM: guest_memfd: Return early if range already has requested attributes Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 17/46] mm/gup: factor out LRU cache draining for folio into lru_cache_drain_for_folio() Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 18/46] KVM: guest_memfd: Handle lru_add fbatch refcounts during conversion safety check Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 19/46] KVM: guest_memfd: Zero page while getting pfn Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 20/46] KVM: SEV: Make 'uaddr' parameter optional for KVM_SEV_SNP_LAUNCH_UPDATE Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 21/46] KVM: TDX: Make source page optional for KVM_TDX_INIT_MEM_REGION Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 22/46] KVM: Move KVM_VM_MEMORY_ATTRIBUTES config definition to x86 Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 23/46] KVM: Let userspace disable per-VM mem attributes, enable per-gmem attributes Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 24/46] KVM: guest_memfd: Enable INIT_SHARED on guest_memfd for x86 Coco VMs Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 25/46] KVM: selftests: Create gmem fd before "regular" fd when adding memslot Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 26/46] KVM: selftests: Rename guest_memfd{,_offset} to gmem_{fd,offset} Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 27/46] KVM: selftests: Add support for mmap() on guest_memfd in core library Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 28/46] KVM: selftests: Add selftests global for guest memory attributes capability Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 29/46] KVM: selftests: Add helpers for calling ioctls on guest_memfd Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 30/46] KVM: selftests: Test basic single-page conversion flow Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 31/46] KVM: selftests: Test conversion flow when INIT_SHARED Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 32/46] KVM: selftests: Test conversion precision in guest_memfd Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 33/46] KVM: selftests: Test conversion before allocation Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 34/46] KVM: selftests: Convert with allocated folios in different layouts Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 35/46] KVM: selftests: Test that truncation does not change shared/private status Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 36/46] KVM: selftests: Test that shared/private status is consistent across processes Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 37/46] KVM: selftests: Add helpers to pin pages with CONFIG_GUP_TEST Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 38/46] KVM: selftests: Test conversion with elevated page refcount Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 39/46] KVM: selftests: Reset shared memory after hole-punching Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 40/46] KVM: selftests: Provide function to look up guest_memfd details from gpa Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 41/46] KVM: selftests: Provide common function to set memory attributes Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 42/46] KVM: selftests: Make TEST_EXPECT_SIGBUS thread-safe Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 43/46] KVM: selftests: Support guest_memfd attributes in private_mem_conversions_test Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 44/46] KVM: selftests: Set up page size and alignment independently for guest_memfd Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 45/46] KVM: selftests: Test in-place conversions in private_mem_conversions_test Ackerley Tng
2026-08-26  9:18 ` [PATCH v11 46/46] KVM: selftests: Update private memory exits test to work with per-gmem attributes Ackerley Tng

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ao9px1j7CLYXMiGP@google.com \
    --to=seanjc@google.com \
    --cc=ackerleytng@google.com \
    --cc=aik@amd.com \
    --cc=akpm@linux-foundation.org \
    --cc=andrew.jones@linux.dev \
    --cc=aneesh.kumar@kernel.org \
    --cc=axelrasmussen@google.com \
    --cc=baohua@kernel.org \
    --cc=baoquan.he@linux.dev \
    --cc=binbin.wu@linux.intel.com \
    --cc=bp@alien8.de \
    --cc=brauner@kernel.org \
    --cc=chao.p.peng@linux.intel.com \
    --cc=chrisl@kernel.org \
    --cc=corbet@lwn.net \
    --cc=dave.hansen@linux.intel.com \
    --cc=david@kernel.org \
    --cc=forkloop@google.com \
    --cc=fuad.tabba@linux.dev \
    --cc=hpa@zytor.com \
    --cc=jgg@ziepe.ca \
    --cc=jhubbard@nvidia.com \
    --cc=jmattson@google.com \
    --cc=jthoughton@google.com \
    --cc=kas@kernel.org \
    --cc=kasong@tencent.com \
    --cc=kvm@vger.kernel.org \
    --cc=liam@infradead.org \
    --cc=linux-coco@lists.linux.dev \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mhiramat@kernel.org \
    --cc=michael.roth@amd.com \
    --cc=mingo@redhat.com \
    --cc=nphamcs@gmail.com \
    --cc=oupton@kernel.org \
    --cc=pankaj.gupta@amd.com \
    --cc=pbonzini@redhat.com \
    --cc=peterx@redhat.com \
    --cc=pratyush@kernel.org \
    --cc=qi.zheng@linux.dev \
    --cc=qperret@google.com \
    --cc=rick.p.edgecombe@intel.com \
    --cc=rientjes@google.com \
    --cc=rostedt@goodmis.org \
    --cc=shakeel.butt@linux.dev \
    --cc=shikemeng@huaweicloud.com \
    --cc=shivankg@amd.com \
    --cc=shuah@kernel.org \
    --cc=skhan@linuxfoundation.org \
    --cc=steven.price@arm.com \
    --cc=suzuki.poulose@arm.com \
    --cc=tarunsahu@google.com \
    --cc=tglx@kernel.org \
    --cc=vannapurve@google.com \
    --cc=vbabka@kernel.org \
    --cc=weixugc@google.com \
    --cc=willy@infradead.org \
    --cc=wyihan@google.com \
    --cc=x86@kernel.org \
    --cc=yan.y.zhao@intel.com \
    --cc=youngjun.park@lge.com \
    --cc=yuanchu@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.