diff options
author | Steve Wise <swise@opengridcomputing.com> | 2008-03-04 17:44:52 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-03-11 00:22:22 -0400 |
commit | d7c1fbd6606085dbf95e47068d6bd2db8a180e38 (patch) | |
tree | 0852af87269facc5f07f08bd20387f183976cca2 /drivers/infiniband | |
parent | d33ed425c6cc14370d8c418b504328d2c3db58b4 (diff) |
RDMA/iwcm: Don't access a cm_id after dropping reference
cm_work_handler() can access cm_id_priv after it drops its reference
by calling iwch_deref_id(), which might cause it to be freed. The fix
is to look at whether IWCM_F_CALLBACK_DESTROY is set _before_ dropping
the reference. Then if it was set, free the cm_id on this thread.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/core/iwcm.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index 223b1aa7d92b..81c9195b512a 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c | |||
@@ -839,6 +839,7 @@ static void cm_work_handler(struct work_struct *_work) | |||
839 | unsigned long flags; | 839 | unsigned long flags; |
840 | int empty; | 840 | int empty; |
841 | int ret = 0; | 841 | int ret = 0; |
842 | int destroy_id; | ||
842 | 843 | ||
843 | spin_lock_irqsave(&cm_id_priv->lock, flags); | 844 | spin_lock_irqsave(&cm_id_priv->lock, flags); |
844 | empty = list_empty(&cm_id_priv->work_list); | 845 | empty = list_empty(&cm_id_priv->work_list); |
@@ -857,9 +858,9 @@ static void cm_work_handler(struct work_struct *_work) | |||
857 | destroy_cm_id(&cm_id_priv->id); | 858 | destroy_cm_id(&cm_id_priv->id); |
858 | } | 859 | } |
859 | BUG_ON(atomic_read(&cm_id_priv->refcount)==0); | 860 | BUG_ON(atomic_read(&cm_id_priv->refcount)==0); |
861 | destroy_id = test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags); | ||
860 | if (iwcm_deref_id(cm_id_priv)) { | 862 | if (iwcm_deref_id(cm_id_priv)) { |
861 | if (test_bit(IWCM_F_CALLBACK_DESTROY, | 863 | if (destroy_id) { |
862 | &cm_id_priv->flags)) { | ||
863 | BUG_ON(!list_empty(&cm_id_priv->work_list)); | 864 | BUG_ON(!list_empty(&cm_id_priv->work_list)); |
864 | free_cm_id(cm_id_priv); | 865 | free_cm_id(cm_id_priv); |
865 | } | 866 | } |