]> xenbits.xensource.com Git - people/jgross/xen.git/commitdiff
evtchn: don't call Xen consumer callback with per-channel lock held
authorJan Beulich <jbeulich@suse.com>
Mon, 11 Jan 2021 13:53:02 +0000 (14:53 +0100)
committerJan Beulich <jbeulich@suse.com>
Mon, 11 Jan 2021 13:53:02 +0000 (14:53 +0100)
While there don't look to be any problems with this right now, the lock
order implications from holding the lock can be very difficult to follow
(and may be easy to violate unknowingly). The present callbacks don't
(and no such callback should) have any need for the lock to be held.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Julien Grall <jgrall@amazon.com>
xen/common/event_channel.c

index 3aa4189d7a0b7d0d8f6ae4178b5fe8b3518df616..37592028c822fcd68922555fc009830b3c36eaac 100644 (file)
@@ -775,9 +775,18 @@ int evtchn_send(struct domain *ld, unsigned int lport)
         rport = lchn->u.interdomain.remote_port;
         rchn  = evtchn_from_port(rd, rport);
         if ( consumer_is_xen(rchn) )
-            xen_notification_fn(rchn)(rd->vcpu[rchn->notify_vcpu_id], rport);
-        else
-            evtchn_port_set_pending(rd, rchn->notify_vcpu_id, rchn);
+        {
+            /* Don't keep holding the lock for the call below. */
+            xen_event_channel_notification_t fn = xen_notification_fn(rchn);
+            struct vcpu *rv = rd->vcpu[rchn->notify_vcpu_id];
+
+            rcu_lock_domain(rd);
+            evtchn_read_unlock(lchn);
+            fn(rv, rport);
+            rcu_unlock_domain(rd);
+            return 0;
+        }
+        evtchn_port_set_pending(rd, rchn->notify_vcpu_id, rchn);
         break;
     case ECS_IPI:
         evtchn_port_set_pending(ld, lchn->notify_vcpu_id, lchn);