[openib-general] [PATCH] mad: prevent duplicate RMPP sessions on responder side

Jack Morgenstein jackm at mellanox.co.il
Tue May 23 04:59:44 PDT 2006


Prevent opening multiple RMPP MAD transaction sessions at responder side
with the same TID, GID/LID, class.

Could happen if RMPP requests are retried while response is in progress.

Signed-off-by: Jack Morgenstein <jackm at mellanox.co.il>

Index: openib_branch1.0/drivers/infiniband/core/mad.c
===================================================================
--- openib_branch1.0.orig/drivers/infiniband/core/mad.c
+++ openib_branch1.0/drivers/infiniband/core/mad.c
@@ -1038,6 +1038,102 @@ int ib_send_mad(struct ib_mad_send_wr_pr
 	return ret;
 }
 
+static inline int is_rmpp_data(struct ib_mad *mad)
+{
+	struct ib_rmpp_mad *r;
+
+	if (!ib_is_mad_class_rmpp(mad->mad_hdr.mgmt_class))
+		return 0;
+
+	r = (struct ib_rmpp_mad *)mad;
+	return (ib_get_rmpp_flags(&r->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE) &&
+	       r->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA;
+}
+
+static inline int send_has_same_class(struct ib_mad_send_wr_private *mwr1,
+				 struct ib_mad_send_wr_private *mwr2)
+{
+	return (((struct ib_mad *)(mwr1->send_buf.mad))->mad_hdr.mgmt_class ==
+		((struct ib_mad *)(mwr2->send_buf.mad))->mad_hdr.mgmt_class);
+}
+
+static int send_has_same_gid(struct ib_mad_agent_private *agent,
+			     struct ib_mad_send_wr_private *lwr,
+			     struct ib_mad_send_wr_private *swr)
+{
+	struct ib_ah_attr sattr, lattr;
+	u8 lmethod = ((struct ib_mad *)(lwr->send_buf.mad))->mad_hdr.method;
+	u8 smethod = ((struct ib_mad *)(swr->send_buf.mad))->mad_hdr.method;
+	u8 lmc;
+
+	/* one is a response mad, other is not */
+	if ((lmethod & IB_MGMT_METHOD_RESP) != (smethod & IB_MGMT_METHOD_RESP))
+		return 0;
+
+	/* need to compare GIDs/LIDs */
+	if (ib_query_ah(swr->send_buf.ah, &sattr) ||
+	    ib_query_ah(lwr->send_buf.ah, &lattr))
+		/* No AH data. Assume not equal, to avoid false positives. */
+		return 0;
+
+	if (!(smethod & IB_MGMT_METHOD_RESP)) {
+		/* Is not a response */
+		if (!(lattr.ah_flags & IB_AH_GRH) &&
+		    !(sattr.ah_flags & IB_AH_GRH)) {
+			/* no GIDs, compare src_path_bits */
+			if (ib_get_cached_lmc(agent->agent.device,
+					      agent->agent.port_num,
+					      &lmc))
+				return 0;
+			return (!lmc || !((sattr.src_path_bits ^
+					   lattr.src_path_bits) &
+					  ((1 << lmc) - 1)));
+		}
+		if ((lattr.ah_flags & IB_AH_GRH) && (sattr.ah_flags & IB_AH_GRH))
+			return lattr.grh.sgid_index == sattr.grh.sgid_index;
+		return 0;
+	}
+
+	/* comparing send responses */
+	if (!(lattr.ah_flags & IB_AH_GRH) && !(sattr.ah_flags & IB_AH_GRH))
+		/* No GIDs. Compare LIDs */
+		return (sattr.dlid && (lattr.dlid == sattr.dlid));
+	if ((lattr.ah_flags & IB_AH_GRH) && (sattr.ah_flags & IB_AH_GRH))
+		/* check if GIDs are equal */
+		return (!memcmp(lattr.grh.dgid.raw, sattr.grh.dgid.raw, 16));
+	/* one has GID, other does not.  Assume different dest */
+	return 0;
+}
+
+static int check_dup_send_mad(struct ib_mad_agent_private *agent,
+			      struct ib_mad_send_wr_private *send_wr)
+{
+	struct ib_mad_send_wr_private *t;
+
+	if (!is_rmpp_data(send_wr->send_buf.mad))
+		return 0;
+	list_for_each_entry(t, &agent->wait_list, agent_list) {
+		if (t->tid == send_wr->tid &&
+		    send_has_same_class(t, send_wr) &&
+		    send_has_same_gid(agent, t, send_wr))
+			return 1;
+	}
+
+	/*
+	 * It's possible to send a duplicate mad before we've
+	 * been notified that the first send has completed
+	 */
+	list_for_each_entry(t, &agent->send_list, agent_list) {
+		if (is_rmpp_data(t->send_buf.mad) &&
+		    t->tid == send_wr->tid && send_has_same_class(t, send_wr) &&
+		    send_has_same_gid(agent, t, send_wr)) {
+			/* Verify request has not been canceled */
+			return (send_wr->status == IB_WC_SUCCESS) ?  1 : 0;
+		}
+	}
+	return 0;
+}
+
 /*
  * ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated
  *  with the registered client
@@ -1102,6 +1198,12 @@ int ib_post_send_mad(struct ib_mad_send_
 		/* Reference MAD agent until send completes */
 		atomic_inc(&mad_agent_priv->refcount);
 		spin_lock_irqsave(&mad_agent_priv->lock, flags);
+		if (check_dup_send_mad(mad_agent_priv, mad_send_wr)) {
+			/* Duplicate send request */
+			spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
+			atomic_dec(&mad_agent_priv->refcount);
+			return -EBUSY;
+		}
 		list_add_tail(&mad_send_wr->agent_list,
 			      &mad_agent_priv->send_list);
 		spin_unlock_irqrestore(&mad_agent_priv->lock, flags);



More information about the general mailing list