| 
 | 1 | +From 9a4d7cd855d14e1522f363e3e04ebb9fa0a90ff0 Mon Sep 17 00:00:00 2001  | 
 | 2 | +From: Fuad Tabba < [email protected]>  | 
 | 3 | +Date: Tue, 18 Mar 2025 16:18:16 +0000  | 
 | 4 | +Subject: [PATCH 02/34] KVM: guest_memfd: Handle final folio_put() of  | 
 | 5 | + guest_memfd pages  | 
 | 6 | + | 
 | 7 | +Before transitioning a guest_memfd folio to unshared, thereby  | 
 | 8 | +disallowing access by the host and allowing the hypervisor to  | 
 | 9 | +transition its view of the guest page as private, we need to be  | 
 | 10 | +sure that the host doesn't have any references to the folio.  | 
 | 11 | + | 
 | 12 | +This patch introduces a new type for guest_memfd folios, which  | 
 | 13 | +isn't activated in this series but is here as a placeholder and  | 
 | 14 | +to facilitate the code in the subsequent patch series. This will  | 
 | 15 | +be used in the future to register a callback that informs the  | 
 | 16 | +guest_memfd subsystem when the last reference is dropped,  | 
 | 17 | +therefore knowing that the host doesn't have any remaining  | 
 | 18 | +references.  | 
 | 19 | + | 
 | 20 | +This patch also introduces the configuration option,  | 
 | 21 | +KVM_GMEM_SHARED_MEM, which toggles support for mapping  | 
 | 22 | +guest_memfd shared memory at the host.  | 
 | 23 | + | 
 | 24 | +Signed-off-by: Fuad Tabba < [email protected]>  | 
 | 25 | +Acked-by: Vlastimil Babka < [email protected]>  | 
 | 26 | +Acked-by: David Hildenbrand < [email protected]>  | 
 | 27 | +---  | 
 | 28 | + include/linux/kvm_host.h   |  4 ++++  | 
 | 29 | + include/linux/page-flags.h | 16 ++++++++++++++++  | 
 | 30 | + mm/debug.c                 |  1 +  | 
 | 31 | + mm/swap.c                  | 29 +++++++++++++++++++++++++++++  | 
 | 32 | + virt/kvm/Kconfig           |  4 ++++  | 
 | 33 | + virt/kvm/guest_memfd.c     |  8 ++++++++  | 
 | 34 | + 6 files changed, 62 insertions(+)  | 
 | 35 | + | 
 | 36 | +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h  | 
 | 37 | +index f34f4cfaa513..3ad0719bfc4f 100644  | 
 | 38 | +--- a/include/linux/kvm_host.h  | 
 | 39 | ++++ b/include/linux/kvm_host.h  | 
 | 40 | +@@ -2571,4 +2571,8 @@ long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,  | 
 | 41 | + 				    struct kvm_pre_fault_memory *range);  | 
 | 42 | + #endif  | 
 | 43 | +   | 
 | 44 | ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM  | 
 | 45 | ++void kvm_gmem_handle_folio_put(struct folio *folio);  | 
 | 46 | ++#endif  | 
 | 47 | ++  | 
 | 48 | + #endif  | 
 | 49 | +diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h  | 
 | 50 | +index 6dc2494bd002..daeee9a38e4c 100644  | 
 | 51 | +--- a/include/linux/page-flags.h  | 
 | 52 | ++++ b/include/linux/page-flags.h  | 
 | 53 | +@@ -933,6 +933,7 @@ enum pagetype {  | 
 | 54 | + 	PGTY_slab	= 0xf5,  | 
 | 55 | + 	PGTY_zsmalloc	= 0xf6,  | 
 | 56 | + 	PGTY_unaccepted	= 0xf7,  | 
 | 57 | ++	PGTY_guestmem	= 0xf8,  | 
 | 58 | +   | 
 | 59 | + 	PGTY_mapcount_underflow = 0xff  | 
 | 60 | + };  | 
 | 61 | +@@ -1082,6 +1083,21 @@ FOLIO_TYPE_OPS(hugetlb, hugetlb)  | 
 | 62 | + FOLIO_TEST_FLAG_FALSE(hugetlb)  | 
 | 63 | + #endif  | 
 | 64 | +   | 
 | 65 | ++/*  | 
 | 66 | ++ * guestmem folios are used to back VM memory as managed by guest_memfd. Once  | 
 | 67 | ++ * the last reference is put, instead of freeing these folios back to the page  | 
 | 68 | ++ * allocator, they are returned to guest_memfd.  | 
 | 69 | ++ *  | 
 | 70 | ++ * For now, guestmem will only be set on these folios as long as they  cannot be  | 
 | 71 | ++ * mapped to user space ("private state"), with the plan of always setting that  | 
 | 72 | ++ * type once typed folios can be mapped to user space cleanly.  | 
 | 73 | ++ */  | 
 | 74 | ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM  | 
 | 75 | ++FOLIO_TYPE_OPS(guestmem, guestmem)  | 
 | 76 | ++#else  | 
 | 77 | ++FOLIO_TEST_FLAG_FALSE(guestmem)  | 
 | 78 | ++#endif  | 
 | 79 | ++  | 
 | 80 | + PAGE_TYPE_OPS(Zsmalloc, zsmalloc, zsmalloc)  | 
 | 81 | +   | 
 | 82 | + /*  | 
 | 83 | +diff --git a/mm/debug.c b/mm/debug.c  | 
 | 84 | +index 8d2acf432385..08bc42c6cba8 100644  | 
 | 85 | +--- a/mm/debug.c  | 
 | 86 | ++++ b/mm/debug.c  | 
 | 87 | +@@ -56,6 +56,7 @@ static const char *page_type_names[] = {  | 
 | 88 | + 	DEF_PAGETYPE_NAME(table),  | 
 | 89 | + 	DEF_PAGETYPE_NAME(buddy),  | 
 | 90 | + 	DEF_PAGETYPE_NAME(unaccepted),  | 
 | 91 | ++	DEF_PAGETYPE_NAME(guestmem),  | 
 | 92 | + };  | 
 | 93 | +   | 
 | 94 | + static const char *page_type_name(unsigned int page_type)  | 
 | 95 | +diff --git a/mm/swap.c b/mm/swap.c  | 
 | 96 | +index 47bc1bb919cc..d8fda3948684 100644  | 
 | 97 | +--- a/mm/swap.c  | 
 | 98 | ++++ b/mm/swap.c  | 
 | 99 | +@@ -38,6 +38,10 @@  | 
 | 100 | + #include <linux/local_lock.h>  | 
 | 101 | + #include <linux/buffer_head.h>  | 
 | 102 | +   | 
 | 103 | ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM  | 
 | 104 | ++#include <linux/kvm_host.h>  | 
 | 105 | ++#endif  | 
 | 106 | ++  | 
 | 107 | + #include "internal.h"  | 
 | 108 | +   | 
 | 109 | + #define CREATE_TRACE_POINTS  | 
 | 110 | +@@ -94,6 +98,26 @@ static void page_cache_release(struct folio *folio)  | 
 | 111 | + 		unlock_page_lruvec_irqrestore(lruvec, flags);  | 
 | 112 | + }  | 
 | 113 | +   | 
 | 114 | ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM  | 
 | 115 | ++static void gmem_folio_put(struct folio *folio)  | 
 | 116 | ++{  | 
 | 117 | ++	/*  | 
 | 118 | ++	 * Perform the callback only as long as the KVM module is still loaded.  | 
 | 119 | ++	 * As long as the folio mapping is set, the folio is associated with a  | 
 | 120 | ++	 * guest_memfd inode.  | 
 | 121 | ++	 */  | 
 | 122 | ++	if (folio->mapping)  | 
 | 123 | ++		kvm_gmem_handle_folio_put(folio);  | 
 | 124 | ++  | 
 | 125 | ++	/*  | 
 | 126 | ++	 * If there are no references to the folio left, it's not associated  | 
 | 127 | ++	 * with a guest_memfd inode anymore.  | 
 | 128 | ++	 */  | 
 | 129 | ++	if (folio_ref_count(folio) == 0)  | 
 | 130 | ++		__folio_put(folio);  | 
 | 131 | ++}  | 
 | 132 | ++#endif /* CONFIG_KVM_GMEM_SHARED_MEM */  | 
 | 133 | ++  | 
 | 134 | + static void free_typed_folio(struct folio *folio)  | 
 | 135 | + {  | 
 | 136 | + 	switch (folio_get_type(folio)) {  | 
 | 137 | +@@ -101,6 +125,11 @@ static void free_typed_folio(struct folio *folio)  | 
 | 138 | + 	case PGTY_hugetlb:  | 
 | 139 | + 		free_huge_folio(folio);  | 
 | 140 | + 		return;  | 
 | 141 | ++#endif  | 
 | 142 | ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM  | 
 | 143 | ++	case PGTY_guestmem:  | 
 | 144 | ++		gmem_folio_put(folio);  | 
 | 145 | ++		return;  | 
 | 146 | + #endif  | 
 | 147 | + 	default:  | 
 | 148 | + 		WARN_ON_ONCE(1);  | 
 | 149 | +diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig  | 
 | 150 | +index 54e959e7d68f..4e759e8020c5 100644  | 
 | 151 | +--- a/virt/kvm/Kconfig  | 
 | 152 | ++++ b/virt/kvm/Kconfig  | 
 | 153 | +@@ -124,3 +124,7 @@ config HAVE_KVM_ARCH_GMEM_PREPARE  | 
 | 154 | + config HAVE_KVM_ARCH_GMEM_INVALIDATE  | 
 | 155 | +        bool  | 
 | 156 | +        depends on KVM_PRIVATE_MEM  | 
 | 157 | ++  | 
 | 158 | ++config KVM_GMEM_SHARED_MEM  | 
 | 159 | ++       select KVM_PRIVATE_MEM  | 
 | 160 | ++       bool  | 
 | 161 | +diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c  | 
 | 162 | +index b2aa6bf24d3a..5fc414becae5 100644  | 
 | 163 | +--- a/virt/kvm/guest_memfd.c  | 
 | 164 | ++++ b/virt/kvm/guest_memfd.c  | 
 | 165 | +@@ -13,6 +13,14 @@ struct kvm_gmem {  | 
 | 166 | + 	struct list_head entry;  | 
 | 167 | + };  | 
 | 168 | +   | 
 | 169 | ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM  | 
 | 170 | ++void kvm_gmem_handle_folio_put(struct folio *folio)  | 
 | 171 | ++{  | 
 | 172 | ++	WARN_ONCE(1, "A placeholder that shouldn't trigger. Work in progress.");  | 
 | 173 | ++}  | 
 | 174 | ++EXPORT_SYMBOL_GPL(kvm_gmem_handle_folio_put);  | 
 | 175 | ++#endif /* CONFIG_KVM_GMEM_SHARED_MEM */  | 
 | 176 | ++  | 
 | 177 | + /**  | 
 | 178 | +  * folio_file_pfn - like folio_file_page, but return a pfn.  | 
 | 179 | +  * @folio: The folio which contains this index.  | 
 | 180 | +--   | 
 | 181 | +2.47.1  | 
 | 182 | + | 
0 commit comments