diff mbox series

[RFC,3/3] KVM: Obey kvm.halt_poll_ns in VMs not using KVM_CAP_HALT_POLL

Message ID 20221117001657.1067231-4-dmatlack@google.com (mailing list archive)
State New, archived
Headers show
Series KVM: Restore original behavior of kvm.halt_poll_ns | expand

Commit Message

David Matlack Nov. 17, 2022, 12:16 a.m. UTC
Obey kvm.halt_poll_ns in VMs not using KVM_CAP_HALT_POLL on every halt,
rather than just sampling the module parameter when the VM is first
created. This restore the original behavior of kvm.halt_poll_ns for VMs
that have not opted into KVM_CAP_HALT_POLL.

Notably, this change restores the ability for admins to disable or
change the maximum halt-polling time system wide for VMs not using
KVM_CAP_HALT_POLL.

Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
Fixes: acd05785e48c ("kvm: add capability for halt polling")
Signed-off-by: David Matlack <dmatlack@google.com>
---
 include/linux/kvm_host.h |  1 +
 virt/kvm/kvm_main.c      | 27 ++++++++++++++++++++++++---
 2 files changed, 25 insertions(+), 3 deletions(-)

Comments

Yanan Wang Nov. 18, 2022, 8:28 a.m. UTC | #1
Hi David,

On 2022/11/17 8:16, David Matlack wrote:
> Obey kvm.halt_poll_ns in VMs not using KVM_CAP_HALT_POLL on every halt,
> rather than just sampling the module parameter when the VM is first
s/first/firstly
> created. This restore the original behavior of kvm.halt_poll_ns for VMs
s/restore/restores
> that have not opted into KVM_CAP_HALT_POLL.
>
> Notably, this change restores the ability for admins to disable or
> change the maximum halt-polling time system wide for VMs not using
> KVM_CAP_HALT_POLL.
Should we add more detailed comments about relationship
between KVM_CAP_HALT_POLL and kvm.halt_poll_ns in
Documentation/virt/kvm/api.rst? Something like:
"once KVM_CAP_HALT_POLL is used for a target VM, it will
completely ignores any future changes to kvm.halt_poll_ns..."
> Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
> Fixes: acd05785e48c ("kvm: add capability for halt polling")
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
>   include/linux/kvm_host.h |  1 +
>   virt/kvm/kvm_main.c      | 27 ++++++++++++++++++++++++---
>   2 files changed, 25 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index e6e66c5e56f2..253ad055b6ad 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -788,6 +788,7 @@ struct kvm {
>   	struct srcu_struct srcu;
>   	struct srcu_struct irq_srcu;
>   	pid_t userspace_pid;
> +	bool override_halt_poll_ns;
>   	unsigned int max_halt_poll_ns;
>   	u32 dirty_ring_size;
>   	bool vm_bugged;
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 78caf19608eb..7f73ce99bd0e 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -1198,8 +1198,6 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
>   			goto out_err_no_arch_destroy_vm;
>   	}
>   
> -	kvm->max_halt_poll_ns = halt_poll_ns;
> -
>   	r = kvm_arch_init_vm(kvm, type);
>   	if (r)
>   		goto out_err_no_arch_destroy_vm;
> @@ -3490,7 +3488,20 @@ static inline void update_halt_poll_stats(struct kvm_vcpu *vcpu, ktime_t start,
>   
>   static unsigned int kvm_vcpu_max_halt_poll_ns(struct kvm_vcpu *vcpu)
>   {
> -	return READ_ONCE(vcpu->kvm->max_halt_poll_ns);
> +	struct kvm *kvm = vcpu->kvm;
> +
> +	if (kvm->override_halt_poll_ns) {
> +		/*
> +		 * Ensure kvm->max_halt_poll_ns is not read before
> +		 * kvm->override_halt_poll_ns.
> +		 *
> +		 * Pairs with the smp_wmb() when enabling KVM_CAP_HALT_POLL.
> +		 */
> +		smp_rmb();
> +		return READ_ONCE(kvm->max_halt_poll_ns);
> +	}
> +
> +	return READ_ONCE(halt_poll_ns);
>   }
>   
>   /*
> @@ -4600,6 +4611,16 @@ static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm,
>   			return -EINVAL;
>   
>   		kvm->max_halt_poll_ns = cap->args[0];
> +
> +		/*
> +		 * Ensure kvm->override_halt_poll_ns does not become visible
> +		 * before kvm->max_halt_poll_ns.
> +		 *
> +		 * Pairs with the smp_rmb() in kvm_vcpu_max_halt_poll_ns().
> +		 */
> +		smp_wmb();
> +		kvm->override_halt_poll_ns = true;
> +
>   		return 0;
>   	}
>   	case KVM_CAP_DIRTY_LOG_RING:
Looks good to me:
Reviewed-by: Yanan Wang <wangyanan55@huawei.com>

