Skip to content

Commit 29a47f4

Browse files
committed
Merge tag 'nfs-for-5.7-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust: "Highlights include: Stable fixes: - fix handling of backchannel binding in BIND_CONN_TO_SESSION Bugfixes: - Fix a credential use-after-free issue in pnfs_roc() - Fix potential posix_acl refcnt leak in nfs3_set_acl - defer slow parts of rpc_free_client() to a workqueue - Fix an Oopsable race in __nfs_list_for_each_server() - Fix trace point use-after-free race - Regression: the RDMA client no longer responds to server disconnect requests - Fix return values of xdr_stream_encode_item_{present, absent} - _pnfs_return_layout() must always wait for layoutreturn completion Cleanups: - Remove unreachable error conditions" * tag 'nfs-for-5.7-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFS: Fix a race in __nfs_list_for_each_server() NFSv4.1: fix handling of backchannel binding in BIND_CONN_TO_SESSION SUNRPC: defer slow parts of rpc_free_client() to a workqueue. NFSv4: Remove unreachable error condition due to rpc_run_task() SUNRPC: Remove unreachable error condition xprtrdma: Fix use of xdr_stream_encode_item_{present, absent} xprtrdma: Fix trace point use-after-free race xprtrdma: Restore wake-up-all to rpcrdma_cm_event_handler() nfs: Fix potential posix_acl refcnt leak in nfs3_set_acl NFS/pnfs: Fix a credential use-after-free issue in pnfs_roc() NFS/pnfs: Ensure that _pnfs_return_layout() waits for layoutreturn completion
2 parents ed6889d + 9c07b75 commit 29a47f4

File tree

10 files changed

+79
-36
lines changed

10 files changed

+79
-36
lines changed

fs/nfs/nfs3acl.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -253,37 +253,45 @@ int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
253253

254254
int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type)
255255
{
256-
struct posix_acl *alloc = NULL, *dfacl = NULL;
256+
struct posix_acl *orig = acl, *dfacl = NULL, *alloc;
257257
int status;
258258

259259
if (S_ISDIR(inode->i_mode)) {
260260
switch(type) {
261261
case ACL_TYPE_ACCESS:
262-
alloc = dfacl = get_acl(inode, ACL_TYPE_DEFAULT);
262+
alloc = get_acl(inode, ACL_TYPE_DEFAULT);
263263
if (IS_ERR(alloc))
264264
goto fail;
265+
dfacl = alloc;
265266
break;
266267

267268
case ACL_TYPE_DEFAULT:
268-
dfacl = acl;
269-
alloc = acl = get_acl(inode, ACL_TYPE_ACCESS);
269+
alloc = get_acl(inode, ACL_TYPE_ACCESS);
270270
if (IS_ERR(alloc))
271271
goto fail;
272+
dfacl = acl;
273+
acl = alloc;
272274
break;
273275
}
274276
}
275277

276278
if (acl == NULL) {
277-
alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
279+
alloc = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
278280
if (IS_ERR(alloc))
279281
goto fail;
282+
acl = alloc;
280283
}
281284
status = __nfs3_proc_setacls(inode, acl, dfacl);
282-
posix_acl_release(alloc);
285+
out:
286+
if (acl != orig)
287+
posix_acl_release(acl);
288+
if (dfacl != orig)
289+
posix_acl_release(dfacl);
283290
return status;
284291

285292
fail:
286-
return PTR_ERR(alloc);
293+
status = PTR_ERR(alloc);
294+
goto out;
287295
}
288296

