Re: [PATCH v12 04/18] KVM: x86: Rename kvm->arch.has_private_mem to kvm->arch.supports_gmem

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Sean Christopherson <seanjc@xxxxxxxxxx> writes:

> On Wed, Jun 11, 2025, Fuad Tabba wrote:
>> The bool has_private_mem is used to indicate whether guest_memfd is
>> supported.
>
> No?  This is at best weird, and at worst flat out wrong:
>
> 	if (kvm->arch.supports_gmem &&
> 	    fault->is_private != kvm_mem_is_private(kvm, fault->gfn))
> 		return false;
>
> ditto for this code:
>
> 	if (kvm_arch_supports_gmem(vcpu->kvm) &&
> 	    kvm_mem_is_private(vcpu->kvm, gpa_to_gfn(range->gpa)))i
> 		error_code |= PFERR_PRIVATE_ACCESS;
>
> and for the memory_attributes code.  E.g. IIRC, with guest_memfd() mmap support,
> private vs. shared will become a property of the guest_memfd inode, i.e. this will
> become wrong:
>
> static u64 kvm_supported_mem_attributes(struct kvm *kvm)
> {
> 	if (!kvm || kvm_arch_supports_gmem(kvm))
> 		return KVM_MEMORY_ATTRIBUTE_PRIVATE;
>
> 	return 0;
> }
>
> Instead of renaming kvm_arch_has_private_mem() => kvm_arch_supports_gmem(), *add*
> kvm_arch_supports_gmem() and then kill off kvm_arch_has_private_mem() once non-x86
> usage is gone (i.e. query kvm->arch.has_private_mem directly).
>
> And then rather than rename has_private_mem, either add supports_gmem or do what
> you did for kvm_arch_supports_gmem_shared_mem() and explicitly check the VM type.
>

IIUC Fuad will be adding bool supports_gmem instead of renaming, but we
haven't discussed which usages will start using the new function.

Let me go over all the changes/usages related to has_private_mem and
supports_gmem.

> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 6e0bbf4c2202..3d69da6d2d9e 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -2270,9 +2270,9 @@ void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level,
>  
>  
>  #ifdef CONFIG_KVM_GMEM
> -#define kvm_arch_has_private_mem(kvm) ((kvm)->arch.has_private_mem)
> +#define kvm_arch_supports_gmem(kvm) ((kvm)->arch.has_private_mem)
>  #else
> -#define kvm_arch_has_private_mem(kvm) false
> +#define kvm_arch_supports_gmem(kvm) false
>  #endif
>

*The* renaming vs adding-new-function change.

>  #define kvm_arch_has_readonly_mem(kvm) (!(kvm)->arch.has_protected_state)
> @@ -2325,8 +2325,8 @@ enum {
>  #define HF_SMM_INSIDE_NMI_MASK	(1 << 2)
>  
>  # define KVM_MAX_NR_ADDRESS_SPACES	2
> -/* SMM is currently unsupported for guests with private memory. */
> -# define kvm_arch_nr_memslot_as_ids(kvm) (kvm_arch_has_private_mem(kvm) ? 1 : 2)
> +/* SMM is currently unsupported for guests with guest_memfd (esp private) memory. */
> +# define kvm_arch_nr_memslot_as_ids(kvm) (kvm_arch_supports_gmem(kvm) ? 1 : 2)
>  # define kvm_arch_vcpu_memslots_id(vcpu) ((vcpu)->arch.hflags & HF_SMM_MASK ? 1 : 0)
>  # define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, (role).smm)
>  #else

IIUC from the discussion at guest_memfd call on 2025-05-15, SMM can't be
supported because SMM relies on memory being shared.

This should remain as kvm_arch_has_private_mem() - as long as the VM
supports private memory at all, kvm_arch_nr_memslot_as_ids() should
return 1 (no SMM support).

> diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
> index cbc84c6abc2e..e7ecf089780a 100644
> --- a/arch/x86/kvm/mmu/mmu.c
> +++ b/arch/x86/kvm/mmu/mmu.c
> @@ -4910,7 +4910,7 @@ long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,
>  	if (r)
>  		return r;
>  
> -	if (kvm_arch_has_private_mem(vcpu->kvm) &&
> +	if (kvm_arch_supports_gmem(vcpu->kvm) &&
>  	    kvm_mem_is_private(vcpu->kvm, gpa_to_gfn(range->gpa)))
>  		error_code |= PFERR_PRIVATE_ACCESS;
>  

If the VM supports private mem and KVM knows the gfn to be private
(whether based on memory attributes or in future, guest_memfd's
shareability), prefault it as private.

Here technically the kvm_arch_has_private_mem() check just helps
short-circuit to save deeper lookups, but if kvm_arch_has_private_mem()
is false, kvm_mem_is_private() always return false anyway.

This should remain as kvm_arch_has_private_mem().

> @@ -7707,7 +7707,7 @@ bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm,
>  	 * Zapping SPTEs in this case ensures KVM will reassess whether or not
>  	 * a hugepage can be used for affected ranges.
>  	 */
> -	if (WARN_ON_ONCE(!kvm_arch_has_private_mem(kvm)))
> +	if (WARN_ON_ONCE(!kvm_arch_supports_gmem(kvm)))
>  		return false;
>  
>  	if (WARN_ON_ONCE(range->end <= range->start))

Skip setting memory attributes if this kvm doesn't support private
memory.

This should remain as kvm_arch_has_private_mem().

> @@ -7786,7 +7786,7 @@ bool kvm_arch_post_set_memory_attributes(struct kvm *kvm,
>  	 * a range that has PRIVATE GFNs, and conversely converting a range to
>  	 * SHARED may now allow hugepages.
>  	 */
> -	if (WARN_ON_ONCE(!kvm_arch_has_private_mem(kvm)))
> +	if (WARN_ON_ONCE(!kvm_arch_supports_gmem(kvm)))
>  		return false;
>  
>  	/*

Skip setting memory attributes if this kvm doesn't support private
memory.

This should remain as kvm_arch_has_private_mem().

> @@ -7842,7 +7842,7 @@ void kvm_mmu_init_memslot_memory_attributes(struct kvm *kvm,
>  {
>  	int level;
>  
> -	if (!kvm_arch_has_private_mem(kvm))
> +	if (!kvm_arch_supports_gmem(kvm))
>  		return;
>  
>  	for (level = PG_LEVEL_2M; level <= KVM_MAX_HUGEPAGE_LEVEL; level++) {

Skip initializing memory attributes if this kvm doesn't support private
memory, since for now KVM_MEMORY_ATTRIBUTE_PRIVATE is the only memory
attribute.

This should remain as kvm_arch_has_private_mem().

Or perhaps (separately from this series) this check can be changed to
kvm_supported_mem_attributes() != 0.

> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index 7700efc06e35..a0e661aa3f8a 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -719,11 +719,11 @@ static inline int kvm_arch_vcpu_memslots_id(struct kvm_vcpu *vcpu)
>  #endif
>  
>  /*
> - * Arch code must define kvm_arch_has_private_mem if support for private memory
> + * Arch code must define kvm_arch_supports_gmem if support for guest_memfd
>   * is enabled.
>   */
> -#if !defined(kvm_arch_has_private_mem) && !IS_ENABLED(CONFIG_KVM_GMEM)
> -static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
> +#if !defined(kvm_arch_supports_gmem) && !IS_ENABLED(CONFIG_KVM_GMEM)
> +static inline bool kvm_arch_supports_gmem(struct kvm *kvm)
>  {
>  	return false;
>  }

*The* renaming vs adding-new-function change.

> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 898c3d5a7ba8..6efbea208fa6 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -1588,7 +1588,7 @@ static int check_memory_region_flags(struct kvm *kvm,
>  {
>  	u32 valid_flags = KVM_MEM_LOG_DIRTY_PAGES;
>  
> -	if (kvm_arch_has_private_mem(kvm))
> +	if (kvm_arch_supports_gmem(kvm))
>  		valid_flags |= KVM_MEM_GUEST_MEMFD;
>  
>  	/* Dirty logging private memory is not currently supported. */

This should be renamed - the flag is valid only if guest_memfd is
supported and squarely matches kvm_arch_supports_gmem().

> @@ -2419,7 +2419,7 @@ static int kvm_vm_ioctl_clear_dirty_log(struct kvm *kvm,
>  #ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
>  static u64 kvm_supported_mem_attributes(struct kvm *kvm)
>  {
> -	if (!kvm || kvm_arch_has_private_mem(kvm))
> +	if (!kvm || kvm_arch_supports_gmem(kvm))
>  		return KVM_MEMORY_ATTRIBUTE_PRIVATE;
>  
>  	return 0;

This should remain as kvm_arch_has_private_mem().

There's a little issue when mmap support is added: generally for the VM
(for non-guest_memfd memslots in this VM), KVM_MEMORY_ATTRIBUTE_PRIVATE
should be supported, but specifically for some ranges that belong to
guest_memfd-only memslots, KVM_MEMORY_ATTRIBUTE_PRIVATE should not be
supported?

I think kvm_supported_mem_attributes() respond generically for the
entire VM, so leaving this as kvm_arch_has_private_mem() is correct.

> @@ -4912,7 +4912,7 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
>  #endif
>  #ifdef CONFIG_KVM_GMEM
>  	case KVM_CAP_GUEST_MEMFD:
> -		return !kvm || kvm_arch_has_private_mem(kvm);
> +		return !kvm || kvm_arch_supports_gmem(kvm);
>  #endif
>  	default:
>  		break;

This should be renamed - the CAP is valid only if guest_memfd is
supported and squarely matches kvm_arch_supports_gmem().

> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 3d69da6d2d9e..4bc50c1e21bd 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -1341,7 +1341,7 @@ struct kvm_arch {
>  	unsigned int indirect_shadow_pages;
>  	u8 mmu_valid_gen;
>  	u8 vm_type;
> -	bool has_private_mem;
> +	bool supports_gmem;
>  	bool has_protected_state;
>  	bool pre_fault_allowed;
>  	struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
> @@ -2270,7 +2270,7 @@ void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level,
>  
>  
>  #ifdef CONFIG_KVM_GMEM
> -#define kvm_arch_supports_gmem(kvm) ((kvm)->arch.has_private_mem)
> +#define kvm_arch_supports_gmem(kvm) ((kvm)->arch.supports_gmem)
>  #else
>  #define kvm_arch_supports_gmem(kvm) false
>  #endif
> diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
> index e7ecf089780a..c4e10797610c 100644
> --- a/arch/x86/kvm/mmu/mmu.c
> +++ b/arch/x86/kvm/mmu/mmu.c
> @@ -3488,7 +3488,7 @@ static bool page_fault_can_be_fast(struct kvm *kvm, struct kvm_page_fault *fault
>  	 * on RET_PF_SPURIOUS until the update completes, or an actual spurious
>  	 * case might go down the slow path. Either case will resolve itself.
>  	 */
> -	if (kvm->arch.has_private_mem &&
> +	if (kvm->arch.supports_gmem &&
>  	    fault->is_private != kvm_mem_is_private(kvm, fault->gfn))
>  		return false;
>  

This check should remain as a check on has_private_mem.

If the VM supports private memory, skip fast page faults on fault type
and KVM memory privacy status mismatches.

> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index ab9b947dbf4f..67ab05fd3517 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -5180,8 +5180,8 @@ static int svm_vm_init(struct kvm *kvm)
>  			(type == KVM_X86_SEV_ES_VM || type == KVM_X86_SNP_VM);
>  		to_kvm_sev_info(kvm)->need_init = true;
>  
> -		kvm->arch.has_private_mem = (type == KVM_X86_SNP_VM);
> -		kvm->arch.pre_fault_allowed = !kvm->arch.has_private_mem;
> +		kvm->arch.supports_gmem = (type == KVM_X86_SNP_VM);
> +		kvm->arch.pre_fault_allowed = !kvm->arch.supports_gmem;
>  	}
>  
>  	if (!pause_filter_count || !pause_filter_thresh)
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index b58a74c1722d..401256ee817f 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -12778,8 +12778,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>  		return -EINVAL;
>  
>  	kvm->arch.vm_type = type;
> -	kvm->arch.has_private_mem =
> -		(type == KVM_X86_SW_PROTECTED_VM);
> +	kvm->arch.supports_gmem = (type == KVM_X86_SW_PROTECTED_VM);
>  	/* Decided by the vendor code for other VM types.  */
>  	kvm->arch.pre_fault_allowed =
>  		type == KVM_X86_DEFAULT_VM || type == KVM_X86_SW_PROTECTED_VM;

and

> arch/x86/kvm/vmx/tdx.c: In function ‘tdx_vm_init’:
> arch/x86/kvm/vmx/tdx.c:627:18: error: ‘struct kvm_arch’ has no member named ‘has_private_mem’
>   627 |         kvm->arch.has_private_mem = true;
>       |                  ^
> make[5]: *** [scripts/Makefile.build:287: arch/x86/kvm/vmx/tdx.o] Error 1

These three changes make me think that maybe .has_private_mem shouldn't
be a field at all and can be removed.

What if kvm_arch_has_private_mem() for x86 always checks for a specific
list of VM types? Something like this: on x86,

* kvm_arch_has_private_mem() will return true for
  KVM_X86_SW_PROTECTED_VM, KVM_X86_SNP_VM and KVM_X86_TDX_VM.
  
* kvm_arch_supports_gmem() will return true for KVM_X86_SW_PROTECTED_VM,
  KVM_X86_SNP_VM and KVM_X86_TDX_VM as well.

After mmap support, kvm_arch_supports_gmem() also return true for
KVM_X86_DEFAULT_VM, in addition to the original SW_PROTECTED, SNP and
TDX.

Patrick, Nikita, am I right that for KVM_X86_DEFAULT_VM to work with
mmap-able guest_memfd, the usage in page_fault_can_be_fast() need not be
updated, and that patch 10/18 in this series will be sufficient?

>> [...]






[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux