[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v5 2/2] xen/evtchn: rework per event channel lock
On 09.11.2020 07:41, Juergen Gross wrote: > Currently the lock for a single event channel needs to be taken with > interrupts off, which causes deadlocks in some cases. > > Rework the per event channel lock to be non-blocking for the case of > sending an event and removing the need for disabling interrupts for > taking the lock. > > The lock is needed for avoiding races between event channel state > changes (creation, closing, binding) against normal operations (set > pending, [un]masking, priority changes). > > Use a rwlock, but with some restrictions: > > - normal operations use read_trylock(), in case of not obtaining the > lock the operation is omitted or a default state is returned > > - closing an event channel is using write_lock(), with ASSERT()ing that > the lock is taken as writer only when the state of the event channel > is either before or after the locked region appropriate (either free > or unbound). This has become stale, and may have been incomplete already before: - Normal operations now may use two diffeent approaches. Which one is to be used when would want writing down here. - write_lock() use goes beyond closing. > --- a/xen/arch/x86/irq.c > +++ b/xen/arch/x86/irq.c > @@ -2495,14 +2495,12 @@ static void dump_irqs(unsigned char key) > pirq = domain_irq_to_pirq(d, irq); > info = pirq_info(d, pirq); > evtchn = evtchn_from_port(d, info->evtchn); > - local_irq_disable(); > - if ( spin_trylock(&evtchn->lock) ) > + if ( evtchn_read_trylock(evtchn) ) > { > pending = evtchn_is_pending(d, evtchn); > masked = evtchn_is_masked(d, evtchn); > - spin_unlock(&evtchn->lock); > + evtchn_read_unlock(evtchn); > } > - local_irq_enable(); > printk("d%d:%3d(%c%c%c)%c", > d->domain_id, pirq, "-P?"[pending], > "-M?"[masked], info->masked ? 'M' : '-', Using trylock here has a reason different from that in sending functions, aiui. Please say so in the description, to justify exposure of evtchn_read_lock(). > --- a/xen/arch/x86/pv/shim.c > +++ b/xen/arch/x86/pv/shim.c > @@ -660,11 +660,12 @@ void pv_shim_inject_evtchn(unsigned int port) > if ( port_is_valid(guest, port) ) > { > struct evtchn *chn = evtchn_from_port(guest, port); > - unsigned long flags; > > - spin_lock_irqsave(&chn->lock, flags); > - evtchn_port_set_pending(guest, chn->notify_vcpu_id, chn); > - spin_unlock_irqrestore(&chn->lock, flags); > + if ( evtchn_read_trylock(chn) ) > + { > + evtchn_port_set_pending(guest, chn->notify_vcpu_id, chn); > + evtchn_read_unlock(chn); > + } Does this need trylock? > @@ -1068,15 +1088,16 @@ int evtchn_unmask(unsigned int port) > { > struct domain *d = current->domain; > struct evtchn *evtchn; > - unsigned long flags; > > if ( unlikely(!port_is_valid(d, port)) ) > return -EINVAL; > > evtchn = evtchn_from_port(d, port); > - spin_lock_irqsave(&evtchn->lock, flags); > - evtchn_port_unmask(d, evtchn); > - spin_unlock_irqrestore(&evtchn->lock, flags); > + if ( evtchn_read_trylock(evtchn) ) > + { > + evtchn_port_unmask(d, evtchn); > + evtchn_read_unlock(evtchn); > + } I think this one could as well use plain read_lock(). > @@ -234,12 +244,13 @@ static inline bool evtchn_is_masked(const struct domain > *d, > static inline bool evtchn_port_is_masked(struct domain *d, evtchn_port_t > port) > { > struct evtchn *evtchn = evtchn_from_port(d, port); > - bool rc; > - unsigned long flags; > + bool rc = true; > > - spin_lock_irqsave(&evtchn->lock, flags); > - rc = evtchn_is_masked(d, evtchn); > - spin_unlock_irqrestore(&evtchn->lock, flags); > + if ( evtchn_read_trylock(evtchn) ) > + { > + rc = evtchn_is_masked(d, evtchn); > + evtchn_read_unlock(evtchn); > + } > > return rc; > } > @@ -252,12 +263,13 @@ static inline int evtchn_port_poll(struct domain *d, > evtchn_port_t port) > if ( port_is_valid(d, port) ) > { > struct evtchn *evtchn = evtchn_from_port(d, port); > - unsigned long flags; > > - spin_lock_irqsave(&evtchn->lock, flags); > - if ( evtchn_usable(evtchn) ) > - rc = evtchn_is_pending(d, evtchn); > - spin_unlock_irqrestore(&evtchn->lock, flags); > + if ( evtchn_read_trylock(evtchn) ) > + { > + if ( evtchn_usable(evtchn) ) > + rc = evtchn_is_pending(d, evtchn); > + evtchn_read_unlock(evtchn); > + } > } > > return rc; At least for the latter I suppose it should also be plain read_lock(). We ought to keep the exceptions to where they're actually needed, I think. Jan
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |