diff options
author | Ralph Campbell <ralph.campbell@qlogic.com> | 2009-03-03 17:22:17 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2009-03-03 17:22:17 -0500 |
commit | 4780c1953f9bef07365b13af01ae4e8238ecd3de (patch) | |
tree | ce68e77fc5ad410b9c320cf80ad7f76faa1bc7f1 /drivers/infiniband/core | |
parent | d9620a4c82c61a91c9313f80ba951c902573c028 (diff) |
IB/mad: Fix ib_post_send_mad() returning 0 with no generate send comp
If ib_post_send_mad() returns 0, the API guarantees that there will be
a callback to send_buf->mad_agent->send_handler() so that the sender
can call ib_free_send_mad(). Otherwise, the ib_mad_send_buf will be
leaked and the mad_agent reference count will never go to zero and the
IB device module cannot be unloaded. The above can happen without
this patch if process_mad() returns (IB_MAD_RESULT_SUCCESS |
IB_MAD_RESULT_CONSUMED).
If process_mad() returns IB_MAD_RESULT_SUCCESS and there is no agent
registered to receive the mad being sent, handle_outgoing_dr_smp()
returns zero which causes a MAD packet which is at the end of the
directed route to be incorrectly sent on the wire but doesn't cause a
hang since the HCA generates a send completion.
Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/core')
-rw-r--r-- | drivers/infiniband/core/mad.c | 12 |
1 files changed, 6 insertions, 6 deletions
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index dbcd285405ec..de922a04ca2d 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c | |||
@@ -742,9 +742,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, | |||
742 | break; | 742 | break; |
743 | case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED: | 743 | case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED: |
744 | kmem_cache_free(ib_mad_cache, mad_priv); | 744 | kmem_cache_free(ib_mad_cache, mad_priv); |
745 | kfree(local); | 745 | break; |
746 | ret = 1; | ||
747 | goto out; | ||
748 | case IB_MAD_RESULT_SUCCESS: | 746 | case IB_MAD_RESULT_SUCCESS: |
749 | /* Treat like an incoming receive MAD */ | 747 | /* Treat like an incoming receive MAD */ |
750 | port_priv = ib_get_mad_port(mad_agent_priv->agent.device, | 748 | port_priv = ib_get_mad_port(mad_agent_priv->agent.device, |
@@ -755,10 +753,12 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, | |||
755 | &mad_priv->mad.mad); | 753 | &mad_priv->mad.mad); |
756 | } | 754 | } |
757 | if (!port_priv || !recv_mad_agent) { | 755 | if (!port_priv || !recv_mad_agent) { |
756 | /* | ||
757 | * No receiving agent so drop packet and | ||
758 | * generate send completion. | ||
759 | */ | ||
758 | kmem_cache_free(ib_mad_cache, mad_priv); | 760 | kmem_cache_free(ib_mad_cache, mad_priv); |
759 | kfree(local); | 761 | break; |
760 | ret = 0; | ||
761 | goto out; | ||
762 | } | 762 | } |
763 | local->mad_priv = mad_priv; | 763 | local->mad_priv = mad_priv; |
764 | local->recv_mad_agent = recv_mad_agent; | 764 | local->recv_mad_agent = recv_mad_agent; |