xprtrdma: RPC/RDMA must invoke xprt_wake_pending_tasks() in process context
An IB provider can invoke rpcrdma_conn_func() in an IRQ context, thus rpcrdma_conn_func() cannot be allowed to directly invoke generic RPC functions like xprt_wake_pending_tasks(). Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Tested-by: Steve Wise <swise@opengridcomputing.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
parent
4034ba0423
commit
254f91e2fa
@ -676,15 +676,11 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
|
|||||||
rqst->rq_private_buf = rqst->rq_rcv_buf;
|
rqst->rq_private_buf = rqst->rq_rcv_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This function is called when an async event is posted to
|
|
||||||
* the connection which changes the connection state. All it
|
|
||||||
* does at this point is mark the connection up/down, the rpc
|
|
||||||
* timers do the rest.
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
rpcrdma_conn_func(struct rpcrdma_ep *ep)
|
rpcrdma_connect_worker(struct work_struct *work)
|
||||||
{
|
{
|
||||||
|
struct rpcrdma_ep *ep =
|
||||||
|
container_of(work, struct rpcrdma_ep, rep_connect_worker.work);
|
||||||
struct rpc_xprt *xprt = ep->rep_xprt;
|
struct rpc_xprt *xprt = ep->rep_xprt;
|
||||||
|
|
||||||
spin_lock_bh(&xprt->transport_lock);
|
spin_lock_bh(&xprt->transport_lock);
|
||||||
@ -700,6 +696,18 @@ rpcrdma_conn_func(struct rpcrdma_ep *ep)
|
|||||||
spin_unlock_bh(&xprt->transport_lock);
|
spin_unlock_bh(&xprt->transport_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is called when an async event is posted to
|
||||||
|
* the connection which changes the connection state. All it
|
||||||
|
* does at this point is mark the connection up/down, the rpc
|
||||||
|
* timers do the rest.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
rpcrdma_conn_func(struct rpcrdma_ep *ep)
|
||||||
|
{
|
||||||
|
schedule_delayed_work(&ep->rep_connect_worker, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is called when memory window unbind which we are waiting
|
* This function is called when memory window unbind which we are waiting
|
||||||
* for completes. Just use rr_func (zeroed by upcall) to signal completion.
|
* for completes. Just use rr_func (zeroed by upcall) to signal completion.
|
||||||
|
@ -742,6 +742,7 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
|
|||||||
INIT_CQCOUNT(ep);
|
INIT_CQCOUNT(ep);
|
||||||
ep->rep_ia = ia;
|
ep->rep_ia = ia;
|
||||||
init_waitqueue_head(&ep->rep_connect_wait);
|
init_waitqueue_head(&ep->rep_connect_wait);
|
||||||
|
INIT_DELAYED_WORK(&ep->rep_connect_worker, rpcrdma_connect_worker);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a single cq for receive dto and mw_bind (only ever
|
* Create a single cq for receive dto and mw_bind (only ever
|
||||||
@ -817,6 +818,8 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
|
|||||||
dprintk("RPC: %s: entering, connected is %d\n",
|
dprintk("RPC: %s: entering, connected is %d\n",
|
||||||
__func__, ep->rep_connected);
|
__func__, ep->rep_connected);
|
||||||
|
|
||||||
|
cancel_delayed_work_sync(&ep->rep_connect_worker);
|
||||||
|
|
||||||
if (ia->ri_id->qp) {
|
if (ia->ri_id->qp) {
|
||||||
rc = rpcrdma_ep_disconnect(ep, ia);
|
rc = rpcrdma_ep_disconnect(ep, ia);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include <linux/wait.h> /* wait_queue_head_t, etc */
|
#include <linux/wait.h> /* wait_queue_head_t, etc */
|
||||||
#include <linux/spinlock.h> /* spinlock_t, etc */
|
#include <linux/spinlock.h> /* spinlock_t, etc */
|
||||||
#include <linux/atomic.h> /* atomic_t, etc */
|
#include <linux/atomic.h> /* atomic_t, etc */
|
||||||
|
#include <linux/workqueue.h> /* struct work_struct */
|
||||||
|
|
||||||
#include <rdma/rdma_cm.h> /* RDMA connection api */
|
#include <rdma/rdma_cm.h> /* RDMA connection api */
|
||||||
#include <rdma/ib_verbs.h> /* RDMA verbs api */
|
#include <rdma/ib_verbs.h> /* RDMA verbs api */
|
||||||
@ -87,6 +88,7 @@ struct rpcrdma_ep {
|
|||||||
struct rpc_xprt *rep_xprt; /* for rep_func */
|
struct rpc_xprt *rep_xprt; /* for rep_func */
|
||||||
struct rdma_conn_param rep_remote_cma;
|
struct rdma_conn_param rep_remote_cma;
|
||||||
struct sockaddr_storage rep_remote_addr;
|
struct sockaddr_storage rep_remote_addr;
|
||||||
|
struct delayed_work rep_connect_worker;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define INIT_CQCOUNT(ep) atomic_set(&(ep)->rep_cqcount, (ep)->rep_cqinit)
|
#define INIT_CQCOUNT(ep) atomic_set(&(ep)->rep_cqcount, (ep)->rep_cqinit)
|
||||||
@ -336,6 +338,7 @@ int rpcrdma_deregister_external(struct rpcrdma_mr_seg *,
|
|||||||
/*
|
/*
|
||||||
* RPC/RDMA connection management calls - xprtrdma/rpc_rdma.c
|
* RPC/RDMA connection management calls - xprtrdma/rpc_rdma.c
|
||||||
*/
|
*/
|
||||||
|
void rpcrdma_connect_worker(struct work_struct *);
|
||||||
void rpcrdma_conn_func(struct rpcrdma_ep *);
|
void rpcrdma_conn_func(struct rpcrdma_ep *);
|
||||||
void rpcrdma_reply_handler(struct rpcrdma_rep *);
|
void rpcrdma_reply_handler(struct rpcrdma_rep *);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user