Message ID | 20230901105823.3973928-1-mimu@linux.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v4] KVM: s390: fix gisa destroy operation might lead to cpu stalls | expand |
Quoting Michael Mueller (2023-09-01 12:58:23) [...] > diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c > index 9bd0a873f3b1..96450e5c4b6f 100644 > --- a/arch/s390/kvm/interrupt.c > +++ b/arch/s390/kvm/interrupt.c [...] > static inline void gisa_set_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc) > { > set_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); > @@ -3202,11 +3197,12 @@ void kvm_s390_gisa_destroy(struct kvm *kvm) > > if (!gi->origin) > return; > - if (gi->alert.mask) > - KVM_EVENT(3, "vm 0x%pK has unexpected iam 0x%02x", > - kvm, gi->alert.mask); > - while (gisa_in_alert_list(gi->origin)) > - cpu_relax(); > + WARN(gi->alert.mask != 0x00, > + "unexpected non zero alert.mask 0x%02x", > + gi->alert.mask); > + gi->alert.mask = 0x00; > + if (gisa_set_iam(gi->origin, gi->alert.mask)) > + process_gib_alert_list(); I am not an expert for the GISA, so excuse my possibly stupid question: process_gib_alert_list() starts the timer. So can gisa_vcpu_kicker() already be running before we reach hrtimer_cancel() below? Is this fine? > hrtimer_cancel(&gi->timer); > gi->origin = NULL; > VM_EVENT(kvm, 3, "gisa 0x%pK destroyed", gisa);
On 04.09.23 09:05, Nico Boehr wrote: > Quoting Michael Mueller (2023-09-01 12:58:23) > [...] >> diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c >> index 9bd0a873f3b1..96450e5c4b6f 100644 >> --- a/arch/s390/kvm/interrupt.c >> +++ b/arch/s390/kvm/interrupt.c > [...] >> static inline void gisa_set_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc) >> { >> set_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); >> @@ -3202,11 +3197,12 @@ void kvm_s390_gisa_destroy(struct kvm *kvm) >> >> if (!gi->origin) >> return; >> - if (gi->alert.mask) >> - KVM_EVENT(3, "vm 0x%pK has unexpected iam 0x%02x", >> - kvm, gi->alert.mask); >> - while (gisa_in_alert_list(gi->origin)) >> - cpu_relax(); >> + WARN(gi->alert.mask != 0x00, >> + "unexpected non zero alert.mask 0x%02x", >> + gi->alert.mask); >> + gi->alert.mask = 0x00; >> + if (gisa_set_iam(gi->origin, gi->alert.mask)) >> + process_gib_alert_list(); > > I am not an expert for the GISA, so excuse my possibly stupid question: > process_gib_alert_list() starts the timer. So can gisa_vcpu_kicker() > already be running before we reach hrtimer_cancel() below? Is this fine? You are right, It cannnot be running in that situation because gisa_vcpu_kicker() has returned with HRTIMER_NORESTART and no vcpus are defined anymore. There is another case when the gisa specific timer is started not only in the process_gib_alert() case but also when a vcpu of the guest owning the gisa is put into wait state, see kvm_s390_handle_wait(). Thus yes, it could be running already in that situation. I remember having seen this situation when I write the gisa/gib code. But that's case in process_gib_alert_list() It does not hurt to have the hrtimer_cancel() here but I don't want to add a change to this patch. Eventually a new one. Thanks for asking! > >> hrtimer_cancel(&gi->timer); >> gi->origin = NULL; >> VM_EVENT(kvm, 3, "gisa 0x%pK destroyed", gisa);
Quoting Michael Mueller (2023-09-04 16:11:26) > > > On 04.09.23 09:05, Nico Boehr wrote: > > Quoting Michael Mueller (2023-09-01 12:58:23) > > [...] > >> diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c > >> index 9bd0a873f3b1..96450e5c4b6f 100644 > >> --- a/arch/s390/kvm/interrupt.c > >> +++ b/arch/s390/kvm/interrupt.c > > [...] > >> static inline void gisa_set_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc) > >> { > >> set_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); > >> @@ -3202,11 +3197,12 @@ void kvm_s390_gisa_destroy(struct kvm *kvm) > >> > >> if (!gi->origin) > >> return; > >> - if (gi->alert.mask) > >> - KVM_EVENT(3, "vm 0x%pK has unexpected iam 0x%02x", > >> - kvm, gi->alert.mask); > >> - while (gisa_in_alert_list(gi->origin)) > >> - cpu_relax(); > >> + WARN(gi->alert.mask != 0x00, > >> + "unexpected non zero alert.mask 0x%02x", > >> + gi->alert.mask); > >> + gi->alert.mask = 0x00; > >> + if (gisa_set_iam(gi->origin, gi->alert.mask)) > >> + process_gib_alert_list(); > > > > I am not an expert for the GISA, so excuse my possibly stupid question: > > process_gib_alert_list() starts the timer. So can gisa_vcpu_kicker() > > already be running before we reach hrtimer_cancel() below? Is this fine? > > You are right, It cannnot be running in that situation because > gisa_vcpu_kicker() has returned with HRTIMER_NORESTART and no vcpus are > defined anymore. > > There is another case when the gisa specific timer is started not only > in the process_gib_alert() case but also when a vcpu of the guest owning > the gisa is put into wait state, see kvm_s390_handle_wait(). Thus yes, > it could be running already in that situation. I remember having seen > this situation when I write the gisa/gib code. But that's case in > process_gib_alert_list() > > It does not hurt to have the hrtimer_cancel() here but I don't want to > add a change to this patch. Eventually a new one. Ah OK, thanks for the explanation. hrtimer_cancel() also waits until the timer function has completed. LGTM then. Reviewed-by: Nico Boehr <nrb@linux.ibm.com>
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 9bd0a873f3b1..96450e5c4b6f 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -303,11 +303,6 @@ static inline u8 gisa_get_ipm_or_restore_iam(struct kvm_s390_gisa_interrupt *gi) return 0; } -static inline int gisa_in_alert_list(struct kvm_s390_gisa *gisa) -{ - return READ_ONCE(gisa->next_alert) != (u32)virt_to_phys(gisa); -} - static inline void gisa_set_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc) { set_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); @@ -3202,11 +3197,12 @@ void kvm_s390_gisa_destroy(struct kvm *kvm) if (!gi->origin) return; - if (gi->alert.mask) - KVM_EVENT(3, "vm 0x%pK has unexpected iam 0x%02x", - kvm, gi->alert.mask); - while (gisa_in_alert_list(gi->origin)) - cpu_relax(); + WARN(gi->alert.mask != 0x00, + "unexpected non zero alert.mask 0x%02x", + gi->alert.mask); + gi->alert.mask = 0x00; + if (gisa_set_iam(gi->origin, gi->alert.mask)) + process_gib_alert_list(); hrtimer_cancel(&gi->timer); gi->origin = NULL; VM_EVENT(kvm, 3, "gisa 0x%pK destroyed", gisa);