[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