This is the v7 of this series which tries to implement the fd-based KVM
guest private memory. The patches are based on latest kvm/queue branch
commit:
b9b71f43683a (kvm/queue) KVM: x86/mmu: Buffer nested MMU
split_desc_cache only by default capacity
Introduction
------------
In general this patch series introduce fd-based memslot which provides
guest memory through memory file descriptor fd[offset,size] instead of
hva/size. The fd can be created from a supported memory filesystem
like tmpfs/hugetlbfs etc. which we refer as memory backing store. KVM
and the the memory backing store exchange callbacks when such memslot
gets created. At runtime KVM will call into callbacks provided by the
backing store to get the pfn with the fd+offset. Memory backing store
will also call into KVM callbacks when userspace punch hole on the fd
to notify KVM to unmap secondary MMU page table entries.
Comparing to existing hva-based memslot, this new type of memslot allows
guest memory unmapped from host userspace like QEMU and even the kernel
itself, therefore reduce attack surface and prevent bugs.
Based on this fd-based memslot, we can build guest private memory that
is going to be used in confidential computing environments such as Intel
TDX and AMD SEV. When supported, the memory backing store can provide
more enforcement on the fd and KVM can use a single memslot to hold both
the private and shared part of the guest memory.
mm extension
---------------------
Introduces new MFD_INACCESSIBLE flag for memfd_create(), the file
created with these flags cannot read(), write() or mmap() etc via normal
MMU operations. The file content can only be used with the newly
introduced memfile_notifier extension.
The memfile_notifier extension provides two sets of callbacks for KVM to
interact with the memory backing store:
- memfile_notifier_ops: callbacks for memory backing store to notify
KVM when memory gets invalidated.
- backing store callbacks: callbacks for KVM to call into memory
backing store to request memory pages for guest private memory.
The memfile_notifier extension also provides APIs for memory backing
store to register/unregister itself and to trigger the notifier when the
bookmarked memory gets invalidated.
The patchset also introduces a new memfd seal F_SEAL_AUTO_ALLOCATE to
prevent double allocation caused by unintentional guest when we only
have a single side of the shared/private memfds effective.
memslot extension
-----------------
Add the private fd and the fd offset to existing 'shared' memslot so
that both private/shared guest memory can live in one single memslot.
A page in the memslot is either private or shared. Whether a guest page
is private or shared is maintained through reusing existing SEV ioctls
KVM_MEMORY_ENCRYPT_{UN,}REG_REGION.
Test
----
To test the new functionalities of this patch TDX patchset is needed.
Since TDX patchset has not been merged so I did two kinds of test:
- Regresion test on kvm/queue (this patchset)
Most new code are not covered. Code also in below repo:
https://github.com/chao-p/linux/tree/privmem-v7
- New Funational test on latest TDX code
The patch is rebased to latest TDX code and tested the new
funcationalities. See below repos:
Linux: https://github.com/chao-p/linux/tree/privmem-v7-tdx
QEMU: https://github.com/chao-p/qemu/tree/privmem-v7
An example QEMU command line for TDX test:
-object tdx-guest,id=tdx,debug=off,sept-ve-disable=off \
-machine confidential-guest-support=tdx \
-object memory-backend-memfd-private,id=ram1,size=${mem} \
-machine memory-backend=ram1
Changelog
----------
v7:
- Move the private/shared info from backing store to KVM.
- Introduce F_SEAL_AUTO_ALLOCATE to avoid double allocation.
- Rework on the sync mechanism between zap/page fault paths.
- Addressed other comments in v6.
v6:
- Re-organzied patch for both mm/KVM parts.
- Added flags for memfile_notifier so its consumers can state their
features and memory backing store can check against these flags.
- Put a backing store reference in the memfile_notifier and move pfn_ops
into backing store.
- Only support boot time backing store register.
- Overall KVM part improvement suggested by Sean and some others.
v5:
- Removed userspace visible F_SEAL_INACCESSIBLE, instead using an
in-kernel flag (SHM_F_INACCESSIBLE for shmem). Private fd can only
be created by MFD_INACCESSIBLE.
- Introduced new APIs for backing store to register itself to
memfile_notifier instead of direct function call.
- Added the accounting and restriction for MFD_INACCESSIBLE memory.
- Added KVM API doc for new memslot extensions and man page for the new
MFD_INACCESSIBLE flag.
- Removed the overlap check for mapping the same file+offset into
multiple gfns due to perf consideration, warned in document.
- Addressed other comments in v4.
v4:
- Decoupled the callbacks between KVM/mm from memfd and use new
name 'memfile_notifier'.
- Supported register multiple memslots to the same backing store.
- Added per-memslot pfn_ops instead of per-system.
- Reworked the invalidation part.
- Improved new KVM uAPIs (private memslot extension and memory
error) per Sean's suggestions.
- Addressed many other minor fixes for comments from v3.
v3:
- Added locking protection when calling
invalidate_page_range/fallocate callbacks.
- Changed memslot structure to keep use useraddr for shared memory.
- Re-organized F_SEAL_INACCESSIBLE and MEMFD_OPS.
- Added MFD_INACCESSIBLE flag to force F_SEAL_INACCESSIBLE.
- Commit message improvement.
- Many small fixes for comments from the last version.
Links to previous discussions
-----------------------------
[1] Original design proposal:
https://lkml.kernel.org/kvm/20210824005248.200037-1-seanjc@google.com/
[2] Updated proposal and RFC patch v1:
https://lkml.kernel.org/linux-fsdevel/20211111141352.26311-1-chao.p.peng@linux.intel.com/
[3] Patch v5: https://lkml.org/lkml/2022/5/19/861
Chao Peng (12):
mm: Add F_SEAL_AUTO_ALLOCATE seal to memfd
selftests/memfd: Add tests for F_SEAL_AUTO_ALLOCATE
mm: Introduce memfile_notifier
mm/memfd: Introduce MFD_INACCESSIBLE flag
KVM: Rename KVM_PRIVATE_MEM_SLOTS to KVM_INTERNAL_MEM_SLOTS
KVM: Use gfn instead of hva for mmu_notifier_retry
KVM: Rename mmu_notifier_*
KVM: Extend the memslot to support fd-based private memory
KVM: Add KVM_EXIT_MEMORY_FAULT exit
KVM: Register/unregister the guest private memory regions
KVM: Handle page fault for private memory
KVM: Enable and expose KVM_MEM_PRIVATE
Kirill A. Shutemov (1):
mm/shmem: Support memfile_notifier
Documentation/virt/kvm/api.rst | 77 +++++-
arch/arm64/kvm/mmu.c | 8 +-
arch/mips/include/asm/kvm_host.h | 2 +-
arch/mips/kvm/mmu.c | 10 +-
arch/powerpc/include/asm/kvm_book3s_64.h | 2 +-
arch/powerpc/kvm/book3s_64_mmu_host.c | 4 +-
arch/powerpc/kvm/book3s_64_mmu_hv.c | 4 +-
arch/powerpc/kvm/book3s_64_mmu_radix.c | 6 +-
arch/powerpc/kvm/book3s_hv_nested.c | 2 +-
arch/powerpc/kvm/book3s_hv_rm_mmu.c | 8 +-
arch/powerpc/kvm/e500_mmu_host.c | 4 +-
arch/riscv/kvm/mmu.c | 4 +-
arch/x86/include/asm/kvm_host.h | 3 +-
arch/x86/kvm/Kconfig | 3 +
arch/x86/kvm/mmu.h | 2 -
arch/x86/kvm/mmu/mmu.c | 74 +++++-
arch/x86/kvm/mmu/mmu_internal.h | 18 ++
arch/x86/kvm/mmu/mmutrace.h | 1 +
arch/x86/kvm/mmu/paging_tmpl.h | 4 +-
arch/x86/kvm/x86.c | 2 +-
include/linux/kvm_host.h | 105 +++++---
include/linux/memfile_notifier.h | 91 +++++++
include/linux/shmem_fs.h | 2 +
include/uapi/linux/fcntl.h | 1 +
include/uapi/linux/kvm.h | 37 +++
include/uapi/linux/memfd.h | 1 +
mm/Kconfig | 4 +
mm/Makefile | 1 +
mm/memfd.c | 18 +-
mm/memfile_notifier.c | 123 ++++++++++
mm/shmem.c | 125 +++++++++-
tools/testing/selftests/memfd/memfd_test.c | 166 +++++++++++++
virt/kvm/Kconfig | 3 +
virt/kvm/kvm_main.c | 272 ++++++++++++++++++---
virt/kvm/pfncache.c | 14 +-
35 files changed, 1074 insertions(+), 127 deletions(-)
create mode 100644 include/linux/memfile_notifier.h
create mode 100644 mm/memfile_notifier.c
--
2.25.1
Normally, a write to unallocated space of a file or the hole of a sparse
file automatically causes space allocation, for memfd, this equals to
memory allocation. This new seal prevents such automatically allocating,
either this is from a direct write() or a write on the previously
mmap-ed area. The seal does not prevent fallocate() so an explicit
fallocate() can still cause allocating and can be used to reserve
memory.
This is used to prevent unintentional allocation from userspace on a
stray or careless write and any intentional allocation should use an
explicit fallocate(). One of the main usecases is to avoid memory double
allocation for confidential computing usage where we use two memfds to
back guest memory and at a single point only one memfd is alive and we
want to prevent memory allocation for the other memfd which may have
been mmap-ed previously. More discussion can be found at:
https://lkml.org/lkml/2022/6/14/1255
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Chao Peng <redacted>
---
include/uapi/linux/fcntl.h | 1 +
mm/memfd.c | 3 ++-
mm/shmem.c | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
From: David Hildenbrand <hidden> Date: 2022-07-21 09:44:22
On 06.07.22 10:20, Chao Peng wrote:
quoted hunk
Normally, a write to unallocated space of a file or the hole of a sparse
file automatically causes space allocation, for memfd, this equals to
memory allocation. This new seal prevents such automatically allocating,
either this is from a direct write() or a write on the previously
mmap-ed area. The seal does not prevent fallocate() so an explicit
fallocate() can still cause allocating and can be used to reserve
memory.
This is used to prevent unintentional allocation from userspace on a
stray or careless write and any intentional allocation should use an
explicit fallocate(). One of the main usecases is to avoid memory double
allocation for confidential computing usage where we use two memfds to
back guest memory and at a single point only one memfd is alive and we
want to prevent memory allocation for the other memfd which may have
been mmap-ed previously. More discussion can be found at:
https://lkml.org/lkml/2022/6/14/1255
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Chao Peng <redacted>
---
include/uapi/linux/fcntl.h | 1 +
mm/memfd.c | 3 ++-
mm/shmem.c | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
Why only "on writes" and not "on reads". IIRC, shmem doesn't support the
shared zeropage, so you'll simply allocate a new page via read() or on
read faults.
Also, I *think* you can place pages via userfaultfd into shmem. Not sure
if that would count "auto alloc", but it would certainly bypass fallocate().
--
Thanks,
David / dhildenb
From: David Hildenbrand <hidden> Date: 2022-07-21 09:50:57
On 21.07.22 11:44, David Hildenbrand wrote:
On 06.07.22 10:20, Chao Peng wrote:
quoted
Normally, a write to unallocated space of a file or the hole of a sparse
file automatically causes space allocation, for memfd, this equals to
memory allocation. This new seal prevents such automatically allocating,
either this is from a direct write() or a write on the previously
mmap-ed area. The seal does not prevent fallocate() so an explicit
fallocate() can still cause allocating and can be used to reserve
memory.
This is used to prevent unintentional allocation from userspace on a
stray or careless write and any intentional allocation should use an
explicit fallocate(). One of the main usecases is to avoid memory double
allocation for confidential computing usage where we use two memfds to
back guest memory and at a single point only one memfd is alive and we
want to prevent memory allocation for the other memfd which may have
been mmap-ed previously. More discussion can be found at:
https://lkml.org/lkml/2022/6/14/1255
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Chao Peng <redacted>
---
include/uapi/linux/fcntl.h | 1 +
mm/memfd.c | 3 ++-
mm/shmem.c | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
Why only "on writes" and not "on reads". IIRC, shmem doesn't support the
shared zeropage, so you'll simply allocate a new page via read() or on
read faults.
Correction: on read() we don't allocate a fresh page. But on read faults
we would. So this comment here needs clarification.
Also, I *think* you can place pages via userfaultfd into shmem. Not sure
if that would count "auto alloc", but it would certainly bypass fallocate().
From: Sean Christopherson <seanjc@google.com> Date: 2022-07-21 15:05:19
On Thu, Jul 21, 2022, David Hildenbrand wrote:
On 21.07.22 11:44, David Hildenbrand wrote:
quoted
On 06.07.22 10:20, Chao Peng wrote:
quoted
Normally, a write to unallocated space of a file or the hole of a sparse
file automatically causes space allocation, for memfd, this equals to
memory allocation. This new seal prevents such automatically allocating,
either this is from a direct write() or a write on the previously
mmap-ed area. The seal does not prevent fallocate() so an explicit
fallocate() can still cause allocating and can be used to reserve
memory.
This is used to prevent unintentional allocation from userspace on a
stray or careless write and any intentional allocation should use an
explicit fallocate(). One of the main usecases is to avoid memory double
allocation for confidential computing usage where we use two memfds to
back guest memory and at a single point only one memfd is alive and we
want to prevent memory allocation for the other memfd which may have
been mmap-ed previously. More discussion can be found at:
https://lkml.org/lkml/2022/6/14/1255
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Chao Peng <redacted>
---
include/uapi/linux/fcntl.h | 1 +
mm/memfd.c | 3 ++-
mm/shmem.c | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
Why only "on writes" and not "on reads". IIRC, shmem doesn't support the
shared zeropage, so you'll simply allocate a new page via read() or on
read faults.
Correction: on read() we don't allocate a fresh page. But on read faults
we would. So this comment here needs clarification.
Not just the comment, the code too. The intent of F_SEAL_AUTO_ALLOCATE is very
much to block _all_ implicit allocations (or maybe just fault-based allocations
if "implicit" is too broad of a description).
On Thu, Jul 21, 2022 at 03:05:09PM +0000, Sean Christopherson wrote:
On Thu, Jul 21, 2022, David Hildenbrand wrote:
quoted
On 21.07.22 11:44, David Hildenbrand wrote:
quoted
On 06.07.22 10:20, Chao Peng wrote:
quoted
Normally, a write to unallocated space of a file or the hole of a sparse
file automatically causes space allocation, for memfd, this equals to
memory allocation. This new seal prevents such automatically allocating,
either this is from a direct write() or a write on the previously
mmap-ed area. The seal does not prevent fallocate() so an explicit
fallocate() can still cause allocating and can be used to reserve
memory.
This is used to prevent unintentional allocation from userspace on a
stray or careless write and any intentional allocation should use an
explicit fallocate(). One of the main usecases is to avoid memory double
allocation for confidential computing usage where we use two memfds to
back guest memory and at a single point only one memfd is alive and we
want to prevent memory allocation for the other memfd which may have
been mmap-ed previously. More discussion can be found at:
https://lkml.org/lkml/2022/6/14/1255
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Chao Peng <redacted>
---
include/uapi/linux/fcntl.h | 1 +
mm/memfd.c | 3 ++-
mm/shmem.c | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
Why only "on writes" and not "on reads". IIRC, shmem doesn't support the
shared zeropage, so you'll simply allocate a new page via read() or on
read faults.
Correction: on read() we don't allocate a fresh page. But on read faults
we would. So this comment here needs clarification.
Not just the comment, the code too. The intent of F_SEAL_AUTO_ALLOCATE is very
much to block _all_ implicit allocations (or maybe just fault-based allocations
if "implicit" is too broad of a description).
So maybe still your initial suggestion F_SEAL_FAULT_ALLOCATIONS? One
reason I don't like it is the write() ioctl also cause allocation and we
want to prevent it.
Chao
Normally, a write to unallocated space of a file or the hole of a sparse
file automatically causes space allocation, for memfd, this equals to
memory allocation. This new seal prevents such automatically allocating,
either this is from a direct write() or a write on the previously
mmap-ed area. The seal does not prevent fallocate() so an explicit
fallocate() can still cause allocating and can be used to reserve
memory.
This is used to prevent unintentional allocation from userspace on a
stray or careless write and any intentional allocation should use an
explicit fallocate(). One of the main usecases is to avoid memory double
allocation for confidential computing usage where we use two memfds to
back guest memory and at a single point only one memfd is alive and we
want to prevent memory allocation for the other memfd which may have
been mmap-ed previously. More discussion can be found at:
https://lkml.org/lkml/2022/6/14/1255
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Chao Peng <redacted>
---
include/uapi/linux/fcntl.h | 1 +
mm/memfd.c | 3 ++-
mm/shmem.c | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
Why only "on writes" and not "on reads". IIRC, shmem doesn't support the
shared zeropage, so you'll simply allocate a new page via read() or on
read faults.
Also, I *think* you can place pages via userfaultfd into shmem. Not sure
if that would count "auto alloc", but it would certainly bypass fallocate().
I was also thinking this at the same time, but for different reason:
"Want to populate private preboot memory with firmware payload", so was
thinking userfaulftd could be an option as direct writes are restricted?
Thanks,
Pankaj
On Thu, Jul 21, 2022 at 12:27:03PM +0200, Gupta, Pankaj wrote:
quoted
quoted
Normally, a write to unallocated space of a file or the hole of a sparse
file automatically causes space allocation, for memfd, this equals to
memory allocation. This new seal prevents such automatically allocating,
either this is from a direct write() or a write on the previously
mmap-ed area. The seal does not prevent fallocate() so an explicit
fallocate() can still cause allocating and can be used to reserve
memory.
This is used to prevent unintentional allocation from userspace on a
stray or careless write and any intentional allocation should use an
explicit fallocate(). One of the main usecases is to avoid memory double
allocation for confidential computing usage where we use two memfds to
back guest memory and at a single point only one memfd is alive and we
want to prevent memory allocation for the other memfd which may have
been mmap-ed previously. More discussion can be found at:
https://lkml.org/lkml/2022/6/14/1255
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Chao Peng <redacted>
---
include/uapi/linux/fcntl.h | 1 +
mm/memfd.c | 3 ++-
mm/shmem.c | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
Why only "on writes" and not "on reads". IIRC, shmem doesn't support the
shared zeropage, so you'll simply allocate a new page via read() or on
read faults.
Also, I *think* you can place pages via userfaultfd into shmem. Not sure
if that would count "auto alloc", but it would certainly bypass fallocate().
I was also thinking this at the same time, but for different reason:
"Want to populate private preboot memory with firmware payload", so was
thinking userfaulftd could be an option as direct writes are restricted?
If that can be a side effect, I definitely glad to see it, though I'm
still not clear how userfaultfd can be particularly helpful for that.
Chao
Normally, a write to unallocated space of a file or the hole of a sparse
file automatically causes space allocation, for memfd, this equals to
memory allocation. This new seal prevents such automatically allocating,
either this is from a direct write() or a write on the previously
mmap-ed area. The seal does not prevent fallocate() so an explicit
fallocate() can still cause allocating and can be used to reserve
memory.
This is used to prevent unintentional allocation from userspace on a
stray or careless write and any intentional allocation should use an
explicit fallocate(). One of the main usecases is to avoid memory double
allocation for confidential computing usage where we use two memfds to
back guest memory and at a single point only one memfd is alive and we
want to prevent memory allocation for the other memfd which may have
been mmap-ed previously. More discussion can be found at:
https://lkml.org/lkml/2022/6/14/1255
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Chao Peng <redacted>
---
include/uapi/linux/fcntl.h | 1 +
mm/memfd.c | 3 ++-
mm/shmem.c | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
Why only "on writes" and not "on reads". IIRC, shmem doesn't support the
shared zeropage, so you'll simply allocate a new page via read() or on
read faults.
Also, I *think* you can place pages via userfaultfd into shmem. Not sure
if that would count "auto alloc", but it would certainly bypass fallocate().
I was also thinking this at the same time, but for different reason:
"Want to populate private preboot memory with firmware payload", so was
thinking userfaulftd could be an option as direct writes are restricted?
If that can be a side effect, I definitely glad to see it, though I'm
still not clear how userfaultfd can be particularly helpful for that.
Was thinking if we can use userfaultfd to monitor the pagefault on
virtual firmware memory range and use to populate the private memory.
Not sure if it is a side effect. Was just theoretically thinking (for
now kept the idea aside as these enhancements can be worked later).
Thanks,
Pankaj
On Thu, Jul 21, 2022 at 11:44:11AM +0200, David Hildenbrand wrote:
On 06.07.22 10:20, Chao Peng wrote:
quoted
Normally, a write to unallocated space of a file or the hole of a sparse
file automatically causes space allocation, for memfd, this equals to
memory allocation. This new seal prevents such automatically allocating,
either this is from a direct write() or a write on the previously
mmap-ed area. The seal does not prevent fallocate() so an explicit
fallocate() can still cause allocating and can be used to reserve
memory.
This is used to prevent unintentional allocation from userspace on a
stray or careless write and any intentional allocation should use an
explicit fallocate(). One of the main usecases is to avoid memory double
allocation for confidential computing usage where we use two memfds to
back guest memory and at a single point only one memfd is alive and we
want to prevent memory allocation for the other memfd which may have
been mmap-ed previously. More discussion can be found at:
https://lkml.org/lkml/2022/6/14/1255
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Chao Peng <redacted>
---
include/uapi/linux/fcntl.h | 1 +
mm/memfd.c | 3 ++-
mm/shmem.c | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
Why only "on writes" and not "on reads". IIRC, shmem doesn't support the
shared zeropage, so you'll simply allocate a new page via read() or on
read faults.
Right, it also prevents read faults.
Also, I *think* you can place pages via userfaultfd into shmem. Not sure
if that would count "auto alloc", but it would certainly bypass fallocate().
Userfaultfd sounds interesting, will further investigate it. But a rough
look sounds it only faults to usrspace for write/read fault, not
write()? Also sounds it operates on vma and userfaultfd_register() takes
mmap_lock which is what we want to avoid for frequent
register/unregister during private/shared memory conversion.
Chao
From: Paolo Bonzini <pbonzini@redhat.com> Date: 2022-08-05 17:55:51
On 7/21/22 11:44, David Hildenbrand wrote:
Also, I*think* you can place pages via userfaultfd into shmem. Not
sure if that would count "auto alloc", but it would certainly bypass
fallocate().
Yeah, userfaultfd_register would probably have to forbid this for
F_SEAL_AUTO_ALLOCATE vmas. Maybe the memfile_node can be reused for
this, adding a new MEMFILE_F_NO_AUTO_ALLOCATE flags? Then
userfault_register would do something like
memfile_node_get_flags(vma->vm_file) and check the result.
This means moving this patch later, after "mm: Introduce memfile_notifier".
Thanks,
Paolo
From: David Hildenbrand <hidden> Date: 2022-08-05 18:06:13
On 05.08.22 19:55, Paolo Bonzini wrote:
On 7/21/22 11:44, David Hildenbrand wrote:
quoted
Also, I*think* you can place pages via userfaultfd into shmem. Not
sure if that would count "auto alloc", but it would certainly bypass
fallocate().
Yeah, userfaultfd_register would probably have to forbid this for
F_SEAL_AUTO_ALLOCATE vmas. Maybe the memfile_node can be reused for
this, adding a new MEMFILE_F_NO_AUTO_ALLOCATE flags? Then
userfault_register would do something like
memfile_node_get_flags(vma->vm_file) and check the result.
An alternative is to simply have the shmem allocation fail in a similar
way. Maybe it does already, I haven't checked (don't think so).
--
Thanks,
David / dhildenb
On Fri, Aug 05, 2022 at 08:06:03PM +0200, David Hildenbrand wrote:
On 05.08.22 19:55, Paolo Bonzini wrote:
quoted
On 7/21/22 11:44, David Hildenbrand wrote:
quoted
Also, I*think* you can place pages via userfaultfd into shmem. Not
sure if that would count "auto alloc", but it would certainly bypass
fallocate().
Yeah, userfaultfd_register would probably have to forbid this for
F_SEAL_AUTO_ALLOCATE vmas. Maybe the memfile_node can be reused for
this, adding a new MEMFILE_F_NO_AUTO_ALLOCATE flags? Then
userfault_register would do something like
memfile_node_get_flags(vma->vm_file) and check the result.
An alternative is to simply have the shmem allocation fail in a similar
way. Maybe it does already, I haven't checked (don't think so).
This sounds a better option. We don't need uAPI changes for
userfault_register uAPI but I guess we will still need a KVM uAPI,
either on the memslot or on the whole VM since Roth said this feature
should be optional because some usages may want to disable it for
performance reason. For details please see discussion:
https://lkml.org/lkml/2022/6/23/1905
Chao
On Fri, Aug 05, 2022 at 07:55:38PM +0200, Paolo Bonzini wrote:
On 7/21/22 11:44, David Hildenbrand wrote:
quoted
Also, I*think* you can place pages via userfaultfd into shmem. Not
sure if that would count "auto alloc", but it would certainly bypass
fallocate().
Yeah, userfaultfd_register would probably have to forbid this for
F_SEAL_AUTO_ALLOCATE vmas. Maybe the memfile_node can be reused for this,
adding a new MEMFILE_F_NO_AUTO_ALLOCATE flags? Then userfault_register
would do something like memfile_node_get_flags(vma->vm_file) and check the
result.
Then we need change userfault_register uAPI for a new property flag.
Userspace should still the decision-maker for this flag.
This means moving this patch later, after "mm: Introduce memfile_notifier".
From: Kirill A. Shutemov <hidden> Date: 2022-08-18 00:00:56
On Fri, Aug 05, 2022 at 07:55:38PM +0200, Paolo Bonzini wrote:
On 7/21/22 11:44, David Hildenbrand wrote:
quoted
Also, I*think* you can place pages via userfaultfd into shmem. Not
sure if that would count "auto alloc", but it would certainly bypass
fallocate().
Yeah, userfaultfd_register would probably have to forbid this for
F_SEAL_AUTO_ALLOCATE vmas. Maybe the memfile_node can be reused for this,
adding a new MEMFILE_F_NO_AUTO_ALLOCATE flags? Then userfault_register
would do something like memfile_node_get_flags(vma->vm_file) and check the
result.
I donno, memory allocation with userfaultfd looks pretty intentional to
me. Why would F_SEAL_AUTO_ALLOCATE prevent it?
Maybe we would need it in the future for post-copy migration or something?
Or existing practises around userfaultfd touch memory randomly and
therefore incompatible with F_SEAL_AUTO_ALLOCATE intent?
Note, that userfaultfd is only relevant for shared memory as it requires
VMA which we don't have for MFD_INACCESSIBLE.
--
Kiryl Shutsemau / Kirill A. Shutemov
From: David Hildenbrand <hidden> Date: 2022-08-23 07:37:06
On 18.08.22 01:41, Kirill A. Shutemov wrote:
On Fri, Aug 05, 2022 at 07:55:38PM +0200, Paolo Bonzini wrote:
quoted
On 7/21/22 11:44, David Hildenbrand wrote:
quoted
Also, I*think* you can place pages via userfaultfd into shmem. Not
sure if that would count "auto alloc", but it would certainly bypass
fallocate().
Yeah, userfaultfd_register would probably have to forbid this for
F_SEAL_AUTO_ALLOCATE vmas. Maybe the memfile_node can be reused for this,
adding a new MEMFILE_F_NO_AUTO_ALLOCATE flags? Then userfault_register
would do something like memfile_node_get_flags(vma->vm_file) and check the
result.
I donno, memory allocation with userfaultfd looks pretty intentional to
me. Why would F_SEAL_AUTO_ALLOCATE prevent it?
Can't we say the same about a write()?
Maybe we would need it in the future for post-copy migration or something?
Or existing practises around userfaultfd touch memory randomly and
therefore incompatible with F_SEAL_AUTO_ALLOCATE intent?
Note, that userfaultfd is only relevant for shared memory as it requires
VMA which we don't have for MFD_INACCESSIBLE.
This feature (F_SEAL_AUTO_ALLOCATE) is independent of all the lovely
encrypted VM stuff, so it doesn't matter how it relates to MFD_INACCESSIBLE.
--
Thanks,
David / dhildenb
On Tue, Aug 23, 2022 at 09:36:57AM +0200, David Hildenbrand wrote:
On 18.08.22 01:41, Kirill A. Shutemov wrote:
quoted
On Fri, Aug 05, 2022 at 07:55:38PM +0200, Paolo Bonzini wrote:
quoted
On 7/21/22 11:44, David Hildenbrand wrote:
quoted
Also, I*think* you can place pages via userfaultfd into shmem. Not
sure if that would count "auto alloc", but it would certainly bypass
fallocate().
Yeah, userfaultfd_register would probably have to forbid this for
F_SEAL_AUTO_ALLOCATE vmas. Maybe the memfile_node can be reused for this,
adding a new MEMFILE_F_NO_AUTO_ALLOCATE flags? Then userfault_register
would do something like memfile_node_get_flags(vma->vm_file) and check the
result.
I donno, memory allocation with userfaultfd looks pretty intentional to
me. Why would F_SEAL_AUTO_ALLOCATE prevent it?
Can't we say the same about a write()?
quoted
Maybe we would need it in the future for post-copy migration or something?
Or existing practises around userfaultfd touch memory randomly and
therefore incompatible with F_SEAL_AUTO_ALLOCATE intent?
Note, that userfaultfd is only relevant for shared memory as it requires
VMA which we don't have for MFD_INACCESSIBLE.
This feature (F_SEAL_AUTO_ALLOCATE) is independent of all the lovely
encrypted VM stuff, so it doesn't matter how it relates to MFD_INACCESSIBLE.
Right, this patch is for normal user accssible fd. In KVM this flag is
expected to be set on the shared part of the memslot, while all other
patches in this series are for private part of the memslot.
Private memory doesn't have this need because it's totally inaccissible
from userspace so no chance for userspace to write to the fd and cause
allocation by accident. While for shared memory, malicious/buggy guest
OS may cause userspace to write to any range of the shared fd and cause
memory allocation, even that range should the private memory not the
shared memory be visible to guest OS.
Chao
Hi Chao,
On Wed, Jul 6, 2022 at 9:25 AM Chao Peng [off-list ref] wrote:
quoted hunk
Normally, a write to unallocated space of a file or the hole of a sparse
file automatically causes space allocation, for memfd, this equals to
memory allocation. This new seal prevents such automatically allocating,
either this is from a direct write() or a write on the previously
mmap-ed area. The seal does not prevent fallocate() so an explicit
fallocate() can still cause allocating and can be used to reserve
memory.
This is used to prevent unintentional allocation from userspace on a
stray or careless write and any intentional allocation should use an
explicit fallocate(). One of the main usecases is to avoid memory double
allocation for confidential computing usage where we use two memfds to
back guest memory and at a single point only one memfd is alive and we
want to prevent memory allocation for the other memfd which may have
been mmap-ed previously. More discussion can be found at:
https://lkml.org/lkml/2022/6/14/1255
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Chao Peng <redacted>
---
include/uapi/linux/fcntl.h | 1 +
mm/memfd.c | 3 ++-
mm/shmem.c | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
On Fri, Aug 26, 2022 at 04:19:32PM +0100, Fuad Tabba wrote:
Hi Chao,
On Wed, Jul 6, 2022 at 9:25 AM Chao Peng [off-list ref] wrote:
quoted
Normally, a write to unallocated space of a file or the hole of a sparse
file automatically causes space allocation, for memfd, this equals to
memory allocation. This new seal prevents such automatically allocating,
either this is from a direct write() or a write on the previously
mmap-ed area. The seal does not prevent fallocate() so an explicit
fallocate() can still cause allocating and can be used to reserve
memory.
This is used to prevent unintentional allocation from userspace on a
stray or careless write and any intentional allocation should use an
explicit fallocate(). One of the main usecases is to avoid memory double
allocation for confidential computing usage where we use two memfds to
back guest memory and at a single point only one memfd is alive and we
want to prevent memory allocation for the other memfd which may have
been mmap-ed previously. More discussion can be found at:
https://lkml.org/lkml/2022/6/14/1255
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Chao Peng <redacted>
---
include/uapi/linux/fcntl.h | 1 +
mm/memfd.c | 3 ++-
mm/shmem.c | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 3 deletions(-)
@@ -594,6 +620,94 @@ static void mfd_fail_grow_write(int fd)}}+staticvoidmfd_assert_hole_write(intfd)+{+ssize_tl;+void*p;+char*p1;++/*+*huegtlbfsdoesnotsupportwrite,butwewantto+*verifyeverythingelsehere.+*/+if(!hugetlbfs_test){+/* verify direct write() succeeds */+l=write(fd,"\0\0\0\0",4);+if(l!=4){+printf("write() failed: %m\n");+abort();+}+}++/* verify mmaped write succeeds */+p=mmap(NULL,+mfd_def_size,+PROT_READ|PROT_WRITE,+MAP_SHARED,+fd,+0);+if(p==MAP_FAILED){+printf("mmap() failed: %m\n");+abort();+}+p1=(char*)p+mfd_def_size-1;+*p1='H';+if(*p1!='H'){+printf("mmaped write failed: %m\n");+abort();++}+munmap(p,mfd_def_size);+}++sigjmp_bufjbuf,*sigbuf;+staticvoidsig_handler(intsig,siginfo_t*siginfo,void*ptr)+{+if(sig==SIGBUS){+if(sigbuf)+siglongjmp(*sigbuf,1);+abort();+}+}++staticvoidmfd_fail_hole_write(intfd)+{+ssize_tl;+void*p;+char*p1;++/* verify direct write() fails */+l=write(fd,"data",4);+if(l>0){+printf("expected failure on write(), but got %d: %m\n",(int)l);+abort();+}++/* verify mmaped write fails */+p=mmap(NULL,+mfd_def_size,+PROT_READ|PROT_WRITE,+MAP_SHARED,+fd,+0);+if(p==MAP_FAILED){+printf("mmap() failed: %m\n");+abort();+}++sigbuf=&jbuf;+if(sigsetjmp(*sigbuf,1))+gotoout;++/* Below write should trigger SIGBUS signal */+p1=(char*)p+mfd_def_size-1;+*p1='H';+printf("failed to receive SIGBUS for mmaped write: %m\n");+abort();+out:+munmap(p,mfd_def_size);+}+staticintidle_thread_fn(void*arg){sigset_tset;
@@ -880,6 +994,57 @@ static void test_seal_resize(void)close(fd);}+/*+*TestF_SEAL_AUTO_ALLOCATE+*TestwhetherF_SEAL_AUTO_ALLOCATEactuallypreventsallocation.+*/+staticvoidtest_seal_auto_allocate(void)+{+structsigactionact;+intfd;++printf("%s SEAL-AUTO-ALLOCATE\n",memfd_str);++memset(&act,0,sizeof(act));+act.sa_sigaction=sig_handler;+act.sa_flags=SA_SIGINFO;+if(sigaction(SIGBUS,&act,0)){+printf("sigaction() failed: %m\n");+abort();+}++fd=mfd_assert_new("kern_memfd_seal_auto_allocate",+mfd_def_size,+MFD_CLOEXEC|MFD_ALLOW_SEALING);++/* read/write should pass if F_SEAL_AUTO_ALLOCATE not set */+mfd_assert_read(fd);+mfd_assert_hole_write(fd);++mfd_assert_has_seals(fd,0);+mfd_assert_add_seals(fd,F_SEAL_AUTO_ALLOCATE);+mfd_assert_has_seals(fd,F_SEAL_AUTO_ALLOCATE);++/* read/write should pass for pre-allocated area */+mfd_assert_read(fd);+mfd_assert_hole_write(fd);++mfd_assert_punch_hole(fd);++/* read should pass, write should fail in hole */+mfd_assert_read(fd);+mfd_fail_hole_write(fd);++mfd_assert_fallocate(fd);++/* read/write should pass after fallocate */+mfd_assert_read(fd);+mfd_assert_hole_write(fd);++close(fd);+}++/**Testsharingviadup()*TestthatsealsaresharedbetweenduppedFDsandthey'reallequal.
@@ -1059,6 +1224,7 @@ int main(int argc, char **argv)test_seal_shrink();test_seal_grow();test_seal_resize();+test_seal_auto_allocate();test_share_dup("SHARE-DUP","");test_share_mmap("SHARE-MMAP","");
@@ -594,6 +620,94 @@ static void mfd_fail_grow_write(int fd)}}+staticvoidmfd_assert_hole_write(intfd)+{+ssize_tl;+void*p;+char*p1;++/*+*huegtlbfsdoesnotsupportwrite,butwewantto+*verifyeverythingelsehere.+*/+if(!hugetlbfs_test){+/* verify direct write() succeeds */+l=write(fd,"\0\0\0\0",4);+if(l!=4){+printf("write() failed: %m\n");+abort();+}+}++/* verify mmaped write succeeds */+p=mmap(NULL,+mfd_def_size,+PROT_READ|PROT_WRITE,+MAP_SHARED,+fd,+0);+if(p==MAP_FAILED){+printf("mmap() failed: %m\n");+abort();+}+p1=(char*)p+mfd_def_size-1;+*p1='H';+if(*p1!='H'){+printf("mmaped write failed: %m\n");+abort();++}+munmap(p,mfd_def_size);+}++sigjmp_bufjbuf,*sigbuf;+staticvoidsig_handler(intsig,siginfo_t*siginfo,void*ptr)+{+if(sig==SIGBUS){+if(sigbuf)+siglongjmp(*sigbuf,1);+abort();+}+}++staticvoidmfd_fail_hole_write(intfd)+{+ssize_tl;+void*p;+char*p1;++/* verify direct write() fails */+l=write(fd,"data",4);+if(l>0){+printf("expected failure on write(), but got %d: %m\n",(int)l);+abort();+}++/* verify mmaped write fails */+p=mmap(NULL,+mfd_def_size,+PROT_READ|PROT_WRITE,+MAP_SHARED,+fd,+0);+if(p==MAP_FAILED){+printf("mmap() failed: %m\n");+abort();+}++sigbuf=&jbuf;+if(sigsetjmp(*sigbuf,1))+gotoout;++/* Below write should trigger SIGBUS signal */+p1=(char*)p+mfd_def_size-1;+*p1='H';
Maybe you want to verify separately, that bothj
quoted hunk
+ printf("failed to receive SIGBUS for mmaped write: %m\n");
+ abort();
+out:
+ munmap(p, mfd_def_size);
+}
+
static int idle_thread_fn(void *arg)
{
sigset_t set;
@@ -880,6 +994,57 @@ static void test_seal_resize(void) close(fd); }+/*+ * Test F_SEAL_AUTO_ALLOCATE+ * Test whether F_SEAL_AUTO_ALLOCATE actually prevents allocation.+ */+static void test_seal_auto_allocate(void)+{+ struct sigaction act;+ int fd;++ printf("%s SEAL-AUTO-ALLOCATE\n", memfd_str);++ memset(&act, 0, sizeof(act));+ act.sa_sigaction = sig_handler;+ act.sa_flags = SA_SIGINFO;+ if (sigaction(SIGBUS, &act, 0)) {+ printf("sigaction() failed: %m\n");+ abort();+ }++ fd = mfd_assert_new("kern_memfd_seal_auto_allocate",+ mfd_def_size,+ MFD_CLOEXEC | MFD_ALLOW_SEALING);++ /* read/write should pass if F_SEAL_AUTO_ALLOCATE not set */+ mfd_assert_read(fd);+ mfd_assert_hole_write(fd);++ mfd_assert_has_seals(fd, 0);+ mfd_assert_add_seals(fd, F_SEAL_AUTO_ALLOCATE);+ mfd_assert_has_seals(fd, F_SEAL_AUTO_ALLOCATE);++ /* read/write should pass for pre-allocated area */+ mfd_assert_read(fd);+ mfd_assert_hole_write(fd);++ mfd_assert_punch_hole(fd);++ /* read should pass, write should fail in hole */+ mfd_assert_read(fd);+ mfd_fail_hole_write(fd);++ mfd_assert_fallocate(fd);++ /* read/write should pass after fallocate */+ mfd_assert_read(fd);+ mfd_assert_hole_write(fd);++ close(fd);+}
What might make sense is to verify for the following operations:
* read()
* write()
* read via mmap
* write via mmap
After sealing on a hole, that there is *still* a hole and that only the
read() might succeed, with a comment stating that shmem optimized for
read on holes by reading from the shared zeropage.
I'd suggest decoupling hole_write from hole_mmap_write and similarly
have hole_read and hole_mmap_read.
You should be able to use fstat() to obtain the number of allocated
blocks to check that fairly easily.
--
Thanks,
David / dhildenb
This patch introduces memfile_notifier facility so existing memory file
subsystems (e.g. tmpfs/hugetlbfs) can provide memory pages to allow a
third kernel component to make use of memory bookmarked in the memory
file and gets notified when the pages in the memory file become
invalidated.
It will be used for KVM to use a file descriptor as the guest memory
backing store and KVM will use this memfile_notifier interface to
interact with memory file subsystems. In the future there might be other
consumers (e.g. VFIO with encrypted device memory).
It consists below components:
- memfile_backing_store: Each supported memory file subsystem can be
implemented as a memory backing store which bookmarks memory and
provides callbacks for other kernel systems (memfile_notifier
consumers) to interact with.
- memfile_notifier: memfile_notifier consumers defines callbacks and
associate them to a file using memfile_register_notifier().
- memfile_node: A memfile_node is associated with the file (inode) from
the backing store and includes feature flags and a list of registered
memfile_notifier for notifying.
In KVM usages, userspace is in charge of guest memory lifecycle: it first
allocates pages in memory backing store and then passes the fd to KVM and
lets KVM register memory slot to memory backing store via
memfile_register_notifier.
Co-developed-by: Kirill A. Shutemov <redacted>
Signed-off-by: Kirill A. Shutemov <redacted>
Signed-off-by: Chao Peng <redacted>
---
include/linux/memfile_notifier.h | 93 ++++++++++++++++++++++++
mm/Kconfig | 4 +
mm/Makefile | 1 +
mm/memfile_notifier.c | 121 +++++++++++++++++++++++++++++++
4 files changed, 219 insertions(+)
create mode 100644 include/linux/memfile_notifier.h
create mode 100644 mm/memfile_notifier.c
From: David Hildenbrand <hidden> Date: 2022-08-05 13:23:07
On 06.07.22 10:20, Chao Peng wrote:
This patch introduces memfile_notifier facility so existing memory file
subsystems (e.g. tmpfs/hugetlbfs) can provide memory pages to allow a
third kernel component to make use of memory bookmarked in the memory
file and gets notified when the pages in the memory file become
invalidated.
Stupid question, but why is this called "memfile_notifier" and not
"memfd_notifier". We're only dealing with memfd's after all ... which
are anonymous files essentially. Or what am I missing? Are there any
other plans for fs than plain memfd support that I am not aware of?
It will be used for KVM to use a file descriptor as the guest memory
backing store and KVM will use this memfile_notifier interface to
interact with memory file subsystems. In the future there might be other
consumers (e.g. VFIO with encrypted device memory).
It consists below components:
- memfile_backing_store: Each supported memory file subsystem can be
implemented as a memory backing store which bookmarks memory and
provides callbacks for other kernel systems (memfile_notifier
consumers) to interact with.
- memfile_notifier: memfile_notifier consumers defines callbacks and
associate them to a file using memfile_register_notifier().
- memfile_node: A memfile_node is associated with the file (inode) from
the backing store and includes feature flags and a list of registered
memfile_notifier for notifying.
In KVM usages, userspace is in charge of guest memory lifecycle: it first
allocates pages in memory backing store and then passes the fd to KVM and
lets KVM register memory slot to memory backing store via
memfile_register_notifier.
Can we add documentation/description in any form how the different
functions exposed in linux/memfile_notifier.h are supposed to be used?
Staring at memfile_node_set_flags() and memfile_notifier_invalidate()
it's not immediately clear to me who's supposed to call that and under
which conditions.
--
Thanks,
David / dhildenb
On Fri, Aug 05, 2022 at 03:22:58PM +0200, David Hildenbrand wrote:
On 06.07.22 10:20, Chao Peng wrote:
quoted
This patch introduces memfile_notifier facility so existing memory file
subsystems (e.g. tmpfs/hugetlbfs) can provide memory pages to allow a
third kernel component to make use of memory bookmarked in the memory
file and gets notified when the pages in the memory file become
invalidated.
Stupid question, but why is this called "memfile_notifier" and not
"memfd_notifier". We're only dealing with memfd's after all ... which
are anonymous files essentially. Or what am I missing? Are there any
other plans for fs than plain memfd support that I am not aware of?
There were some discussions on this in v3.
https://lkml.org/lkml/2021/12/28/484
Sean commented it's OK to abstract it from memfd but he also wants the
kAPI (name) should not bind to memfd to make room for future non-memfd
usages.
quoted
It will be used for KVM to use a file descriptor as the guest memory
backing store and KVM will use this memfile_notifier interface to
interact with memory file subsystems. In the future there might be other
consumers (e.g. VFIO with encrypted device memory).
It consists below components:
- memfile_backing_store: Each supported memory file subsystem can be
implemented as a memory backing store which bookmarks memory and
provides callbacks for other kernel systems (memfile_notifier
consumers) to interact with.
- memfile_notifier: memfile_notifier consumers defines callbacks and
associate them to a file using memfile_register_notifier().
- memfile_node: A memfile_node is associated with the file (inode) from
the backing store and includes feature flags and a list of registered
memfile_notifier for notifying.
In KVM usages, userspace is in charge of guest memory lifecycle: it first
allocates pages in memory backing store and then passes the fd to KVM and
lets KVM register memory slot to memory backing store via
memfile_register_notifier.
Can we add documentation/description in any form how the different
functions exposed in linux/memfile_notifier.h are supposed to be used?
Yeah, code comments can be added.
Staring at memfile_node_set_flags() and memfile_notifier_invalidate()
it's not immediately clear to me who's supposed to call that and under
which conditions.
From: David Hildenbrand <hidden> Date: 2022-08-10 10:05:54
On 10.08.22 11:22, Chao Peng wrote:
On Fri, Aug 05, 2022 at 03:22:58PM +0200, David Hildenbrand wrote:
quoted
On 06.07.22 10:20, Chao Peng wrote:
quoted
This patch introduces memfile_notifier facility so existing memory file
subsystems (e.g. tmpfs/hugetlbfs) can provide memory pages to allow a
third kernel component to make use of memory bookmarked in the memory
file and gets notified when the pages in the memory file become
invalidated.
Stupid question, but why is this called "memfile_notifier" and not
"memfd_notifier". We're only dealing with memfd's after all ... which
are anonymous files essentially. Or what am I missing? Are there any
other plans for fs than plain memfd support that I am not aware of?
There were some discussions on this in v3.
https://lkml.org/lkml/2021/12/28/484
Sean commented it's OK to abstract it from memfd but he also wants the
kAPI (name) should not bind to memfd to make room for future non-memfd
usages.
Sorry, but how is "memfile" any better? memfd abstracted to memfile?! :)
I understand Sean's suggestion about abstracting, but if the new name
makes it harder to grasp and there isn't really an alternative to memfd
in sight, I'm not so sure I enjoy the tried abstraction here.
Otherwise we'd have to get creative now and discuss something like
"file_population_notifer" or "mapping_population_notifer" and I am not
sure that our time is well spent doing so right now.
... as this is kernel-internal, we can always adjust the name as we
please later, once we *actually* now what the abstraction should be.
Until then I'd suggest to KIS and soft-glue this to memfd.
Or am I missing something important?
--
Thanks,
David / dhildenb
From: Sean Christopherson <seanjc@google.com> Date: 2022-08-10 14:39:27
+Will
On Wed, Aug 10, 2022, David Hildenbrand wrote:
On 10.08.22 11:22, Chao Peng wrote:
quoted
On Fri, Aug 05, 2022 at 03:22:58PM +0200, David Hildenbrand wrote:
quoted
On 06.07.22 10:20, Chao Peng wrote:
quoted
This patch introduces memfile_notifier facility so existing memory file
subsystems (e.g. tmpfs/hugetlbfs) can provide memory pages to allow a
third kernel component to make use of memory bookmarked in the memory
file and gets notified when the pages in the memory file become
invalidated.
Stupid question, but why is this called "memfile_notifier" and not
"memfd_notifier". We're only dealing with memfd's after all ... which
are anonymous files essentially. Or what am I missing? Are there any
other plans for fs than plain memfd support that I am not aware of?
There were some discussions on this in v3.
https://lkml.org/lkml/2021/12/28/484
Sean commented it's OK to abstract it from memfd but he also wants the
kAPI (name) should not bind to memfd to make room for future non-memfd
usages.
Sorry, but how is "memfile" any better? memfd abstracted to memfile?! :)
FWIW, I don't really like the memfile name either.
I understand Sean's suggestion about abstracting, but if the new name
makes it harder to grasp and there isn't really an alternative to memfd
in sight, I'm not so sure I enjoy the tried abstraction here.
ARM's pKVM implementation is potentially (hopefully) going to switch to this API
(as a consumer) sooner than later. If they anticipate being able to use memfd,
then there's unlikely to be a second backing type any time soon.
Quentin, Will?
Otherwise we'd have to get creative now and discuss something like
"file_population_notifer" or "mapping_population_notifer" and I am not
sure that our time is well spent doing so right now.
... as this is kernel-internal, we can always adjust the name as we
please later, once we *actually* now what the abstraction should be.
Until then I'd suggest to KIS and soft-glue this to memfd.
Or am I missing something important?
I don't think you're missing anything. I'd still prefer a name that doesn't couple
KVM to memfd, but it's not a sticking point, and I've never been able to come up
with a better name...
With a little bit of cleverness I think we can keep the coupling in KVM to a
minimum, which is what I really care about.
+CC Fuad
On Wednesday 10 Aug 2022 at 14:38:43 (+0000), Sean Christopherson wrote:
quoted
I understand Sean's suggestion about abstracting, but if the new name
makes it harder to grasp and there isn't really an alternative to memfd
in sight, I'm not so sure I enjoy the tried abstraction here.
ARM's pKVM implementation is potentially (hopefully) going to switch to this API
(as a consumer) sooner than later. If they anticipate being able to use memfd,
then there's unlikely to be a second backing type any time soon.
Quentin, Will?
Yep, Fuad is currently trying to port the pKVM mm stuff on top of this
series to see how well it fits, so stay tuned. I think there is still
some room for discussion around page conversions (private->shared etc),
and we'll need a clearer idea of what the code might look like to have a
constructive discussion, but so far it does seem like using a memfd (the
new private one or perhaps just memfd_secret, to be discussed) + memfd
notifiers is a promising option.
On Thu, Aug 11, 2022 at 12:27:56PM +0000, Quentin Perret wrote:
+CC Fuad
On Wednesday 10 Aug 2022 at 14:38:43 (+0000), Sean Christopherson wrote:
quoted
quoted
I understand Sean's suggestion about abstracting, but if the new name
makes it harder to grasp and there isn't really an alternative to memfd
in sight, I'm not so sure I enjoy the tried abstraction here.
ARM's pKVM implementation is potentially (hopefully) going to switch to this API
(as a consumer) sooner than later. If they anticipate being able to use memfd,
then there's unlikely to be a second backing type any time soon.
Quentin, Will?
Yep, Fuad is currently trying to port the pKVM mm stuff on top of this
series to see how well it fits, so stay tuned.
Good to hear that.
I think there is still
some room for discussion around page conversions (private->shared etc),
and we'll need a clearer idea of what the code might look like to have a
constructive discussion,
That's fine. Looking forward to your feedbacks.
but so far it does seem like using a memfd (the
new private one or perhaps just memfd_secret, to be discussed) + memfd
notifiers is a promising option.
If it still memfd (even memfd_secret), maybe we can use the name
memfd_notifier?
Chao
@@ -9,6 +9,7 @@#include<linux/percpu_counter.h>#include<linux/xattr.h>#include<linux/fs_parser.h>+#include<linux/memfile_notifier.h>/* inode in-kernel data */
@@ -25,6 +26,7 @@ struct shmem_inode_info {structsimple_xattrsxattrs;/* list of xattrs */atomic_tstop_eviction;/* hold when working on inode */structtimespec64i_crtime;/* file creation time */+structmemfile_nodememfile_node;/* memfile node */structinodevfs_inode;};
@@ -3956,6 +4059,10 @@ void __init shmem_init(void)elseshmem_huge=SHMEM_HUGE_NEVER;/* just in case it was patched */#endif++#ifdef CONFIG_MEMFILE_NOTIFIER+memfile_register_backing_store(&shmem_backing_store);+#endifreturn;out1:
@@ -9,6 +9,7 @@#include<linux/percpu_counter.h>#include<linux/xattr.h>#include<linux/fs_parser.h>+#include<linux/memfile_notifier.h>/* inode in-kernel data */
@@ -25,6 +26,7 @@ struct shmem_inode_info {structsimple_xattrsxattrs;/* list of xattrs */atomic_tstop_eviction;/* hold when working on inode */structtimespec64i_crtime;/* file creation time */+structmemfile_nodememfile_node;/* memfile node */structinodevfs_inode;};
@@ -3956,6 +4059,10 @@ void __init shmem_init(void) else shmem_huge = SHMEM_HUGE_NEVER; /* just in case it was patched */ #endif++#ifdef CONFIG_MEMFILE_NOTIFIER+ memfile_register_backing_store(&shmem_backing_store);+#endif return; out1:
Wondering how well page migrate would work for private pages
on shmem memfd based backend?
From high level:
- KVM unset MEMFILE_F_UNMOVABLE bit to indicate it capable of
migrating a page.
- Introduce new 'migrate' callback(s) to memfile_notifier_ops for KVM
to register.
- The callback is hooked to migrate_page() here.
- Once page migration requested, shmem calls into the 'migrate'
callback(s) to perform additional steps for encrypted memory (For
TDX we will call TDH.MEM.PAGE.RELOCATE).
Chao
Wondering how well page migrate would work for private pages
on shmem memfd based backend?
From high level:
- KVM unset MEMFILE_F_UNMOVABLE bit to indicate it capable of
migrating a page.
- Introduce new 'migrate' callback(s) to memfile_notifier_ops for KVM
to register.
- The callback is hooked to migrate_page() here.
- Once page migration requested, shmem calls into the 'migrate'
callback(s) to perform additional steps for encrypted memory (For
TDX we will call TDH.MEM.PAGE.RELOCATE).
Yes, that would require additional (protocol specific) handling for
private pages. Was trying to find where "MEMFILE_F_UNMOVABLE" flag is
set currently?
Thanks,
Pankaj
Wondering how well page migrate would work for private pages
on shmem memfd based backend?
From high level:
- KVM unset MEMFILE_F_UNMOVABLE bit to indicate it capable of
migrating a page.
- Introduce new 'migrate' callback(s) to memfile_notifier_ops for KVM
to register.
- The callback is hooked to migrate_page() here.
- Once page migration requested, shmem calls into the 'migrate'
callback(s) to perform additional steps for encrypted memory (For
TDX we will call TDH.MEM.PAGE.RELOCATE).
Yes, that would require additional (protocol specific) handling for private
pages. Was trying to find where "MEMFILE_F_UNMOVABLE" flag is set currently?
It's set with memfile_register_notifier() in patch 13.
Wondering how well page migrate would work for private pages
on shmem memfd based backend?
From high level:
- KVM unset MEMFILE_F_UNMOVABLE bit to indicate it capable of
migrating a page.
- Introduce new 'migrate' callback(s) to memfile_notifier_ops for KVM
to register.
- The callback is hooked to migrate_page() here.
- Once page migration requested, shmem calls into the 'migrate'
callback(s) to perform additional steps for encrypted memory (For
TDX we will call TDH.MEM.PAGE.RELOCATE).
Yes, that would require additional (protocol specific) handling for private
pages. Was trying to find where "MEMFILE_F_UNMOVABLE" flag is set currently?
It's set with memfile_register_notifier() in patch 13.
From: David Hildenbrand <hidden> Date: 2022-08-05 13:26:15
On 06.07.22 10:20, Chao Peng wrote:
From: "Kirill A. Shutemov" <redacted>
Implement shmem as a memfile_notifier backing store. Essentially it
interacts with the memfile_notifier feature flags for userspace
access/page migration/page reclaiming and implements the necessary
memfile_backing_store callbacks.
Signed-off-by: Kirill A. Shutemov <redacted>
Signed-off-by: Chao Peng <redacted>
---
Why do we export shmem_get_pfn/shmem_put_pfn and not simply
get_folio()
and let the caller deal with putting the folio? What's the reason to
a) Operate on PFNs and not folios
b) Have these get/put semantics?
@@ -3956,6 +4059,10 @@ void __init shmem_init(void) else shmem_huge = SHMEM_HUGE_NEVER; /* just in case it was patched */ #endif++#ifdef CONFIG_MEMFILE_NOTIFIER+ memfile_register_backing_store(&shmem_backing_store);
Can we instead prove a dummy function that does nothing without
CONFIG_MEMFILE_NOTIFIER?
On Fri, Aug 05, 2022 at 03:26:02PM +0200, David Hildenbrand wrote:
On 06.07.22 10:20, Chao Peng wrote:
quoted
From: "Kirill A. Shutemov" <redacted>
Implement shmem as a memfile_notifier backing store. Essentially it
interacts with the memfile_notifier feature flags for userspace
access/page migration/page reclaiming and implements the necessary
memfile_backing_store callbacks.
Signed-off-by: Kirill A. Shutemov <redacted>
Signed-off-by: Chao Peng <redacted>
---
Why do we export shmem_get_pfn/shmem_put_pfn and not simply
get_folio()
and let the caller deal with putting the folio? What's the reason to
a) Operate on PFNs and not folios
b) Have these get/put semantics?
We have a design assumption that somedays this can even support non-page
based backing stores. There are some discussions:
https://lkml.org/lkml/2022/3/28/1440
I should add document for this two callbacks.
@@ -3956,6 +4059,10 @@ void __init shmem_init(void) else shmem_huge = SHMEM_HUGE_NEVER; /* just in case it was patched */ #endif++#ifdef CONFIG_MEMFILE_NOTIFIER+ memfile_register_backing_store(&shmem_backing_store);
Can we instead prove a dummy function that does nothing without
CONFIG_MEMFILE_NOTIFIER?
Introduce a new memfd_create() flag indicating the content of the
created memfd is inaccessible from userspace through ordinary MMU
access (e.g., read/write/mmap). However, the file content can be
accessed via a different mechanism (e.g. KVM MMU) indirectly.
It provides semantics required for KVM guest private memory support
that a file descriptor with this flag set is going to be used as the
source of guest memory in confidential computing environments such
as Intel TDX/AMD SEV but may not be accessible from host userspace.
The flag can not coexist with MFD_ALLOW_SEALING, future sealing is
also impossible for a memfd created with this flag.
Signed-off-by: Chao Peng <redacted>
---
include/uapi/linux/memfd.h | 1 +
mm/memfd.c | 15 ++++++++++++++-
2 files changed, 15 insertions(+), 1 deletion(-)
@@ -284,6 +286,10 @@ SYSCALL_DEFINE2(memfd_create,return-EINVAL;}+/* Disallow sealing when MFD_INACCESSIBLE is set. */+if(flags&MFD_INACCESSIBLE&&flags&MFD_ALLOW_SEALING)+return-EINVAL;+/* length includes terminating zero */len=strnlen_user(uname,MFD_NAME_MAX_LEN+1);if(len<=0)
From: David Hildenbrand <hidden> Date: 2022-08-05 13:29:02
On 06.07.22 10:20, Chao Peng wrote:
Introduce a new memfd_create() flag indicating the content of the
created memfd is inaccessible from userspace through ordinary MMU
access (e.g., read/write/mmap). However, the file content can be
accessed via a different mechanism (e.g. KVM MMU) indirectly.
It provides semantics required for KVM guest private memory support
that a file descriptor with this flag set is going to be used as the
source of guest memory in confidential computing environments such
as Intel TDX/AMD SEV but may not be accessible from host userspace.
The flag can not coexist with MFD_ALLOW_SEALING, future sealing is
also impossible for a memfd created with this flag.
It's kind of weird to have it that way. Why should the user have to
care? It's the notifier requirement to have that, no?
Why can't we handle that when register a notifier? If anything is
already mapped, fail registering the notifier if the notifier has these
demands. If registering succeeds, block it internally.
Or what am I missing? We might not need the memfile set flag semantics
eventually and would not have to expose such a flag to user space.
--
Thanks,
David / dhildenb
On Fri, Aug 05, 2022 at 03:28:50PM +0200, David Hildenbrand wrote:
On 06.07.22 10:20, Chao Peng wrote:
quoted
Introduce a new memfd_create() flag indicating the content of the
created memfd is inaccessible from userspace through ordinary MMU
access (e.g., read/write/mmap). However, the file content can be
accessed via a different mechanism (e.g. KVM MMU) indirectly.
It provides semantics required for KVM guest private memory support
that a file descriptor with this flag set is going to be used as the
source of guest memory in confidential computing environments such
as Intel TDX/AMD SEV but may not be accessible from host userspace.
The flag can not coexist with MFD_ALLOW_SEALING, future sealing is
also impossible for a memfd created with this flag.
It's kind of weird to have it that way. Why should the user have to
care? It's the notifier requirement to have that, no?
Why can't we handle that when register a notifier? If anything is
already mapped, fail registering the notifier if the notifier has these
demands. If registering succeeds, block it internally.
Or what am I missing? We might not need the memfile set flag semantics
eventually and would not have to expose such a flag to user space.
This makes sense if doable. The major concern was: is there a reliable
way to detect this (already mapped) at the time of memslot registering.
Chao
From: David Hildenbrand <hidden> Date: 2022-08-10 09:55:31
On 10.08.22 11:37, Chao Peng wrote:
On Fri, Aug 05, 2022 at 03:28:50PM +0200, David Hildenbrand wrote:
quoted
On 06.07.22 10:20, Chao Peng wrote:
quoted
Introduce a new memfd_create() flag indicating the content of the
created memfd is inaccessible from userspace through ordinary MMU
access (e.g., read/write/mmap). However, the file content can be
accessed via a different mechanism (e.g. KVM MMU) indirectly.
It provides semantics required for KVM guest private memory support
that a file descriptor with this flag set is going to be used as the
source of guest memory in confidential computing environments such
as Intel TDX/AMD SEV but may not be accessible from host userspace.
The flag can not coexist with MFD_ALLOW_SEALING, future sealing is
also impossible for a memfd created with this flag.
It's kind of weird to have it that way. Why should the user have to
care? It's the notifier requirement to have that, no?
Why can't we handle that when register a notifier? If anything is
already mapped, fail registering the notifier if the notifier has these
demands. If registering succeeds, block it internally.
Or what am I missing? We might not need the memfile set flag semantics
eventually and would not have to expose such a flag to user space.
This makes sense if doable. The major concern was: is there a reliable
way to detect this (already mapped) at the time of memslot registering.
If too complicated, we could simplify to "was this ever mapped" and fail
for now. Hooking into shmem_mmap() might be sufficient for that to get
notified about the first mmap.
As an alternative, mapping_mapped() or similar *might* do what we want.
--
Thanks,
David / dhildenb
On Wed, Aug 10, 2022 at 11:55:19AM +0200, David Hildenbrand wrote:
On 10.08.22 11:37, Chao Peng wrote:
quoted
On Fri, Aug 05, 2022 at 03:28:50PM +0200, David Hildenbrand wrote:
quoted
On 06.07.22 10:20, Chao Peng wrote:
quoted
Introduce a new memfd_create() flag indicating the content of the
created memfd is inaccessible from userspace through ordinary MMU
access (e.g., read/write/mmap). However, the file content can be
accessed via a different mechanism (e.g. KVM MMU) indirectly.
It provides semantics required for KVM guest private memory support
that a file descriptor with this flag set is going to be used as the
source of guest memory in confidential computing environments such
as Intel TDX/AMD SEV but may not be accessible from host userspace.
The flag can not coexist with MFD_ALLOW_SEALING, future sealing is
also impossible for a memfd created with this flag.
It's kind of weird to have it that way. Why should the user have to
care? It's the notifier requirement to have that, no?
Why can't we handle that when register a notifier? If anything is
already mapped, fail registering the notifier if the notifier has these
demands. If registering succeeds, block it internally.
Or what am I missing? We might not need the memfile set flag semantics
eventually and would not have to expose such a flag to user space.
This makes sense if doable. The major concern was: is there a reliable
way to detect this (already mapped) at the time of memslot registering.
If too complicated, we could simplify to "was this ever mapped" and fail
for now. Hooking into shmem_mmap() might be sufficient for that to get
notified about the first mmap.
As an alternative, mapping_mapped() or similar *might* do what we want.
mapping_mapped() sounds the right one, I remember SEV people want first
map then unmap. "was this ever mapped" may not work for them.
Thanks,
Chao
From: Kirill A. Shutemov <hidden> Date: 2022-09-07 16:36:16
On Fri, Aug 05, 2022 at 03:28:50PM +0200, David Hildenbrand wrote:
On 06.07.22 10:20, Chao Peng wrote:
quoted
Introduce a new memfd_create() flag indicating the content of the
created memfd is inaccessible from userspace through ordinary MMU
access (e.g., read/write/mmap). However, the file content can be
accessed via a different mechanism (e.g. KVM MMU) indirectly.
It provides semantics required for KVM guest private memory support
that a file descriptor with this flag set is going to be used as the
source of guest memory in confidential computing environments such
as Intel TDX/AMD SEV but may not be accessible from host userspace.
The flag can not coexist with MFD_ALLOW_SEALING, future sealing is
also impossible for a memfd created with this flag.
It's kind of weird to have it that way. Why should the user have to
care? It's the notifier requirement to have that, no?
Why can't we handle that when register a notifier? If anything is
already mapped, fail registering the notifier if the notifier has these
demands. If registering succeeds, block it internally.
Or what am I missing? We might not need the memfile set flag semantics
eventually and would not have to expose such a flag to user space.
Well, with the new shim-based[1] implementation the approach without uAPI
does not work.
We now have two struct file, one is a normal accessible memfd and the
other one is wrapper around that hides the memfd from userspace and
filters allowed operations. If we first create an accessible memfd that
userspace see it would be hard to hide it as by the time userspace may
have multiple fds in different processes that point to the same struct
file.
[1] https://lore.kernel.org/all/20220831142439.65q2gi4g2d2z4ofh@box.shutemov.name
--
Kiryl Shutsemau / Kirill A. Shutemov
KVM_INTERNAL_MEM_SLOTS better reflects the fact those slots are not
exposed to userspace and avoids confusion to real private slots that
is going to be added.
Signed-off-by: Chao Peng <redacted>
---
arch/mips/include/asm/kvm_host.h | 2 +-
arch/x86/include/asm/kvm_host.h | 2 +-
include/linux/kvm_host.h | 6 +++---
3 files changed, 5 insertions(+), 5 deletions(-)
Currently in mmu_notifier validate path, hva range is recorded and then
checked in the mmu_notifier_retry_hva() from page fault path. However
for the to be introduced private memory, a page fault may not have a hva
associated, checking gfn(gpa) makes more sense. For existing non private
memory case, gfn is expected to continue to work.
The patch also fixes a potential bug in kvm_zap_gfn_range() which has
already been using gfn when calling kvm_inc/dec_notifier_count() in
current code.
Signed-off-by: Chao Peng <redacted>
---
arch/x86/kvm/mmu/mmu.c | 2 +-
include/linux/kvm_host.h | 18 ++++++++----------
virt/kvm/kvm_main.c | 6 +++---
3 files changed, 12 insertions(+), 14 deletions(-)
Currently in mmu_notifier validate path, hva range is recorded and then
checked in the mmu_notifier_retry_hva() from page fault path. However
for the to be introduced private memory, a page fault may not have a hva
As this patch appeared in v7, just wondering did you see an actual bug
because of it? And not having corresponding 'hva' occurs only with
private memory because its not mapped to host userspace?
Thanks,
Pankaj
quoted hunk
associated, checking gfn(gpa) makes more sense. For existing non private
memory case, gfn is expected to continue to work.
The patch also fixes a potential bug in kvm_zap_gfn_range() which has
already been using gfn when calling kvm_inc/dec_notifier_count() in
current code.
Signed-off-by: Chao Peng <redacted>
---
arch/x86/kvm/mmu/mmu.c | 2 +-
include/linux/kvm_host.h | 18 ++++++++----------
virt/kvm/kvm_main.c | 6 +++---
3 files changed, 12 insertions(+), 14 deletions(-)
On Fri, Jul 15, 2022 at 01:36:15PM +0200, Gupta, Pankaj wrote:
quoted
Currently in mmu_notifier validate path, hva range is recorded and then
checked in the mmu_notifier_retry_hva() from page fault path. However
for the to be introduced private memory, a page fault may not have a hva
As this patch appeared in v7, just wondering did you see an actual bug
because of it? And not having corresponding 'hva' occurs only with private
memory because its not mapped to host userspace?
The addressed problem is not new in this version, previous versions I
also had code to handle it (just in different way). But the problem is:
mmu_notifier/memfile_notifier may be in the progress of invalidating a
pfn that obtained earlier in the page fault handler, when happens, we
should retry the fault. In v6 I used global mmu_notifier_retry() for
memfile_notifier but that can block unrelated mmu_notifer invalidation
which has hva range specified.
Sean gave a comment at https://lkml.org/lkml/2022/6/17/1001 to separate
memfile_notifier from mmu_notifier but during the implementation I
realized we actually can reuse the same code for shared and private
memory if both using gpa range and that can simplify the code handling
in kvm_zap_gfn_range and some other code (e.g. we don't need two
versions for memfile_notifier/mmu_notifier).
Adding gpa range for private memory invalidation also relieves the
above blocking issue between private memory page fault and mmu_notifier.
Chao
Thanks,
Pankaj
quoted
associated, checking gfn(gpa) makes more sense. For existing non private
memory case, gfn is expected to continue to work.
The patch also fixes a potential bug in kvm_zap_gfn_range() which has
already been using gfn when calling kvm_inc/dec_notifier_count() in
current code.
Signed-off-by: Chao Peng <redacted>
---
arch/x86/kvm/mmu/mmu.c | 2 +-
include/linux/kvm_host.h | 18 ++++++++----------
virt/kvm/kvm_main.c | 6 +++---
3 files changed, 12 insertions(+), 14 deletions(-)
From: Sean Christopherson <seanjc@google.com> Date: 2022-07-18 15:26:46
On Mon, Jul 18, 2022, Chao Peng wrote:
On Fri, Jul 15, 2022 at 01:36:15PM +0200, Gupta, Pankaj wrote:
quoted
quoted
Currently in mmu_notifier validate path, hva range is recorded and then
checked in the mmu_notifier_retry_hva() from page fault path. However
for the to be introduced private memory, a page fault may not have a hva
As this patch appeared in v7, just wondering did you see an actual bug
because of it? And not having corresponding 'hva' occurs only with private
memory because its not mapped to host userspace?
The addressed problem is not new in this version, previous versions I
also had code to handle it (just in different way). But the problem is:
mmu_notifier/memfile_notifier may be in the progress of invalidating a
pfn that obtained earlier in the page fault handler, when happens, we
should retry the fault. In v6 I used global mmu_notifier_retry() for
memfile_notifier but that can block unrelated mmu_notifer invalidation
which has hva range specified.
Sean gave a comment at https://lkml.org/lkml/2022/6/17/1001 to separate
memfile_notifier from mmu_notifier but during the implementation I
realized we actually can reuse the same code for shared and private
memory if both using gpa range and that can simplify the code handling
in kvm_zap_gfn_range and some other code (e.g. we don't need two
versions for memfile_notifier/mmu_notifier).
This should work, though I'm undecided as to whether or not it's a good idea. KVM
allows aliasing multiple gfns to a single hva, and so using the gfn could result
in a much larger range being rejected given the simplistic algorithm for handling
multiple ranges in kvm_inc_notifier_count(). But I assume such aliasing is uncommon,
so I'm not sure it's worth optimizing for.
Adding gpa range for private memory invalidation also relieves the
above blocking issue between private memory page fault and mmu_notifier.
On Mon, Jul 18, 2022 at 03:26:34PM +0000, Sean Christopherson wrote:
On Mon, Jul 18, 2022, Chao Peng wrote:
quoted
On Fri, Jul 15, 2022 at 01:36:15PM +0200, Gupta, Pankaj wrote:
quoted
quoted
Currently in mmu_notifier validate path, hva range is recorded and then
checked in the mmu_notifier_retry_hva() from page fault path. However
for the to be introduced private memory, a page fault may not have a hva
As this patch appeared in v7, just wondering did you see an actual bug
because of it? And not having corresponding 'hva' occurs only with private
memory because its not mapped to host userspace?
The addressed problem is not new in this version, previous versions I
also had code to handle it (just in different way). But the problem is:
mmu_notifier/memfile_notifier may be in the progress of invalidating a
pfn that obtained earlier in the page fault handler, when happens, we
should retry the fault. In v6 I used global mmu_notifier_retry() for
memfile_notifier but that can block unrelated mmu_notifer invalidation
which has hva range specified.
Sean gave a comment at https://lkml.org/lkml/2022/6/17/1001 to separate
memfile_notifier from mmu_notifier but during the implementation I
realized we actually can reuse the same code for shared and private
memory if both using gpa range and that can simplify the code handling
in kvm_zap_gfn_range and some other code (e.g. we don't need two
versions for memfile_notifier/mmu_notifier).
This should work, though I'm undecided as to whether or not it's a good idea. KVM
allows aliasing multiple gfns to a single hva, and so using the gfn could result
in a much larger range being rejected given the simplistic algorithm for handling
multiple ranges in kvm_inc_notifier_count(). But I assume such aliasing is uncommon,
so I'm not sure it's worth optimizing for.
That can be a real problem for current v7 code, __kvm_handle_hva_range()
loops all possible gfn_range for a given hva_range but the
on_lock/on_unlock is invoked only once, this should work for hva_range,
but not gfn_range since we can have multiple of them.
quoted
Adding gpa range for private memory invalidation also relieves the
above blocking issue between private memory page fault and mmu_notifier.