[ofa-general] [PATCH] opensm: fix race in main OpenSM flow.

Sasha Khapyorsky sashak at voltaire.com
Thu Dec 4 10:52:09 PST 2008


wait_for_pending_transactions() is heavily used during OpenSM heavy and
light sweep, it checks opensm.stats.qp0_mads_outstanding value and blocks
(with pthread_cond_wait()) until it will reach zero, this event is
signaled by pthread_cond_signal() and should wake waiting thread up.
However this code (qp0_mads_outstanding decrease and signaling) is not
protected by the same mutex as check code in
wait_for_pending_transactions() is. As result there is an easily
reproducible race condition (when qp0_mads_outstanding is decreased and
signaled after the check and before pthread_cond_wait() call in
wait_for_pending_transactions()), which causes OpenSM to dead lock.

This patch addresses this issue - it will use the same mutex which is
used in wait_for_pending_transactions() for all qp0_mads_outstanding
change operations.

Signed-off-by: Sasha Khapyorsky <sashak at voltaire.com>
---
 opensm/include/opensm/osm_stats.h |   34 ++++++++++++++++++++++++++++++++++
 opensm/opensm/osm_sm_mad_ctrl.c   |   21 +++++----------------
 opensm/opensm/osm_vl15intf.c      |    4 ++--
 3 files changed, 41 insertions(+), 18 deletions(-)

diff --git a/opensm/include/opensm/osm_stats.h b/opensm/include/opensm/osm_stats.h
index 2b06e3f..4331cfa 100644
--- a/opensm/include/opensm/osm_stats.h
+++ b/opensm/include/opensm/osm_stats.h
@@ -146,5 +146,39 @@ typedef struct osm_stats {
 * SEE ALSO
 ***************/
 
+static inline uint32_t osm_stats_inc_qp0_outstanding(osm_stats_t *stats)
+{
+	uint32_t outstanding;
+
+#ifdef HAVE_LIBPTHREAD
+	pthread_mutex_lock(&stats->mutex);
+	outstanding = ++stats->qp0_mads_outstanding;
+	pthread_mutex_unlock(&stats->mutex);
+#else
+	outstanding = cl_atomic_inc(&stats->qp0_mads_outstanding);
+#endif
+
+	return outstanding;
+}
+
+static inline uint32_t osm_stats_dec_qp0_outstanding(osm_stats_t *stats)
+{
+	uint32_t outstanding;
+
+#ifdef HAVE_LIBPTHREAD
+	pthread_mutex_lock(&stats->mutex);
+	outstanding = --stats->qp0_mads_outstanding;
+	if (!outstanding)
+		pthread_cond_signal(&stats->cond);
+	pthread_mutex_unlock(&stats->mutex);
+#else
+	outstanding = cl_atomic_dec(&stats->qp0_mads_outstanding);
+	if (!outstanding)
+		cl_event_signal(&stats->event);
+#endif
+
+	return outstanding;
+}
+
 END_C_DECLS
 #endif				/* _OSM_STATS_H_ */
diff --git a/opensm/opensm/osm_sm_mad_ctrl.c b/opensm/opensm/osm_sm_mad_ctrl.c
index fa588cf..267ec85 100644
--- a/opensm/opensm/osm_sm_mad_ctrl.c
+++ b/opensm/opensm/osm_sm_mad_ctrl.c
@@ -64,6 +64,7 @@
  *
  * SYNOPSIS
  */
+
 static void
 __osm_sm_mad_ctrl_retire_trans_mad(IN osm_sm_mad_ctrl_t * const p_ctrl,
 				   IN osm_madw_t * const p_madw)
@@ -82,23 +83,11 @@ __osm_sm_mad_ctrl_retire_trans_mad(IN osm_sm_mad_ctrl_t * const p_ctrl,
 
 	osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
 
-	outstanding = cl_atomic_dec(&p_ctrl->p_stats->qp0_mads_outstanding);
-
-	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "%u QP0 MADs outstanding\n",
-		p_ctrl->p_stats->qp0_mads_outstanding);
+	outstanding = osm_stats_dec_qp0_outstanding(p_ctrl->p_stats);
 
-	if (outstanding == 0) {
-		/*
-		   The wire is clean.
-		   Signal the subnet manager.
-		 */
-		OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "wire is clean.\n");
-#ifdef HAVE_LIBPTHREAD
-		pthread_cond_signal(&p_ctrl->p_stats->cond);
-#else
-		cl_event_signal(&p_ctrl->p_stats->event);
-#endif
-	}
+	OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "%u QP0 MADs outstanding%s\n",
+		p_ctrl->p_stats->qp0_mads_outstanding,
+		outstanding ? "" : ": wire is clean.");
 
 	OSM_LOG_EXIT(p_ctrl->p_log);
 }
diff --git a/opensm/opensm/osm_vl15intf.c b/opensm/opensm/osm_vl15intf.c
index 0cd88ec..0703a4f 100644
--- a/opensm/opensm/osm_vl15intf.c
+++ b/opensm/opensm/osm_vl15intf.c
@@ -325,7 +325,7 @@ void osm_vl15_post(IN osm_vl15_t * const p_vl, IN osm_madw_t * const p_madw)
 	cl_spinlock_acquire(&p_vl->lock);
 	if (p_madw->resp_expected == TRUE) {
 		cl_qlist_insert_tail(&p_vl->rfifo, &p_madw->list_item);
-		cl_atomic_inc(&p_vl->p_stats->qp0_mads_outstanding);
+		osm_stats_inc_qp0_outstanding(p_vl->p_stats);
 	} else
 		cl_qlist_insert_tail(&p_vl->ufifo, &p_madw->list_item);
 	cl_spinlock_release(&p_vl->lock);
@@ -374,7 +374,7 @@ osm_vl15_shutdown(IN osm_vl15_t * const p_vl,
 			"Releasing Request p_madw = %p\n", p_madw);
 
 		osm_mad_pool_put(p_mad_pool, p_madw);
-		cl_atomic_dec(&p_vl->p_stats->qp0_mads_outstanding);
+		osm_stats_dec_qp0_outstanding(p_vl->p_stats);
 
 		p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
 	}
-- 
1.6.1.rc1.45.g123ed




More information about the general mailing list