[ofa-general] [PATCH] IB/core: handle race between elements in qork queues after event

Moni Shoua monis at Voltaire.COM
Wed Apr 30 07:12:42 PDT 2008


This patch solves a race between elements in work queues that are 
carried out after an event occurs. When SM address handle becomes i
nvalid and needs an update it is set to NULL and until update_sm_ah() 
is called, any request that needs sm_ah is replied with -EAGAIN return 
status.

Signed-off-by: Moni Levy  <monil at voltaire.com>
Signed-off-by: Moni Shoua <monis at voltaire.com>

---

 drivers/infiniband/core/sa_query.c |   28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index cf474ec..19439d8 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -407,15 +407,27 @@ static void update_sm_ah(struct work_str
 
 static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event)
 {
+
 	if (event->event == IB_EVENT_PORT_ERR    ||
 	    event->event == IB_EVENT_PORT_ACTIVE ||
 	    event->event == IB_EVENT_LID_CHANGE  ||
 	    event->event == IB_EVENT_PKEY_CHANGE ||
 	    event->event == IB_EVENT_SM_CHANGE   ||
 	    event->event == IB_EVENT_CLIENT_REREGISTER) {
-		struct ib_sa_device *sa_dev;
-		sa_dev = container_of(handler, typeof(*sa_dev), event_handler);
-
+		unsigned long flags;
+		struct ib_sa_device *sa_dev =
+			container_of(handler, typeof(*sa_dev), event_handler);
+		struct ib_sa_port *port =
+			&sa_dev->port[event->element.port_num - sa_dev->start_port];
+		struct ib_sa_sm_ah *sm_ah;
+
+		spin_lock_irqsave(&port->ah_lock, flags);
+		sm_ah = port->sm_ah;
+		port->sm_ah = NULL;
+		spin_unlock_irqrestore(&port->ah_lock, flags);
+
+		if (sm_ah)
+			kref_put(&sm_ah->ref, free_sm_ah);
 		schedule_work(&sa_dev->port[event->element.port_num -
 					    sa_dev->start_port].update_task);
 	}
@@ -780,6 +792,10 @@ int ib_sa_service_rec_query(struct ib_sa
 		return -ENODEV;
 
 	port  = &sa_dev->port[port_num - sa_dev->start_port];
+	if (!port->sm_ah) {
+		return  -EAGAIN;
+	}
+
 	agent = port->agent;
 
 	if (method != IB_MGMT_METHOD_GET &&
@@ -877,8 +893,12 @@ int ib_sa_mcmember_rec_query(struct ib_s
 		return -ENODEV;
 
 	port  = &sa_dev->port[port_num - sa_dev->start_port];
-	agent = port->agent;
+	if (!port->sm_ah) {
+		return  -EAGAIN;
+	}
 
+	agent = port->agent;
+	
 	query = kmalloc(sizeof *query, gfp_mask);
 	if (!query)
 		return -ENOMEM;



More information about the general mailing list