|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v4.1 2/2] xen/evtchn: rework per event channel lock
> @@ -738,7 +725,8 @@ int evtchn_send(struct domain *ld, unsigned int lport)
>
> lchn = evtchn_from_port(ld, lport);
>
> - spin_lock_irqsave(&lchn->lock, flags);
> + if ( !evtchn_read_trylock(lchn) )
> + return 0;
Isn't there a change in behavior here? While sends through
ECS_UNBOUND ports indeed get silently ignored, ECS_FREE ones ought
to be getting -EINVAL (as should ECS_UNBOUND ones if they're
Xen-consumer ones). With the failed trylock you don't know which
of the two the port is in the process of being transitioned
to/from. The same would apply for other operations distinguishing
the two states. Right now both evtchn_status() and
evtchn_bind_vcpu() only use the domain-wide lock, but the latter
is getting switched by "evtchn: convert domain event lock to an
r/w one" (granted there's an RFC remark there whether that
transformation is worthwhile). Anyway, the main point of my remark
is that there's another subtlety here which I don't think becomes
obvious from description or comments - where the two states are
mentioned, it gets to look as if they can be treated equally.
> --- a/xen/include/xen/event.h
> +++ b/xen/include/xen/event.h
> @@ -105,6 +105,39 @@ void notify_via_xen_event_channel(struct domain *ld, int
> lport);
> #define bucket_from_port(d, p) \
> ((group_from_port(d, p))[((p) % EVTCHNS_PER_GROUP) / EVTCHNS_PER_BUCKET])
>
> +/*
> + * Lock an event channel exclusively. This is allowed only when the channel
> is
> + * free or unbound either when taking or when releasing the lock, as any
> + * concurrent operation on the event channel using evtchn_read_trylock() will
> + * just assume the event channel is free or unbound at the moment when the
> + * evtchn_read_trylock() returns false.
> + */
> +static inline void evtchn_write_lock(struct evtchn *evtchn)
> +{
> + write_lock(&evtchn->lock);
> +
> + evtchn->old_state = evtchn->state;
> +}
> +
> +static inline void evtchn_write_unlock(struct evtchn *evtchn)
> +{
> + /* Enforce lock discipline. */
> + ASSERT(evtchn->old_state == ECS_FREE || evtchn->old_state == ECS_UNBOUND
> ||
> + evtchn->state == ECS_FREE || evtchn->state == ECS_UNBOUND);
> +
> + write_unlock(&evtchn->lock);
> +}
These two aren't needed outside of event_channel.c, are they? If
so, and if they ought to go in a header rather than directly into
the .c file (where I'd prefer the latter, for the sake of minimal
exposure), then it should be event_channel.h.
> @@ -114,6 +114,7 @@ struct evtchn
> u16 virq; /* state == ECS_VIRQ */
> } u;
> u8 priority;
> + u8 old_state; /* State when taking lock in write mode. */
> u32 fifo_lastq; /* Data for fifo events identifying last queue. */
> #ifdef CONFIG_XSM
> union {
While there's a gap here after the prior patch (which I'm still
not overly happy about), I'm still inclined to ask that the field
be put inside #ifndef NDEBUG, as its only consumer is an
ASSERT().
Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |