From: Jack Morgenstein Date: Tue, 3 Mar 2009 22:30:01 +0000 (-0800) Subject: IB/sa_query: Fix AH leak due to update_sm_ah() race X-Git-Tag: v2.6.30-rc1~665^2^7 X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=6b708b3dde0ab3a10a0eea7774c1d6482f32f587;p=~emulex%2Finfiniband.git IB/sa_query: Fix AH leak due to update_sm_ah() race Our testing uncovered a race condition in ib_sa_event(): spin_lock_irqsave(&port->ah_lock, flags); if (port->sm_ah) kref_put(&port->sm_ah->ref, free_sm_ah); port->sm_ah = NULL; spin_unlock_irqrestore(&port->ah_lock, flags); schedule_work(&sa_dev->port[event->element.port_num - sa_dev->start_port].update_task); If two events occur back-to-back (e.g., client-reregister and LID change), both may pass the spinlock-protected code above before the scheduled work updates the port->sm_ah handle. Then if the scheduled work ends up running twice, the second operation will then find a non-NULL port->sm_ah, and will simply overwrite it in update_sm_ah -- resulting in an AH leak. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 7863a50d56f..1865049e80f 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -395,6 +395,8 @@ static void update_sm_ah(struct work_struct *work) } spin_lock_irq(&port->ah_lock); + if (port->sm_ah) + kref_put(&port->sm_ah->ref, free_sm_ah); port->sm_ah = new_ah; spin_unlock_irq(&port->ah_lock);