On Tue, Apr 21, 2026 at 9:31 AM Sean Christopherson <[email protected]> wrote: > > On Fri, Apr 10, 2026, Nikita Kalyazin wrote: > > From: Patrick Roy <[email protected]> > > > > 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/[email protected] >
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