289297
const struct xattr_handler *nfs3_xattr_handlers[] = {

fs/nfs/nfs4proc.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7891,6 +7891,7 @@ static void
78917891
nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata)
78927892
{
78937893
struct nfs41_bind_conn_to_session_args *args = task->tk_msg.rpc_argp;
7894+
struct nfs41_bind_conn_to_session_res *res = task->tk_msg.rpc_resp;
78947895
struct nfs_client *clp = args->client;
78957896

78967897
switch (task->tk_status) {
@@ -7899,6 +7900,12 @@ nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata)
78997900
nfs4_schedule_session_recovery(clp->cl_session,
79007901
task->tk_status);
79017902
}
7903+
if (args->dir == NFS4_CDFC4_FORE_OR_BOTH &&
7904+
res->dir != NFS4_CDFS4_BOTH) {
7905+
rpc_task_close_connection(task);
7906+
if (args->retries++ < MAX_BIND_CONN_TO_SESSION_RETRIES)
7907+
rpc_restart_call(task);
7908+
}
79027909
}
79037910

79047911
static const struct rpc_call_ops nfs4_bind_one_conn_to_session_ops = {
@@ -7921,6 +7928,7 @@ int nfs4_proc_bind_one_conn_to_session(struct rpc_clnt *clnt,
79217928
struct nfs41_bind_conn_to_session_args args = {
79227929
.client = clp,
79237930
.dir = NFS4_CDFC4_FORE_OR_BOTH,
7931+
.retries = 0,
79247932
};
79257933
struct nfs41_bind_conn_to_session_res res;
79267934
struct rpc_message msg = {
@@ -9191,8 +9199,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
91919199
nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0, 0);
91929200

91939201
task = rpc_run_task(&task_setup_data);
9194-
if (IS_ERR(task))
9195-
return ERR_CAST(task);
9202+
91969203
status = rpc_wait_for_completion_task(task);
91979204
if (status != 0)
91989205
goto out;

fs/nfs/pnfs.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,13 +1332,15 @@ _pnfs_return_layout(struct inode *ino)
13321332
!valid_layout) {
13331333
spin_unlock(&ino->i_lock);
13341334
dprintk("NFS: %s no layout segments to return\n", __func__);
1335-
goto out_put_layout_hdr;
1335+
goto out_wait_layoutreturn;
13361336
}
13371337

13381338
send = pnfs_prepare_layoutreturn(lo, &stateid, &cred, NULL);
13391339
spin_unlock(&ino->i_lock);
13401340
if (send)
13411341
status = pnfs_send_layoutreturn(lo, &stateid, &cred, IOMODE_ANY, true);
1342+
out_wait_layoutreturn:
1343+
wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, TASK_UNINTERRUPTIBLE);
13421344
out_put_layout_hdr:
13431345
pnfs_free_lseg_list(&tmp_list);
13441346
pnfs_put_layout_hdr(lo);
@@ -1456,18 +1458,15 @@ bool pnfs_roc(struct inode *ino,
14561458
/* lo ref dropped in pnfs_roc_release() */
14571459
layoutreturn = pnfs_prepare_layoutreturn(lo, &stateid, &lc_cred, &iomode);
14581460
/* If the creds don't match, we can't compound the layoutreturn */
1459-
if (!layoutreturn)
1461+
if (!layoutreturn || cred_fscmp(cred, lc_cred) != 0)
14601462
goto out_noroc;
1461-
if (cred_fscmp(cred, lc_cred) != 0)
1462-
goto out_noroc_put_cred;
14631463

14641464
roc = layoutreturn;
14651465
pnfs_init_layoutreturn_args(args, lo, &stateid, iomode);
14661466
res->lrs_present = 0;
14671467
layoutreturn = false;
1468-
1469-
out_noroc_put_cred:
14701468
put_cred(lc_cred);
1469+
14711470
out_noroc:
14721471
spin_unlock(&ino->i_lock);
14731472
rcu_read_unlock();

fs/nfs/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ static int __nfs_list_for_each_server(struct list_head *head,
185185

186186
rcu_read_lock();
187187
list_for_each_entry_rcu(server, head, client_link) {
188-
if (!nfs_sb_active(server->super))
188+
if (!(server->super && nfs_sb_active(server->super)))
189189
continue;
190190
rcu_read_unlock();
191191
if (last)

include/linux/nfs_xdr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,11 +1317,13 @@ struct nfs41_impl_id {
13171317
struct nfstime4 date;
13181318
};
13191319

1320+
#define MAX_BIND_CONN_TO_SESSION_RETRIES 3
13201321
struct nfs41_bind_conn_to_session_args {
13211322
struct nfs_client *client;
13221323
struct nfs4_sessionid sessionid;
13231324
u32 dir;
13241325
bool use_conn_in_rdma_mode;
1326+
int retries;
13251327
};
13261328

13271329
struct nfs41_bind_conn_to_session_res {

include/linux/sunrpc/clnt.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,13 @@ struct rpc_clnt {
7171
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
7272
struct dentry *cl_debugfs; /* debugfs directory */
7373
#endif
74-
struct rpc_xprt_iter cl_xpi;
74+
/* cl_work is only needed after cl_xpi is no longer used,
75+
* and that are of similar size
76+
*/
77+
union {
78+
struct rpc_xprt_iter cl_xpi;
79+
struct work_struct cl_work;
80+
};
7581
const struct cred *cl_cred;
7682
};
7783

@@ -236,4 +242,9 @@ static inline int rpc_reply_expected(struct rpc_task *task)
236242
(task->tk_msg.rpc_proc->p_decode != NULL);
237243
}
238244

245+
static inline void rpc_task_close_connection(struct rpc_task *task)
246+
{
247+
if (task->tk_xprt)
248+
xprt_force_disconnect(task->tk_xprt);
249+
}
239250
#endif /* _LINUX_SUNRPC_CLNT_H */

include/trace/events/rpcrdma.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -692,11 +692,10 @@ TRACE_EVENT(xprtrdma_prepsend_failed,
692692

693693
TRACE_EVENT(xprtrdma_post_send,
694694
TP_PROTO(
695-
const struct rpcrdma_req *req,
696-
int status
695+
const struct rpcrdma_req *req
697696
),
698697

699-
TP_ARGS(req, status),
698+
TP_ARGS(req),
700699

701700
TP_STRUCT__entry(
702701
__field(const void *, req)
@@ -705,7 +704,6 @@ TRACE_EVENT(xprtrdma_post_send,
705704
__field(unsigned int, client_id)
706705
__field(int, num_sge)
707706
__field(int, signaled)
708-
__field(int, status)
709707
),
710708

711709
TP_fast_assign(
@@ -718,15 +716,13 @@ TRACE_EVENT(xprtrdma_post_send,
718716
__entry->sc = req->rl_sendctx;
719717
__entry->num_sge = req->rl_wr.num_sge;
720718
__entry->signaled = req->rl_wr.send_flags & IB_SEND_SIGNALED;
721-
__entry->status = status;
722719
),
723720

724-
TP_printk("task:%u@%u req=%p sc=%p (%d SGE%s) %sstatus=%d",
721+
TP_printk("task:%u@%u req=%p sc=%p (%d SGE%s) %s",
725722
__entry->task_id, __entry->client_id,
726723
__entry->req, __entry->sc, __entry->num_sge,
727724
(__entry->num_sge == 1 ? "" : "s"),
728-
(__entry->signaled ? "signaled " : ""),
729-
__entry->status
725+
(__entry->signaled ? "signaled" : "")
730726
)
731727
);
732728

net/sunrpc/clnt.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,20 @@ EXPORT_SYMBOL_GPL(rpc_shutdown_client);
880880
/*
881881
* Free an RPC client
882882
*/
883+
static void rpc_free_client_work(struct work_struct *work)
884+
{
885+
struct rpc_clnt *clnt = container_of(work, struct rpc_clnt, cl_work);
886+
887+
/* These might block on processes that might allocate memory,
888+
* so they cannot be called in rpciod, so they are handled separately
889+
* here.
890+
*/
891+
rpc_clnt_debugfs_unregister(clnt);
892+
rpc_clnt_remove_pipedir(clnt);
893+
894+
kfree(clnt);
895+
rpciod_down();
896+
}
883897
static struct rpc_clnt *
884898
rpc_free_client(struct rpc_clnt *clnt)
885899
{
@@ -890,17 +904,16 @@ rpc_free_client(struct rpc_clnt *clnt)
890904
rcu_dereference(clnt->cl_xprt)->servername);
891905
if (clnt->cl_parent != clnt)
892906
parent = clnt->cl_parent;
893-
rpc_clnt_debugfs_unregister(clnt);
894-
rpc_clnt_remove_pipedir(clnt);
895907
rpc_unregister_client(clnt);
896908
rpc_free_iostats(clnt->cl_metrics);
897909
clnt->cl_metrics = NULL;
898910
xprt_put(rcu_dereference_raw(clnt->cl_xprt));
899911
xprt_iter_destroy(&clnt->cl_xpi);
900-
rpciod_down();
901912
put_cred(clnt->cl_cred);
902913
rpc_free_clid(clnt);
903-
kfree(clnt);
914+
915+
INIT_WORK(&clnt->cl_work, rpc_free_client_work);
916+
schedule_work(&clnt->cl_work);
904917
return parent;
905918
}
906919

@@ -2808,8 +2821,7 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
28082821
task = rpc_call_null_helper(clnt, xprt, NULL,
28092822
RPC_TASK_SOFT|RPC_TASK_SOFTCONN|RPC_TASK_ASYNC|RPC_TASK_NULLCREDS,
28102823
&rpc_cb_add_xprt_call_ops, data);
2811-
if (IS_ERR(task))
2812-
return PTR_ERR(task);
2824+
28132825
rpc_put_task(task);
28142826
success:
28152827
return 1;

net/sunrpc/xprtrdma/rpc_rdma.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,9 @@ static int rpcrdma_encode_read_list(struct rpcrdma_xprt *r_xprt,
388388
} while (nsegs);
389389

390390
done:
391-
return xdr_stream_encode_item_absent(xdr);
391+
if (xdr_stream_encode_item_absent(xdr) < 0)
392+
return -EMSGSIZE;
393+
return 0;
392394
}
393395

394396
/* Register and XDR encode the Write list. Supports encoding a list
@@ -454,7 +456,9 @@ static int rpcrdma_encode_write_list(struct rpcrdma_xprt *r_xprt,
454456
*segcount = cpu_to_be32(nchunks);
455457

456458
done:
457-
return xdr_stream_encode_item_absent(xdr);
459+
if (xdr_stream_encode_item_absent(xdr) < 0)
460+
return -EMSGSIZE;
461+
return 0;
458462
}
459463

460464
/* Register and XDR encode the Reply chunk. Supports encoding an array
@@ -480,8 +484,11 @@ static int rpcrdma_encode_reply_chunk(struct rpcrdma_xprt *r_xprt,
480484
int nsegs, nchunks;
481485
__be32 *segcount;
482486

483-
if (wtype != rpcrdma_replych)
484-
return xdr_stream_encode_item_absent(xdr);
487+
if (wtype != rpcrdma_replych) {
488+
if (xdr_stream_encode_item_absent(xdr) < 0)
489+
return -EMSGSIZE;
490+
return 0;
491+
}
485492

486493
seg = req->rl_segments;
487494
nsegs = rpcrdma_convert_iovs(r_xprt, &rqst->rq_rcv_buf, 0, wtype, seg);

net/sunrpc/xprtrdma/verbs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
289289
case RDMA_CM_EVENT_DISCONNECTED:
290290
ep->re_connect_status = -ECONNABORTED;
291291
disconnected:
292+
xprt_force_disconnect(xprt);
292293
return rpcrdma_ep_destroy(ep);
293294
default:
294295
break;
@@ -1355,8 +1356,8 @@ int rpcrdma_post_sends(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
13551356
--ep->re_send_count;
13561357
}
13571358

1359+
trace_xprtrdma_post_send(req);
13581360
rc = frwr_send(r_xprt, req);
1359-
trace_xprtrdma_post_send(req, rc);
13601361
if (rc)
13611362
return -ENOTCONN;
13621363
return 0;

0 commit comments

Comments
 (0)