@@ -693,7 +693,7 @@ int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
mr->state = RXE_MR_STATE_INVALID;
rxe_put(mr_pd(mr));
- rxe_put(mr);
+ rxe_wait(mr);
return 0;
}
@@ -64,8 +64,8 @@ int rxe_dealloc_mw(struct ib_mw *ibmw)
rxe_do_dealloc_mw(mw);
spin_unlock_bh(&mw->lock);
- rxe_put(mw);
rxe_put(pd);
+ rxe_wait(mw);
return 0;
}
@@ -6,6 +6,8 @@
#include "rxe.h"
+#define RXE_POOL_TIMEOUT (200)
+#define RXE_POOL_MAX_TIMEOUTS (3)
#define RXE_POOL_ALIGN (16)
static const struct rxe_type_info {
@@ -158,6 +160,7 @@ void *rxe_alloc(struct rxe_pool *pool)
elem->pool = pool;
elem->obj = obj;
kref_init(&elem->ref_cnt);
+ init_completion(&elem->complete);
err = xa_alloc_cyclic(&pool->xa, &elem->index, NULL, pool->limit,
&pool->next, GFP_KERNEL);
@@ -186,6 +189,7 @@ int __rxe_add_to_pool(struct rxe_pool *pool, struct rxe_pool_elem *elem)
elem->pool = pool;
elem->obj = (u8 *)elem - pool->elem_offset;
kref_init(&elem->ref_cnt);
+ init_completion(&elem->complete);
err = xa_alloc_cyclic(&pool->xa, &elem->index, NULL, pool->limit,
&pool->next, GFP_KERNEL);
@@ -228,6 +232,29 @@ static void rxe_elem_release(struct kref *kref)
__xa_erase(&pool->xa, elem->index);
xa_unlock_irqrestore(xa, flags);
+ complete(&elem->complete);
+}
+
+int __rxe_wait(struct rxe_pool_elem *elem)
+{
+ struct rxe_pool *pool = elem->pool;
+ static int timeout = RXE_POOL_TIMEOUT;
+ int ret, err = 0;
+
+ __rxe_put(elem);
+
+ if (timeout) {
+ ret = wait_for_completion_timeout(&elem->complete, timeout);
+ if (!ret) {
+ pr_warn("Timed out waiting for %s#%d to complete\n",
+ pool->name, elem->index);
+ if (++pool->timeouts >= RXE_POOL_MAX_TIMEOUTS)
+ timeout = 0;
+
+ err = -EINVAL;
+ }
+ }
+
if (pool->cleanup)
pool->cleanup(elem);
@@ -235,6 +262,8 @@ static void rxe_elem_release(struct kref *kref)
kfree(elem->obj);
atomic_dec(&pool->num_elem);
+
+ return err;
}
int __rxe_get(struct rxe_pool_elem *elem)
@@ -28,6 +28,7 @@ struct rxe_pool_elem {
void *obj;
struct kref ref_cnt;
struct list_head list;
+ struct completion complete;
u32 index;
};
@@ -37,6 +38,7 @@ struct rxe_pool {
void (*cleanup)(struct rxe_pool_elem *elem);
enum rxe_pool_flags flags;
enum rxe_elem_type type;
+ unsigned int timeouts;
unsigned int max_elem;
atomic_t num_elem;
@@ -77,6 +79,9 @@ int __rxe_put(struct rxe_pool_elem *elem);
#define rxe_put(obj) __rxe_put(&(obj)->elem)
+int __rxe_wait(struct rxe_pool_elem *elem);
+#define rxe_wait(obj) __rxe_wait(&(obj)->elem)
+
#define rxe_read(obj) kref_read(&(obj)->elem.ref_cnt)
int __rxe_show(struct rxe_pool_elem *elem);
@@ -115,7 +115,7 @@ static void rxe_dealloc_ucontext(struct ib_ucontext *ibuc)
{
struct rxe_ucontext *uc = to_ruc(ibuc);
- rxe_put(uc);
+ rxe_wait(uc);
}
static int rxe_port_immutable(struct ib_device *dev, u32 port_num,
@@ -149,7 +149,7 @@ static int rxe_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
{
struct rxe_pd *pd = to_rpd(ibpd);
- rxe_put(pd);
+ rxe_wait(pd);
return 0;
}
@@ -188,7 +188,7 @@ static int rxe_create_ah(struct ib_ah *ibah,
err = copy_to_user(&uresp->ah_num, &ah->ah_num,
sizeof(uresp->ah_num));
if (err) {
- rxe_put(ah);
+ rxe_wait(ah);
return -EFAULT;
}
} else if (ah->is_user) {
@@ -231,7 +231,7 @@ static int rxe_destroy_ah(struct ib_ah *ibah, u32 flags)
struct rxe_ah *ah = to_rah(ibah);
rxe_hide(ah);
- rxe_put(ah);
+ rxe_wait(ah);
return 0;
}
@@ -318,7 +318,7 @@ static int rxe_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init,
err2:
rxe_put(pd);
- rxe_put(srq);
+ rxe_wait(srq);
err1:
return err;
}
@@ -377,7 +377,7 @@ static int rxe_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata)
rxe_queue_cleanup(srq->rq.queue);
rxe_put(srq->pd);
- rxe_put(srq);
+ rxe_wait(srq);
return 0;
}
@@ -448,7 +448,7 @@ static int rxe_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init,
return 0;
qp_init:
- rxe_put(qp);
+ rxe_wait(qp);
return err;
}
@@ -503,7 +503,7 @@ static int rxe_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
return ret;
rxe_qp_destroy(qp);
- rxe_put(qp);
+ rxe_wait(qp);
return 0;
}
@@ -816,7 +816,7 @@ static int rxe_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
rxe_cq_disable(cq);
- rxe_put(cq);
+ rxe_wait(cq);
return 0;
}
@@ -946,7 +946,7 @@ static struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd,
err3:
rxe_put(pd);
- rxe_put(mr);
+ rxe_wait(mr);
err2:
return ERR_PTR(err);
}
@@ -980,7 +980,7 @@ static struct ib_mr *rxe_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type,
err2:
rxe_put(pd);
- rxe_put(mr);
+ rxe_wait(mr);
err1:
return ERR_PTR(err);
}
Reference counting for object deletion can cause an object to wait for something else to happen before an object gets deleted. The destroy verbs can then return to rdma-core with the object still holding references. Adding wait_for_completion in this path prevents this. Signed-off-by: Bob Pearson <rpearsonhpe@gmail.com> --- drivers/infiniband/sw/rxe/rxe_mr.c | 2 +- drivers/infiniband/sw/rxe/rxe_mw.c | 2 +- drivers/infiniband/sw/rxe/rxe_pool.c | 29 +++++++++++++++++++++++++++ drivers/infiniband/sw/rxe/rxe_pool.h | 5 +++++ drivers/infiniband/sw/rxe/rxe_verbs.c | 22 ++++++++++---------- 5 files changed, 47 insertions(+), 13 deletions(-)