[PATCH v12 10/16] KVM: guest_memfd: Add flag to remove from direct map
Frank van der Linden
fvdl at google.com
Tue Apr 21 10:08:48 PDT 2026
On Tue, Apr 21, 2026 at 9:31 AM Sean Christopherson <seanjc at google.com> wrote:
>
> On Fri, Apr 10, 2026, Nikita Kalyazin wrote:
> > From: Patrick Roy <patrick.roy at linux.dev>
> >
> > Add GUEST_MEMFD_FLAG_NO_DIRECT_MAP flag for KVM_CREATE_GUEST_MEMFD()
> > ioctl. When set, guest_memfd folios will be removed from the direct map
> > after preparation, with direct map entries only restored when the folios
> > are freed.
> >
> > To ensure these folios do not end up in places where the kernel cannot
> > deal with them, set AS_NO_DIRECT_MAP on the guest_memfd's struct
> > address_space if GUEST_MEMFD_FLAG_NO_DIRECT_MAP is requested.
> >
> > Note that this flag causes removal of direct map entries for all
> > guest_memfd folios independent of whether they are "shared" or "private"
> > (although current guest_memfd only supports either all folios in the
> > "shared" state, or all folios in the "private" state if
> > GUEST_MEMFD_FLAG_MMAP is not set). The usecase for removing direct map
> > entries of also the shared parts of guest_memfd are a special type of
> > non-CoCo VM where, host userspace is trusted to have access to all of
> > guest memory, but where Spectre-style transient execution attacks
> > through the host kernel's direct map should still be mitigated. In this
> > setup, KVM retains access to guest memory via userspace mappings of
> > guest_memfd, which are reflected back into KVM's memslots via
> > userspace_addr. This is needed for things like MMIO emulation on x86_64
> > to work.
> >
> > Direct map entries are zapped right before guest or userspace mappings
> > of gmem folios are set up, e.g. in kvm_gmem_fault_user_mapping() or
> > kvm_gmem_get_pfn() [called from the KVM MMU code].
>
> ...
>
> > +#define KVM_GMEM_FOLIO_NO_DIRECT_MAP BIT(0)
> > +
> > +static bool kvm_gmem_folio_no_direct_map(struct folio *folio)
> > +{
> > + return ((u64)folio->private) & KVM_GMEM_FOLIO_NO_DIRECT_MAP;
> > +}
> > +
> > +static int kvm_gmem_folio_zap_direct_map(struct folio *folio)
> > +{
> > + int r = 0;
> > +
> > + VM_WARN_ON_FOLIO(!folio_test_locked(folio), folio);
> > +
> > + if (WARN_ON_ONCE(!(GMEM_I(folio_inode(folio))->flags & GUEST_MEMFD_FLAG_NO_DIRECT_MAP)))
> > + return -EINVAL;
> > +
> > + if (kvm_gmem_folio_no_direct_map(folio))
> > + goto out;
> > +
> > + r = folio_zap_direct_map(folio);
> > + if (!r)
> > + folio->private = (void *)((u64)folio->private | KVM_GMEM_FOLIO_NO_DIRECT_MAP);
> > +
> > +out:
> > + return r;
> > +}
> > +
> > +static void kvm_gmem_folio_restore_direct_map(struct folio *folio)
> > +{
> > + folio_restore_direct_map(folio);
> > + folio->private = (void *)((u64)folio->private & ~KVM_GMEM_FOLIO_NO_DIRECT_MAP);
> > +}
>
> Making guest_memfd responsible for zapping and restoring the direct map on a per-
> folio basis feels wrong given the addition of AS_NO_DIRECT_MAP. I especially don't
> like that the "rules" for when an AS_NO_DIRECT_MAP folio has a direct map will vary
> based on the owner, and even within an owner (e.g. guest_memfd) will be ad hoc.
>
> E.g. as per the series to add guest_memfd write() support[*]:
>
> When direct map removal is implemented [2]
> - write() will not be allowed to access pages that have already
> been removed from direct map
> - on completion, write() will remove the populated pages from
> direct map
>
> That's pretty gross ABI, because with KVM_GMEM_FOLIO_NO_DIRECT_MAP, userspace can
> write() exactly once. To re-write memory, I assume userspace would need to do a
> PUNCH_HOLE or truncate.
>
> What's preventing us from handling this automagically in e.g. filemap_add_folio()
> and filemap_remove_folio()? Then the usage rules are pretty straightforward: the
> kernel must *always* assume the direct map is invalid for folios from
> AS_NO_DIRECT_MAP mappings.
>
> Then if KVM needs to utilize a kernel mapping, e.g. in kvm_gmem_populate(), KVM
> could use dedicated variants of kmap_local_xxx() to deal with a local mapping for
> a folio/page without a direct map. Or, KVM could simply disallow the specific
> sequence that would require KVM to do the memcpy (I'm pretty sure we can do that
> with in-place shared=>private conversion support).
>
> I realize that could throw a big wrench into write() performance, but IMO, before
> merging either series, we need a complete story for exactly how this will all fit
> together, in a maintainable fashion and with sane ABI.
>
> [*] https://lore.kernel.org/all/20251114151828.98165-1-kalyazin@amazon.com
>
I agree with this - this approach would also allow for memory that was
never in the direct map to begin with, or has been taken out already
(for which I happen to have a use case :-)). guest_memfd and other
code can then assume that AS_NO_DIRECT_MAP means they have to take
explicit action to map it if needed. It's a clean, simple ABI.
With the current set of patches, it seems like this couldn't be done
in a clean manner.
- Frank
More information about the linux-riscv
mailing list