On Wed, 2 Mar 2022 11:15:23 +0100 Janis Schoetterl-Glausch <scgl@xxxxxxxxxxxxx> wrote: > On 3/1/22 15:33, Claudio Imbrenda wrote: > > When handling the SCK instruction, the kvm lock is taken, even though > > the vcpu lock is already being held. The normal locking order is kvm > > lock first and then vcpu lock. This is can (and in some circumstances > > does) lead to deadlocks. > > > > The function kvm_s390_set_tod_clock is called both by the SCK handler > > and by some IOCTLs to set the clock. The IOCTLs will not hold the vcpu > > lock, so they can safely take the kvm lock. The SCK handler holds the > > vcpu lock, but will also somehow need to acquire the kvm lock without > > relinquishing the vcpu lock. > > > > The solution is to factor out the code to set the clock, and provide > > two wrappers. One is called like the original function and does the > > locking, the other is called kvm_s390_try_set_tod_clock and uses > > trylock to try to acquire the kvm lock. This new wrapper is then used > > in the SCK handler. If locking fails, -EAGAIN is returned, which is > > eventually propagated to userspace, thus also freeing the vcpu lock and > > allowing for forward progress. > > > > This is not the most efficient or elegant way to solve this issue, but > > the SCK instruction is deprecated and its performance is not critical. > > > > The goal of this patch is just to provide a simple but correct way to > > fix the bug. > > > > Fixes: 6a3f95a6b04c ("KVM: s390: Intercept SCK instruction") > > Signed-off-by: Claudio Imbrenda <imbrenda@xxxxxxxxxxxxx> > > Reviewed-by: Janis Schoetterl-Glausch <scgl@xxxxxxxxxxxxx> > > --- > > arch/s390/kvm/kvm-s390.c | 19 ++++++++++++++++--- > > arch/s390/kvm/kvm-s390.h | 4 ++-- > > arch/s390/kvm/priv.c | 14 +++++++++++++- > > 3 files changed, 31 insertions(+), 6 deletions(-) > > > > diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c > > index 2296b1ff1e02..4e3db4004bfd 100644 > > --- a/arch/s390/kvm/kvm-s390.c > > +++ b/arch/s390/kvm/kvm-s390.c > > @@ -3869,14 +3869,12 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) > > return 0; > > } > > > > -void kvm_s390_set_tod_clock(struct kvm *kvm, > > - const struct kvm_s390_vm_tod_clock *gtod) > > +static void __kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod) > > { > > struct kvm_vcpu *vcpu; > > union tod_clock clk; > > unsigned long i; > > > > - mutex_lock(&kvm->lock); > > preempt_disable(); > > > > store_tod_clock_ext(&clk); > > @@ -3897,7 +3895,22 @@ void kvm_s390_set_tod_clock(struct kvm *kvm, > > > > kvm_s390_vcpu_unblock_all(kvm); > > preempt_enable(); > > +} > > + > > +void kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod) > > +{ > > + mutex_lock(&kvm->lock); > > + __kvm_s390_set_tod_clock(kvm, gtod); > > + mutex_unlock(&kvm->lock); > > +} > > + > > +int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod) > > Why int instead of bool? to be consistent with mutex_trylock, which also returns int > > > +{ > > + if (!mutex_trylock(&kvm->lock)) > > + return 0; > > + __kvm_s390_set_tod_clock(kvm, gtod); > > mutex_unlock(&kvm->lock); > > + return 1; > > } > > > [...]