Thanks,
Yanan
David Matlack Nov. 18, 2022, 4:58 p.m. UTC | #2
On Fri, Nov 18, 2022 at 12:28 AM wangyanan (Y) <wangyanan55@huawei.com> wrote:
>
> Hi David,
>
> On 2022/11/17 8:16, David Matlack wrote:
> > Obey kvm.halt_poll_ns in VMs not using KVM_CAP_HALT_POLL on every halt,
> > rather than just sampling the module parameter when the VM is first
> s/first/firstly
> > created. This restore the original behavior of kvm.halt_poll_ns for VMs
> s/restore/restores
> > that have not opted into KVM_CAP_HALT_POLL.
> >
> > Notably, this change restores the ability for admins to disable or
> > change the maximum halt-polling time system wide for VMs not using
> > KVM_CAP_HALT_POLL.
> Should we add more detailed comments about relationship
> between KVM_CAP_HALT_POLL and kvm.halt_poll_ns in
> Documentation/virt/kvm/api.rst? Something like:
> "once KVM_CAP_HALT_POLL is used for a target VM, it will
> completely ignores any future changes to kvm.halt_poll_ns..."

Yes we should.

I will do some testing on this series today and then resend the series
as a non-RFC with the Documentation changes.

Thanks for the reviews.

> > Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
> > Fixes: acd05785e48c ("kvm: add capability for halt polling")
> > Signed-off-by: David Matlack <dmatlack@google.com>
> > ---
> >   include/linux/kvm_host.h |  1 +
> >   virt/kvm/kvm_main.c      | 27 ++++++++++++++++++++++++---
> >   2 files changed, 25 insertions(+), 3 deletions(-)
> >
> > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> > index e6e66c5e56f2..253ad055b6ad 100644
> > --- a/include/linux/kvm_host.h
> > +++ b/include/linux/kvm_host.h
> > @@ -788,6 +788,7 @@ struct kvm {
> >       struct srcu_struct srcu;
> >       struct srcu_struct irq_srcu;
> >       pid_t userspace_pid;
> > +     bool override_halt_poll_ns;
> >       unsigned int max_halt_poll_ns;
> >       u32 dirty_ring_size;
> >       bool vm_bugged;
> > diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> > index 78caf19608eb..7f73ce99bd0e 100644
> > --- a/virt/kvm/kvm_main.c
> > +++ b/virt/kvm/kvm_main.c
> > @@ -1198,8 +1198,6 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
> >                       goto out_err_no_arch_destroy_vm;
> >       }
> >
> > -     kvm->max_halt_poll_ns = halt_poll_ns;
> > -
> >       r = kvm_arch_init_vm(kvm, type);
> >       if (r)
> >               goto out_err_no_arch_destroy_vm;
> > @@ -3490,7 +3488,20 @@ static inline void update_halt_poll_stats(struct kvm_vcpu *vcpu, ktime_t start,
> >
> >   static unsigned int kvm_vcpu_max_halt_poll_ns(struct kvm_vcpu *vcpu)
> >   {
> > -     return READ_ONCE(vcpu->kvm->max_halt_poll_ns);
> > +     struct kvm *kvm = vcpu->kvm;
> > +
> > +     if (kvm->override_halt_poll_ns) {
> > +             /*
> > +              * Ensure kvm->max_halt_poll_ns is not read before
> > +              * kvm->override_halt_poll_ns.
> > +              *
> > +              * Pairs with the smp_wmb() when enabling KVM_CAP_HALT_POLL.
> > +              */
> > +             smp_rmb();
> > +             return READ_ONCE(kvm->max_halt_poll_ns);
> > +     }
> > +
> > +     return READ_ONCE(halt_poll_ns);
> >   }
> >
> >   /*
> > @@ -4600,6 +4611,16 @@ static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm,
> >                       return -EINVAL;
> >
> >               kvm->max_halt_poll_ns = cap->args[0];
> > +
> > +             /*
> > +              * Ensure kvm->override_halt_poll_ns does not become visible
> > +              * before kvm->max_halt_poll_ns.
> > +              *
> > +              * Pairs with the smp_rmb() in kvm_vcpu_max_halt_poll_ns().
> > +              */
> > +             smp_wmb();
> > +             kvm->override_halt_poll_ns = true;
> > +
> >               return 0;
> >       }
> >       case KVM_CAP_DIRTY_LOG_RING:
> Looks good to me:
> Reviewed-by: Yanan Wang <wangyanan55@huawei.com>
>
> Thanks,
> Yanan
David Matlack Nov. 19, 2022, 1:25 a.m. UTC | #3
On Fri, Nov 18, 2022 at 8:58 AM David Matlack <dmatlack@google.com> wrote:
>
> On Fri, Nov 18, 2022 at 12:28 AM wangyanan (Y) <wangyanan55@huawei.com> wrote:
> >
> > Hi David,
> >
> > On 2022/11/17 8:16, David Matlack wrote:
> > > Obey kvm.halt_poll_ns in VMs not using KVM_CAP_HALT_POLL on every halt,
> > > rather than just sampling the module parameter when the VM is first
> > s/first/firstly
> > > created. This restore the original behavior of kvm.halt_poll_ns for VMs
> > s/restore/restores
> > > that have not opted into KVM_CAP_HALT_POLL.
> > >
> > > Notably, this change restores the ability for admins to disable or
> > > change the maximum halt-polling time system wide for VMs not using
> > > KVM_CAP_HALT_POLL.
> > Should we add more detailed comments about relationship
> > between KVM_CAP_HALT_POLL and kvm.halt_poll_ns in
> > Documentation/virt/kvm/api.rst? Something like:
> > "once KVM_CAP_HALT_POLL is used for a target VM, it will
> > completely ignores any future changes to kvm.halt_poll_ns..."
>
> Yes we should.
>
> I will do some testing on this series today and then resend the series
> as a non-RFC with the Documentation changes.
>
> Thanks for the reviews.

Initial testing looks good but I did not have time to finish due to a
bug in how our VMM is currently using KVM_CAP_HALT_POLL. I will be out
all next week so I'll pick this up the week after.

>
> > > Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
> > > Fixes: acd05785e48c ("kvm: add capability for halt polling")
> > > Signed-off-by: David Matlack <dmatlack@google.com>
> > > ---
> > >   include/linux/kvm_host.h |  1 +
> > >   virt/kvm/kvm_main.c      | 27 ++++++++++++++++++++++++---
> > >   2 files changed, 25 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> > > index e6e66c5e56f2..253ad055b6ad 100644
> > > --- a/include/linux/kvm_host.h
> > > +++ b/include/linux/kvm_host.h
> > > @@ -788,6 +788,7 @@ struct kvm {
> > >       struct srcu_struct srcu;
> > >       struct srcu_struct irq_srcu;
> > >       pid_t userspace_pid;
> > > +     bool override_halt_poll_ns;
> > >       unsigned int max_halt_poll_ns;
> > >       u32 dirty_ring_size;
> > >       bool vm_bugged;
> > > diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> > > index 78caf19608eb..7f73ce99bd0e 100644
> > > --- a/virt/kvm/kvm_main.c
> > > +++ b/virt/kvm/kvm_main.c
> > > @@ -1198,8 +1198,6 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
> > >                       goto out_err_no_arch_destroy_vm;
> > >       }
> > >
> > > -     kvm->max_halt_poll_ns = halt_poll_ns;
> > > -
> > >       r = kvm_arch_init_vm(kvm, type);
> > >       if (r)
> > >               goto out_err_no_arch_destroy_vm;
> > > @@ -3490,7 +3488,20 @@ static inline void update_halt_poll_stats(struct kvm_vcpu *vcpu, ktime_t start,
> > >
> > >   static unsigned int kvm_vcpu_max_halt_poll_ns(struct kvm_vcpu *vcpu)
> > >   {
> > > -     return READ_ONCE(vcpu->kvm->max_halt_poll_ns);
> > > +     struct kvm *kvm = vcpu->kvm;
> > > +
> > > +     if (kvm->override_halt_poll_ns) {
> > > +             /*
> > > +              * Ensure kvm->max_halt_poll_ns is not read before
> > > +              * kvm->override_halt_poll_ns.
> > > +              *
> > > +              * Pairs with the smp_wmb() when enabling KVM_CAP_HALT_POLL.
> > > +              */
> > > +             smp_rmb();
> > > +             return READ_ONCE(kvm->max_halt_poll_ns);
> > > +     }
> > > +
> > > +     return READ_ONCE(halt_poll_ns);
> > >   }
> > >
> > >   /*
> > > @@ -4600,6 +4611,16 @@ static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm,
> > >                       return -EINVAL;
> > >
> > >               kvm->max_halt_poll_ns = cap->args[0];
> > > +
> > > +             /*
> > > +              * Ensure kvm->override_halt_poll_ns does not become visible
> > > +              * before kvm->max_halt_poll_ns.
> > > +              *
> > > +              * Pairs with the smp_rmb() in kvm_vcpu_max_halt_poll_ns().
> > > +              */
> > > +             smp_wmb();
> > > +             kvm->override_halt_poll_ns = true;
> > > +
> > >               return 0;
> > >       }
> > >       case KVM_CAP_DIRTY_LOG_RING:
> > Looks good to me:
> > Reviewed-by: Yanan Wang <wangyanan55@huawei.com>
> >
> > Thanks,
> > Yanan
Yanan Wang Nov. 21, 2022, 1:42 a.m. UTC | #4
On 2022/11/19 9:25, David Matlack wrote:
> On Fri, Nov 18, 2022 at 8:58 AM David Matlack <dmatlack@google.com> wrote:
>> On Fri, Nov 18, 2022 at 12:28 AM wangyanan (Y) <wangyanan55@huawei.com> wrote:
>>> Hi David,
>>>
>>> On 2022/11/17 8:16, David Matlack wrote:
>>>> Obey kvm.halt_poll_ns in VMs not using KVM_CAP_HALT_POLL on every halt,
>>>> rather than just sampling the module parameter when the VM is first
>>> s/first/firstly
>>>> created. This restore the original behavior of kvm.halt_poll_ns for VMs
>>> s/restore/restores
>>>> that have not opted into KVM_CAP_HALT_POLL.
>>>>
>>>> Notably, this change restores the ability for admins to disable or
>>>> change the maximum halt-polling time system wide for VMs not using
>>>> KVM_CAP_HALT_POLL.
>>> Should we add more detailed comments about relationship
>>> between KVM_CAP_HALT_POLL and kvm.halt_poll_ns in
>>> Documentation/virt/kvm/api.rst? Something like:
>>> "once KVM_CAP_HALT_POLL is used for a target VM, it will
>>> completely ignores any future changes to kvm.halt_poll_ns..."
>> Yes we should.
>>
>> I will do some testing on this series today and then resend the series
>> as a non-RFC with the Documentation changes.
>>
>> Thanks for the reviews.
> Initial testing looks good but I did not have time to finish due to a
> bug in how our VMM is currently using KVM_CAP_HALT_POLL. I will be out
> all next week so I'll pick this up the week after.
OK, thanks.

Yanan
>>>> Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
>>>> Fixes: acd05785e48c ("kvm: add capability for halt polling")
>>>> Signed-off-by: David Matlack <dmatlack@google.com>
>>>> ---
>>>>    include/linux/kvm_host.h |  1 +
>>>>    virt/kvm/kvm_main.c      | 27 ++++++++++++++++++++++++---
>>>>    2 files changed, 25 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>>>> index e6e66c5e56f2..253ad055b6ad 100644
>>>> --- a/include/linux/kvm_host.h
>>>> +++ b/include/linux/kvm_host.h
>>>> @@ -788,6 +788,7 @@ struct kvm {
>>>>        struct srcu_struct srcu;
>>>>        struct srcu_struct irq_srcu;
>>>>        pid_t userspace_pid;
>>>> +     bool override_halt_poll_ns;
>>>>        unsigned int max_halt_poll_ns;
>>>>        u32 dirty_ring_size;
>>>>        bool vm_bugged;
>>>> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
>>>> index 78caf19608eb..7f73ce99bd0e 100644
>>>> --- a/virt/kvm/kvm_main.c
>>>> +++ b/virt/kvm/kvm_main.c
>>>> @@ -1198,8 +1198,6 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
>>>>                        goto out_err_no_arch_destroy_vm;
>>>>        }
>>>>
>>>> -     kvm->max_halt_poll_ns = halt_poll_ns;
>>>> -
>>>>        r = kvm_arch_init_vm(kvm, type);
>>>>        if (r)
>>>>                goto out_err_no_arch_destroy_vm;
>>>> @@ -3490,7 +3488,20 @@ static inline void update_halt_poll_stats(struct kvm_vcpu *vcpu, ktime_t start,
>>>>
>>>>    static unsigned int kvm_vcpu_max_halt_poll_ns(struct kvm_vcpu *vcpu)
>>>>    {
>>>> -     return READ_ONCE(vcpu->kvm->max_halt_poll_ns);
>>>> +     struct kvm *kvm = vcpu->kvm;
>>>> +
>>>> +     if (kvm->override_halt_poll_ns) {
>>>> +             /*
>>>> +              * Ensure kvm->max_halt_poll_ns is not read before
>>>> +              * kvm->override_halt_poll_ns.
>>>> +              *
>>>> +              * Pairs with the smp_wmb() when enabling KVM_CAP_HALT_POLL.
>>>> +              */
>>>> +             smp_rmb();
>>>> +             return READ_ONCE(kvm->max_halt_poll_ns);
>>>> +     }
>>>> +
>>>> +     return READ_ONCE(halt_poll_ns);
>>>>    }
>>>>
>>>>    /*
>>>> @@ -4600,6 +4611,16 @@ static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm,
>>>>                        return -EINVAL;
>>>>
>>>>                kvm->max_halt_poll_ns = cap->args[0];
>>>> +
>>>> +             /*
>>>> +              * Ensure kvm->override_halt_poll_ns does not become visible
>>>> +              * before kvm->max_halt_poll_ns.
>>>> +              *
>>>> +              * Pairs with the smp_rmb() in kvm_vcpu_max_halt_poll_ns().
>>>> +              */
>>>> +             smp_wmb();
>>>> +             kvm->override_halt_poll_ns = true;
>>>> +
>>>>                return 0;
>>>>        }
>>>>        case KVM_CAP_DIRTY_LOG_RING:
>>> Looks good to me:
>>> Reviewed-by: Yanan Wang <wangyanan55@huawei.com>
>>>
>>> Thanks,
>>> Yanan
> .
Christian Borntraeger Nov. 21, 2022, 9:22 a.m. UTC | #5
Am 17.11.22 um 01:16 schrieb David Matlack:
> Obey kvm.halt_poll_ns in VMs not using KVM_CAP_HALT_POLL on every halt,
> rather than just sampling the module parameter when the VM is first
> created. This restore the original behavior of kvm.halt_poll_ns for VMs
> that have not opted into KVM_CAP_HALT_POLL.
> 
> Notably, this change restores the ability for admins to disable or
> change the maximum halt-polling time system wide for VMs not using
> KVM_CAP_HALT_POLL.
> 
> Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
> Fixes: acd05785e48c ("kvm: add capability for halt polling")
> Signed-off-by: David Matlack <dmatlack@google.com>

Tested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>

One thing. This does not apply without the other 2 patches. Not sure
if we want to redo this somehow to allow for stable backports?


> ---
>   include/linux/kvm_host.h |  1 +
>   virt/kvm/kvm_main.c      | 27 ++++++++++++++++++++++++---
>   2 files changed, 25 insertions(+), 3 deletions(-)
> 
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index e6e66c5e56f2..253ad055b6ad 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -788,6 +788,7 @@ struct kvm {
>   	struct srcu_struct srcu;
>   	struct srcu_struct irq_srcu;
>   	pid_t userspace_pid;
> +	bool override_halt_poll_ns;
>   	unsigned int max_halt_poll_ns;
>   	u32 dirty_ring_size;
>   	bool vm_bugged;
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 78caf19608eb..7f73ce99bd0e 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -1198,8 +1198,6 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
>   			goto out_err_no_arch_destroy_vm;
>   	}
>   
> -	kvm->max_halt_poll_ns = halt_poll_ns;
> -
>   	r = kvm_arch_init_vm(kvm, type);
>   	if (r)
>   		goto out_err_no_arch_destroy_vm;
> @@ -3490,7 +3488,20 @@ static inline void update_halt_poll_stats(struct kvm_vcpu *vcpu, ktime_t start,
>   
>   static unsigned int kvm_vcpu_max_halt_poll_ns(struct kvm_vcpu *vcpu)
>   {
> -	return READ_ONCE(vcpu->kvm->max_halt_poll_ns);
> +	struct kvm *kvm = vcpu->kvm;
> +
> +	if (kvm->override_halt_poll_ns) {
> +		/*
> +		 * Ensure kvm->max_halt_poll_ns is not read before
> +		 * kvm->override_halt_poll_ns.
> +		 *
> +		 * Pairs with the smp_wmb() when enabling KVM_CAP_HALT_POLL.
> +		 */
> +		smp_rmb();
> +		return READ_ONCE(kvm->max_halt_poll_ns);
> +	}
> +
> +	return READ_ONCE(halt_poll_ns);
>   }
>   
>   /*
> @@ -4600,6 +4611,16 @@ static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm,
>   			return -EINVAL;
>   
>   		kvm->max_halt_poll_ns = cap->args[0];
> +
> +		/*
> +		 * Ensure kvm->override_halt_poll_ns does not become visible
> +		 * before kvm->max_halt_poll_ns.
> +		 *
> +		 * Pairs with the smp_rmb() in kvm_vcpu_max_halt_poll_ns().
> +		 */
> +		smp_wmb();
> +		kvm->override_halt_poll_ns = true;
> +
>   		return 0;
>   	}
>   	case KVM_CAP_DIRTY_LOG_RING:
Christian Borntraeger Nov. 21, 2022, 9:39 a.m. UTC | #6
Am 21.11.22 um 10:22 schrieb Christian Borntraeger:
> Am 17.11.22 um 01:16 schrieb David Matlack:
>> Obey kvm.halt_poll_ns in VMs not using KVM_CAP_HALT_POLL on every halt,
>> rather than just sampling the module parameter when the VM is first
>> created. This restore the original behavior of kvm.halt_poll_ns for VMs
>> that have not opted into KVM_CAP_HALT_POLL.
>>
>> Notably, this change restores the ability for admins to disable or
>> change the maximum halt-polling time system wide for VMs not using
>> KVM_CAP_HALT_POLL.
>>
>> Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
>> Fixes: acd05785e48c ("kvm: add capability for halt polling")
>> Signed-off-by: David Matlack <dmatlack@google.com>
> 
> Tested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
> Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
> 
> One thing. This does not apply without the other 2 patches. Not sure
> if we want to redo this somehow to allow for stable backports?


One option would be that Paolo, when applying uses the stable
syntax as outlined in
Documentation/process/stable-kernel-rules.rst
for dependencies, e.g.

      Cc: <stable@vger.kernel.org> # 3.3.x: a1f84a3: sched: Check for idle
      Cc: <stable@vger.kernel.org> # 3.3.x: 1b9508f: sched: Rate-limit newidle
      Cc: <stable@vger.kernel.org> # 3.3.x: fd21073: sched: Fix affinity logic
David Matlack Dec. 1, 2022, 7:55 p.m. UTC | #7
On Sun, Nov 20, 2022 at 5:42 PM wangyanan (Y) <wangyanan55@huawei.com> wrote:
>
> On 2022/11/19 9:25, David Matlack wrote:
> > On Fri, Nov 18, 2022 at 8:58 AM David Matlack <dmatlack@google.com> wrote:
> >> On Fri, Nov 18, 2022 at 12:28 AM wangyanan (Y) <wangyanan55@huawei.com> wrote:
> >>> Hi David,
> >>>
> >>> On 2022/11/17 8:16, David Matlack wrote:
> >>>> Obey kvm.halt_poll_ns in VMs not using KVM_CAP_HALT_POLL on every halt,
> >>>> rather than just sampling the module parameter when the VM is first
> >>> s/first/firstly
> >>>> created. This restore the original behavior of kvm.halt_poll_ns for VMs
> >>> s/restore/restores
> >>>> that have not opted into KVM_CAP_HALT_POLL.
> >>>>
> >>>> Notably, this change restores the ability for admins to disable or
> >>>> change the maximum halt-polling time system wide for VMs not using
> >>>> KVM_CAP_HALT_POLL.
> >>> Should we add more detailed comments about relationship
> >>> between KVM_CAP_HALT_POLL and kvm.halt_poll_ns in
> >>> Documentation/virt/kvm/api.rst? Something like:
> >>> "once KVM_CAP_HALT_POLL is used for a target VM, it will
> >>> completely ignores any future changes to kvm.halt_poll_ns..."
> >> Yes we should.
> >>
> >> I will do some testing on this series today and then resend the series
> >> as a non-RFC with the Documentation changes.
> >>
> >> Thanks for the reviews.
> > Initial testing looks good but I did not have time to finish due to a
> > bug in how our VMM is currently using KVM_CAP_HALT_POLL. I will be out
> > all next week so I'll pick this up the week after.
> OK, thanks.

I see that Linus already merged these patches into 6.1-rc7, so I've
sent the Documentation changes as a separate series.

https://lore.kernel.org/kvm/20221201195249.3369720-1-dmatlack@google.com/
diff mbox series

Patch

diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index e6e66c5e56f2..253ad055b6ad 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -788,6 +788,7 @@  struct kvm {
 	struct srcu_struct srcu;
 	struct srcu_struct irq_srcu;
 	pid_t userspace_pid;
+	bool override_halt_poll_ns;
 	unsigned int max_halt_poll_ns;
 	u32 dirty_ring_size;
 	bool vm_bugged;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 78caf19608eb..7f73ce99bd0e 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1198,8 +1198,6 @@  static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
 			goto out_err_no_arch_destroy_vm;
 	}
 
-	kvm->max_halt_poll_ns = halt_poll_ns;
-
 	r = kvm_arch_init_vm(kvm, type);
 	if (r)
 		goto out_err_no_arch_destroy_vm;
@@ -3490,7 +3488,20 @@  static inline void update_halt_poll_stats(struct kvm_vcpu *vcpu, ktime_t start,
 
 static unsigned int kvm_vcpu_max_halt_poll_ns(struct kvm_vcpu *vcpu)
 {
-	return READ_ONCE(vcpu->kvm->max_halt_poll_ns);
+	struct kvm *kvm = vcpu->kvm;
+
+	if (kvm->override_halt_poll_ns) {
+		/*
+		 * Ensure kvm->max_halt_poll_ns is not read before
+		 * kvm->override_halt_poll_ns.
+		 *
+		 * Pairs with the smp_wmb() when enabling KVM_CAP_HALT_POLL.
+		 */
+		smp_rmb();
+		return READ_ONCE(kvm->max_halt_poll_ns);
+	}
+
+	return READ_ONCE(halt_poll_ns);
 }
 
 /*
@@ -4600,6 +4611,16 @@  static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm,
 			return -EINVAL;
 
 		kvm->max_halt_poll_ns = cap->args[0];
+
+		/*
+		 * Ensure kvm->override_halt_poll_ns does not become visible
+		 * before kvm->max_halt_poll_ns.
+		 *
+		 * Pairs with the smp_rmb() in kvm_vcpu_max_halt_poll_ns().
+		 */
+		smp_wmb();
+		kvm->override_halt_poll_ns = true;
+
 		return 0;
 	}
 	case KVM_CAP_DIRTY_LOG_RING: