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? > +{ > + if (!mutex_trylock(&kvm->lock)) > + return 0; > + __kvm_s390_set_tod_clock(kvm, gtod); > mutex_unlock(&kvm->lock); > + return 1; > } > [...]