Linux Confidential Computing Development
 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: 51+ 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-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox