Merge tag 'nfs-for-3.9-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust:
- Fix an Oops in the pNFS layoutget code
- Fix a number of NFSv4 and v4.1 state recovery deadlocks and hangs due
to the interaction of the session drain lock and state management
locks.
- Remove task->tk_xprt, which was hiding a lot of RCU dereferencing
bugs
- Fix a long standing NFSv3 posix lock recovery bug.
- Revert commit 324d003b0c ("NFS: add nfs_sb_deactive_async to avoid
deadlock"). It turned out that the root cause of the deadlock was
due to interactions with the workqueues that have now been resolved.
* tag 'nfs-for-3.9-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (22 commits)
NLM: Ensure that we resend all pending blocking locks after a reclaim
umount oops when remove blocklayoutdriver first
sunrpc: silence build warning in gss_fill_context
nfs: remove kfree() redundant null checks
NFSv4.1: Don't decode skipped layoutgets
NFSv4.1: Fix bulk recall and destroy of layouts
NFSv4.1: Fix an ABBA locking issue with session and state serialisation
NFSv4: Fix a reboot recovery race when opening a file
NFSv4: Ensure delegation recall and byte range lock removal don't conflict
NFSv4: Fix up the return values of nfs4_open_delegation_recall
NFSv4.1: Don't lose locks when a server reboots during delegation return
NFSv4.1: Prevent deadlocks between state recovery and file locking
NFSv4: Allow the state manager to mark an open_owner as being recovered
SUNRPC: Add missing static declaration to _gss_mech_get_by_name
Revert "NFS: add nfs_sb_deactive_async to avoid deadlock"
SUNRPC: Nuke the tk_xprt macro
SUNRPC: Avoid RCU dereferences in the transport bind and connect code
SUNRPC: Fix an RCU dereference in xprt_reserve
SUNRPC: Pass pointers to struct rpc_xprt to the congestion window
SUNRPC: Fix an RCU dereference in xs_local_rpcbind
...
This commit is contained in:
@@ -247,8 +247,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
|
||||
__func__, ctx->gc_expiry, now, timeout);
|
||||
return q;
|
||||
err:
|
||||
dprintk("RPC: %s returns %ld gc_expiry %lu now %lu timeout %u\n",
|
||||
__func__, -PTR_ERR(p), ctx->gc_expiry, now, timeout);
|
||||
dprintk("RPC: %s returns error %ld\n", __func__, -PTR_ERR(p));
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -1154,7 +1153,7 @@ gss_marshal(struct rpc_task *task, __be32 *p)
|
||||
|
||||
/* We compute the checksum for the verifier over the xdr-encoded bytes
|
||||
* starting with the xid and ending at the end of the credential: */
|
||||
iov.iov_base = xprt_skip_transport_header(task->tk_xprt,
|
||||
iov.iov_base = xprt_skip_transport_header(req->rq_xprt,
|
||||
req->rq_snd_buf.head[0].iov_base);
|
||||
iov.iov_len = (u8 *)p - (u8 *)iov.iov_base;
|
||||
xdr_buf_from_iov(&iov, &verf_buf);
|
||||
|
||||
@@ -140,7 +140,7 @@ gss_mech_get(struct gss_api_mech *gm)
|
||||
|
||||
EXPORT_SYMBOL_GPL(gss_mech_get);
|
||||
|
||||
struct gss_api_mech *
|
||||
static struct gss_api_mech *
|
||||
_gss_mech_get_by_name(const char *name)
|
||||
{
|
||||
struct gss_api_mech *pos, *gm = NULL;
|
||||
@@ -205,7 +205,7 @@ mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct gss_api_mech *_gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
|
||||
static struct gss_api_mech *_gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
|
||||
{
|
||||
struct gss_api_mech *gm = NULL, *pos;
|
||||
|
||||
|
||||
@@ -1400,7 +1400,7 @@ call_allocate(struct rpc_task *task)
|
||||
{
|
||||
unsigned int slack = task->tk_rqstp->rq_cred->cr_auth->au_cslack;
|
||||
struct rpc_rqst *req = task->tk_rqstp;
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
struct rpc_xprt *xprt = req->rq_xprt;
|
||||
struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
|
||||
|
||||
dprint_status(task);
|
||||
@@ -1508,7 +1508,7 @@ rpc_xdr_encode(struct rpc_task *task)
|
||||
static void
|
||||
call_bind(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
|
||||
|
||||
dprint_status(task);
|
||||
|
||||
@@ -1602,7 +1602,7 @@ retry_timeout:
|
||||
static void
|
||||
call_connect(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
|
||||
|
||||
dprintk("RPC: %5u call_connect xprt %p %s connected\n",
|
||||
task->tk_pid, xprt,
|
||||
@@ -1685,7 +1685,7 @@ call_transmit(struct rpc_task *task)
|
||||
if (rpc_reply_expected(task))
|
||||
return;
|
||||
task->tk_action = rpc_exit_task;
|
||||
rpc_wake_up_queued_task(&task->tk_xprt->pending, task);
|
||||
rpc_wake_up_queued_task(&task->tk_rqstp->rq_xprt->pending, task);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1784,7 +1784,7 @@ call_bc_transmit(struct rpc_task *task)
|
||||
*/
|
||||
printk(KERN_NOTICE "RPC: Could not send backchannel reply "
|
||||
"error: %d\n", task->tk_status);
|
||||
xprt_conditional_disconnect(task->tk_xprt,
|
||||
xprt_conditional_disconnect(req->rq_xprt,
|
||||
req->rq_connect_cookie);
|
||||
break;
|
||||
default:
|
||||
@@ -1836,7 +1836,7 @@ call_status(struct rpc_task *task)
|
||||
case -ETIMEDOUT:
|
||||
task->tk_action = call_timeout;
|
||||
if (task->tk_client->cl_discrtry)
|
||||
xprt_conditional_disconnect(task->tk_xprt,
|
||||
xprt_conditional_disconnect(req->rq_xprt,
|
||||
req->rq_connect_cookie);
|
||||
break;
|
||||
case -ECONNRESET:
|
||||
@@ -1991,7 +1991,7 @@ out_retry:
|
||||
if (task->tk_rqstp == req) {
|
||||
req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0;
|
||||
if (task->tk_client->cl_discrtry)
|
||||
xprt_conditional_disconnect(task->tk_xprt,
|
||||
xprt_conditional_disconnect(req->rq_xprt,
|
||||
req->rq_connect_cookie);
|
||||
}
|
||||
}
|
||||
@@ -2005,7 +2005,7 @@ rpc_encode_header(struct rpc_task *task)
|
||||
|
||||
/* FIXME: check buffer size? */
|
||||
|
||||
p = xprt_skip_transport_header(task->tk_xprt, p);
|
||||
p = xprt_skip_transport_header(req->rq_xprt, p);
|
||||
*p++ = req->rq_xid; /* XID */
|
||||
*p++ = htonl(RPC_CALL); /* CALL */
|
||||
*p++ = htonl(RPC_VERSION); /* RPC version */
|
||||
|
||||
@@ -430,21 +430,23 @@ __xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
|
||||
*/
|
||||
void xprt_release_rqst_cong(struct rpc_task *task)
|
||||
{
|
||||
__xprt_put_cong(task->tk_xprt, task->tk_rqstp);
|
||||
struct rpc_rqst *req = task->tk_rqstp;
|
||||
|
||||
__xprt_put_cong(req->rq_xprt, req);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xprt_release_rqst_cong);
|
||||
|
||||
/**
|
||||
* xprt_adjust_cwnd - adjust transport congestion window
|
||||
* @xprt: pointer to xprt
|
||||
* @task: recently completed RPC request used to adjust window
|
||||
* @result: result code of completed RPC request
|
||||
*
|
||||
* We use a time-smoothed congestion estimator to avoid heavy oscillation.
|
||||
*/
|
||||
void xprt_adjust_cwnd(struct rpc_task *task, int result)
|
||||
void xprt_adjust_cwnd(struct rpc_xprt *xprt, struct rpc_task *task, int result)
|
||||
{
|
||||
struct rpc_rqst *req = task->tk_rqstp;
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
unsigned long cwnd = xprt->cwnd;
|
||||
|
||||
if (result >= 0 && cwnd <= xprt->cong) {
|
||||
@@ -695,7 +697,7 @@ out_abort:
|
||||
*/
|
||||
void xprt_connect(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
|
||||
|
||||
dprintk("RPC: %5u xprt_connect xprt %p %s connected\n", task->tk_pid,
|
||||
xprt, (xprt_connected(xprt) ? "is" : "is not"));
|
||||
@@ -722,13 +724,13 @@ void xprt_connect(struct rpc_task *task)
|
||||
if (xprt_test_and_set_connecting(xprt))
|
||||
return;
|
||||
xprt->stat.connect_start = jiffies;
|
||||
xprt->ops->connect(task);
|
||||
xprt->ops->connect(xprt, task);
|
||||
}
|
||||
}
|
||||
|
||||
static void xprt_connect_status(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
|
||||
|
||||
if (task->tk_status == 0) {
|
||||
xprt->stat.connect_count++;
|
||||
@@ -832,7 +834,7 @@ static void xprt_timer(struct rpc_task *task)
|
||||
spin_lock_bh(&xprt->transport_lock);
|
||||
if (!req->rq_reply_bytes_recvd) {
|
||||
if (xprt->ops->timer)
|
||||
xprt->ops->timer(task);
|
||||
xprt->ops->timer(xprt, task);
|
||||
} else
|
||||
task->tk_status = 0;
|
||||
spin_unlock_bh(&xprt->transport_lock);
|
||||
@@ -1091,7 +1093,7 @@ EXPORT_SYMBOL_GPL(xprt_free);
|
||||
*/
|
||||
void xprt_reserve(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
struct rpc_xprt *xprt;
|
||||
|
||||
task->tk_status = 0;
|
||||
if (task->tk_rqstp != NULL)
|
||||
@@ -1099,7 +1101,10 @@ void xprt_reserve(struct rpc_task *task)
|
||||
|
||||
task->tk_timeout = 0;
|
||||
task->tk_status = -EAGAIN;
|
||||
rcu_read_lock();
|
||||
xprt = rcu_dereference(task->tk_client->cl_xprt);
|
||||
xprt->ops->alloc_slot(xprt, task);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)
|
||||
|
||||
@@ -171,7 +171,7 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target,
|
||||
struct rpcrdma_msg *headerp, enum rpcrdma_chunktype type)
|
||||
{
|
||||
struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
|
||||
struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_task->tk_xprt);
|
||||
struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt);
|
||||
int nsegs, nchunks = 0;
|
||||
unsigned int pos;
|
||||
struct rpcrdma_mr_seg *seg = req->rl_segments;
|
||||
@@ -366,7 +366,7 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
|
||||
int
|
||||
rpcrdma_marshal_req(struct rpc_rqst *rqst)
|
||||
{
|
||||
struct rpc_xprt *xprt = rqst->rq_task->tk_xprt;
|
||||
struct rpc_xprt *xprt = rqst->rq_xprt;
|
||||
struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
|
||||
struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
|
||||
char *base;
|
||||
|
||||
@@ -426,9 +426,8 @@ xprt_rdma_set_port(struct rpc_xprt *xprt, u16 port)
|
||||
}
|
||||
|
||||
static void
|
||||
xprt_rdma_connect(struct rpc_task *task)
|
||||
xprt_rdma_connect(struct rpc_xprt *xprt, struct rpc_task *task)
|
||||
{
|
||||
struct rpc_xprt *xprt = (struct rpc_xprt *)task->tk_xprt;
|
||||
struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
|
||||
|
||||
if (r_xprt->rx_ep.rep_connected != 0) {
|
||||
@@ -475,7 +474,7 @@ xprt_rdma_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
|
||||
static void *
|
||||
xprt_rdma_allocate(struct rpc_task *task, size_t size)
|
||||
{
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
|
||||
struct rpcrdma_req *req, *nreq;
|
||||
|
||||
req = rpcrdma_buffer_get(&rpcx_to_rdmax(xprt)->rx_buf);
|
||||
@@ -627,7 +626,7 @@ static int
|
||||
xprt_rdma_send_request(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_rqst *rqst = task->tk_rqstp;
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
struct rpc_xprt *xprt = rqst->rq_xprt;
|
||||
struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
|
||||
struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
|
||||
|
||||
|
||||
@@ -235,13 +235,13 @@ struct rpcrdma_create_data_internal {
|
||||
};
|
||||
|
||||
#define RPCRDMA_INLINE_READ_THRESHOLD(rq) \
|
||||
(rpcx_to_rdmad(rq->rq_task->tk_xprt).inline_rsize)
|
||||
(rpcx_to_rdmad(rq->rq_xprt).inline_rsize)
|
||||
|
||||
#define RPCRDMA_INLINE_WRITE_THRESHOLD(rq)\
|
||||
(rpcx_to_rdmad(rq->rq_task->tk_xprt).inline_wsize)
|
||||
(rpcx_to_rdmad(rq->rq_xprt).inline_wsize)
|
||||
|
||||
#define RPCRDMA_INLINE_PAD_VALUE(rq)\
|
||||
rpcx_to_rdmad(rq->rq_task->tk_xprt).padding
|
||||
rpcx_to_rdmad(rq->rq_xprt).padding
|
||||
|
||||
/*
|
||||
* Statistics for RPCRDMA
|
||||
|
||||
@@ -770,7 +770,7 @@ static void xs_tcp_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
|
||||
goto out_release;
|
||||
if (req->rq_bytes_sent == req->rq_snd_buf.len)
|
||||
goto out_release;
|
||||
set_bit(XPRT_CLOSE_WAIT, &task->tk_xprt->state);
|
||||
set_bit(XPRT_CLOSE_WAIT, &xprt->state);
|
||||
out_release:
|
||||
xprt_release_xprt(xprt, task);
|
||||
}
|
||||
@@ -1005,7 +1005,7 @@ static void xs_udp_data_ready(struct sock *sk, int len)
|
||||
|
||||
UDPX_INC_STATS_BH(sk, UDP_MIB_INDATAGRAMS);
|
||||
|
||||
xprt_adjust_cwnd(task, copied);
|
||||
xprt_adjust_cwnd(xprt, task, copied);
|
||||
xprt_complete_rqst(task, copied);
|
||||
|
||||
out_unlock:
|
||||
@@ -1646,9 +1646,9 @@ static void xs_udp_set_buffer_size(struct rpc_xprt *xprt, size_t sndsize, size_t
|
||||
*
|
||||
* Adjust the congestion window after a retransmit timeout has occurred.
|
||||
*/
|
||||
static void xs_udp_timer(struct rpc_task *task)
|
||||
static void xs_udp_timer(struct rpc_xprt *xprt, struct rpc_task *task)
|
||||
{
|
||||
xprt_adjust_cwnd(task, -ETIMEDOUT);
|
||||
xprt_adjust_cwnd(xprt, task, -ETIMEDOUT);
|
||||
}
|
||||
|
||||
static unsigned short xs_get_random_port(void)
|
||||
@@ -1731,7 +1731,9 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock)
|
||||
*/
|
||||
static void xs_local_rpcbind(struct rpc_task *task)
|
||||
{
|
||||
xprt_set_bound(task->tk_xprt);
|
||||
rcu_read_lock();
|
||||
xprt_set_bound(rcu_dereference(task->tk_client->cl_xprt));
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void xs_local_set_port(struct rpc_xprt *xprt, unsigned short port)
|
||||
@@ -2205,6 +2207,7 @@ out:
|
||||
|
||||
/**
|
||||
* xs_connect - connect a socket to a remote endpoint
|
||||
* @xprt: pointer to transport structure
|
||||
* @task: address of RPC task that manages state of connect request
|
||||
*
|
||||
* TCP: If the remote end dropped the connection, delay reconnecting.
|
||||
@@ -2216,9 +2219,8 @@ out:
|
||||
* If a UDP socket connect fails, the delay behavior here prevents
|
||||
* retry floods (hard mounts).
|
||||
*/
|
||||
static void xs_connect(struct rpc_task *task)
|
||||
static void xs_connect(struct rpc_xprt *xprt, struct rpc_task *task)
|
||||
{
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
|
||||
|
||||
if (transport->sock != NULL && !RPC_IS_SOFTCONN(task)) {
|
||||
|
||||
Reference in New Issue
Block a user