Skip to content

Commit 24a52e4

Browse files
committed
Merge tag 'nfs-for-3.20-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull more NFS client updates from Trond Myklebust: "Highlights include: - Fix a use-after-free in decode_cb_sequence_args() - Fix a compile error when #undef CONFIG_PROC_FS - NFSv4.1 backchannel spinlocking issue - Cleanups in the NFS unstable write code requested by Linus - NFSv4.1 fix issues when the server denies our backchannel request - Cleanups in create_session and bind_conn_to_session" * tag 'nfs-for-3.20-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFSv4.1: Clean up bind_conn_to_session NFSv4.1: Always set up a forward channel when binding the session NFSv4.1: Don't set up a backchannel if the server didn't agree to do so NFSv4.1: Clean up create_session pnfs: Refactor the *_layout_mark_request_commit to use pnfs_layout_mark_request_commit NFSv4: Kill unused nfs_inode->delegation_state field NFS: struct nfs_commit_info.lock must always point to inode->i_lock nfs: Can call nfs_clear_page_commit() instead nfs: Provide and use helper functions for marking a page as unstable SUNRPC: Always manipulate rpc_rqst::rq_bc_pa_list under xprt->bc_pa_lock SUNRPC: Fix a compile error when #undef CONFIG_PROC_FS NFSv4.1: Convert open-coded array allocation calls to kmalloc_array() NFSv4.1: Fix a kfree() of uninitialised pointers in decode_cb_sequence_args
2 parents cd50b70 + 71a097c commit 24a52e4

File tree

19 files changed

+165
-158
lines changed

19 files changed

+165
-158
lines changed

fs/nfs/callback_proc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,8 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
427427
if (clp == NULL)
428428
goto out;
429429

430+
if (!(clp->cl_session->flags & SESSION4_BACK_CHAN))
431+
goto out;
430432
tbl = &clp->cl_session->bc_slot_table;
431433

432434
spin_lock(&tbl->slot_tbl_lock);

fs/nfs/callback_xdr.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
313313
goto out;
314314
}
315315

316-
args->devs = kmalloc(n * sizeof(*args->devs), GFP_KERNEL);
316+
args->devs = kmalloc_array(n, sizeof(*args->devs), GFP_KERNEL);
317317
if (!args->devs) {
318318
status = htonl(NFS4ERR_DELAY);
319319
goto out;
@@ -415,7 +415,7 @@ static __be32 decode_rc_list(struct xdr_stream *xdr,
415415
rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t));
416416
if (unlikely(p == NULL))
417417
goto out;
418-
rc_list->rcl_refcalls = kmalloc(rc_list->rcl_nrefcalls *
418+
rc_list->rcl_refcalls = kmalloc_array(rc_list->rcl_nrefcalls,
419419
sizeof(*rc_list->rcl_refcalls),
420420
GFP_KERNEL);
421421
if (unlikely(rc_list->rcl_refcalls == NULL))
@@ -464,8 +464,10 @@ static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp,
464464

465465
for (i = 0; i < args->csa_nrclists; i++) {
466466
status = decode_rc_list(xdr, &args->csa_rclists[i]);
467-
if (status)
467+
if (status) {
468+
args->csa_nrclists = i;
468469
goto out_free;
470+
}
469471
}
470472
}
471473
status = 0;

fs/nfs/delegation.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
180180
delegation->cred = get_rpccred(cred);
181181
clear_bit(NFS_DELEGATION_NEED_RECLAIM,
182182
&delegation->flags);
183-
NFS_I(inode)->delegation_state = delegation->type;
184183
spin_unlock(&delegation->lock);
185184
put_rpccred(oldcred);
186185
rcu_read_unlock();
@@ -275,7 +274,6 @@ nfs_detach_delegation_locked(struct nfs_inode *nfsi,
275274
set_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
276275
list_del_rcu(&delegation->super_list);
277276
delegation->inode = NULL;
278-
nfsi->delegation_state = 0;
279277
rcu_assign_pointer(nfsi->delegation, NULL);
280278
spin_unlock(&delegation->lock);
281279
return delegation;
@@ -355,7 +353,6 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
355353
&delegation->stateid)) {
356354
nfs_update_inplace_delegation(old_delegation,
357355
delegation);
358-
nfsi->delegation_state = old_delegation->type;
359356
goto out;
360357
}
361358
/*
@@ -379,7 +376,6 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
379376
goto out;
380377
}
381378
list_add_rcu(&delegation->super_list, &server->delegations);
382-
nfsi->delegation_state = delegation->type;
383379
rcu_assign_pointer(nfsi->delegation, delegation);
384380
delegation = NULL;
385381

fs/nfs/direct.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ static void nfs_direct_release_pages(struct page **pages, unsigned int npages)
283283
void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo,
284284
struct nfs_direct_req *dreq)
285285
{
286-
cinfo->lock = &dreq->lock;
286+
cinfo->lock = &dreq->inode->i_lock;
287287
cinfo->mds = &dreq->mds_cinfo;
288288
cinfo->ds = &dreq->ds_cinfo;
289289
cinfo->dreq = dreq;

fs/nfs/filelayout/filelayout.c

Lines changed: 10 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -960,52 +960,19 @@ filelayout_mark_request_commit(struct nfs_page *req,
960960
{
961961
struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
962962
u32 i, j;
963-
struct list_head *list;
964-
struct pnfs_commit_bucket *buckets;
965963

966964
if (fl->commit_through_mds) {
967-
list = &cinfo->mds->list;
968-
spin_lock(cinfo->lock);
969-
goto mds_commit;
970-
}
971-
972-
/* Note that we are calling nfs4_fl_calc_j_index on each page
973-
* that ends up being committed to a data server. An attractive
974-
* alternative is to add a field to nfs_write_data and nfs_page
975-
* to store the value calculated in filelayout_write_pagelist
976-
* and just use that here.
977-
*/
978-
j = nfs4_fl_calc_j_index(lseg, req_offset(req));
979-
i = select_bucket_index(fl, j);
980-
spin_lock(cinfo->lock);
981-
buckets = cinfo->ds->buckets;
982-
list = &buckets[i].written;
983-
if (list_empty(list)) {
984-
/* Non-empty buckets hold a reference on the lseg. That ref
985-
* is normally transferred to the COMMIT call and released
986-
* there. It could also be released if the last req is pulled
987-
* off due to a rewrite, in which case it will be done in
988-
* pnfs_generic_clear_request_commit
965+
nfs_request_add_commit_list(req, &cinfo->mds->list, cinfo);
966+
} else {
967+
/* Note that we are calling nfs4_fl_calc_j_index on each page
968+
* that ends up being committed to a data server. An attractive
969+
* alternative is to add a field to nfs_write_data and nfs_page
970+
* to store the value calculated in filelayout_write_pagelist
971+
* and just use that here.
989972
*/
990-
buckets[i].wlseg = pnfs_get_lseg(lseg);
991-
}
992-
set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
993-
cinfo->ds->nwritten++;
994-
995-
mds_commit:
996-
/* nfs_request_add_commit_list(). We need to add req to list without
997-
* dropping cinfo lock.
998-
*/
999-
set_bit(PG_CLEAN, &(req)->wb_flags);
1000-
nfs_list_add_request(req, list);
1001-
cinfo->mds->ncommit++;
1002-
spin_unlock(cinfo->lock);
1003-
if (!cinfo->dreq) {
1004-
inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
1005-
inc_bdi_stat(inode_to_bdi(page_file_mapping(req->wb_page)->host),
1006-
BDI_RECLAIMABLE);
1007-
__mark_inode_dirty(req->wb_context->dentry->d_inode,
1008-
I_DIRTY_DATASYNC);
973+
j = nfs4_fl_calc_j_index(lseg, req_offset(req));
974+
i = select_bucket_index(fl, j);
975+
pnfs_layout_mark_request_commit(req, lseg, cinfo, i);
1009976
}
1010977
}
1011978

fs/nfs/flexfilelayout/flexfilelayout.c

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,47 +1332,6 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
13321332
return PNFS_ATTEMPTED;
13331333
}
13341334

1335-
static void
1336-
ff_layout_mark_request_commit(struct nfs_page *req,
1337-
struct pnfs_layout_segment *lseg,
1338-
struct nfs_commit_info *cinfo,
1339-
u32 ds_commit_idx)
1340-
{
1341-
struct list_head *list;
1342-
struct pnfs_commit_bucket *buckets;
1343-
1344-
spin_lock(cinfo->lock);
1345-
buckets = cinfo->ds->buckets;
1346-
list = &buckets[ds_commit_idx].written;
1347-
if (list_empty(list)) {
1348-
/* Non-empty buckets hold a reference on the lseg. That ref
1349-
* is normally transferred to the COMMIT call and released
1350-
* there. It could also be released if the last req is pulled
1351-
* off due to a rewrite, in which case it will be done in
1352-
* pnfs_common_clear_request_commit
1353-
*/
1354-
WARN_ON_ONCE(buckets[ds_commit_idx].wlseg != NULL);
1355-
buckets[ds_commit_idx].wlseg = pnfs_get_lseg(lseg);
1356-
}
1357-
set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
1358-
cinfo->ds->nwritten++;
1359-
1360-
/* nfs_request_add_commit_list(). We need to add req to list without
1361-
* dropping cinfo lock.
1362-
*/
1363-
set_bit(PG_CLEAN, &(req)->wb_flags);
1364-
nfs_list_add_request(req, list);
1365-
cinfo->mds->ncommit++;
1366-
spin_unlock(cinfo->lock);
1367-
if (!cinfo->dreq) {
1368-
inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
1369-
inc_bdi_stat(inode_to_bdi(page_file_mapping(req->wb_page)->host),
1370-
BDI_RECLAIMABLE);
1371-
__mark_inode_dirty(req->wb_context->dentry->d_inode,
1372-
I_DIRTY_DATASYNC);
1373-
}
1374-
}
1375-
13761335
static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i)
13771336
{
13781337
return i;
@@ -1540,7 +1499,7 @@ static struct pnfs_layoutdriver_type flexfilelayout_type = {
15401499
.pg_write_ops = &ff_layout_pg_write_ops,
15411500
.get_ds_info = ff_layout_get_ds_info,
15421501
.free_deviceid_node = ff_layout_free_deveiceid_node,
1543-
.mark_request_commit = ff_layout_mark_request_commit,
1502+
.mark_request_commit = pnfs_layout_mark_request_commit,
15441503
.clear_request_commit = pnfs_generic_clear_request_commit,
15451504
.scan_commit_lists = pnfs_generic_scan_commit_lists,
15461505
.recover_commit_reqs = pnfs_generic_recover_commit_reqs,

fs/nfs/inode.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1775,7 +1775,6 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi)
17751775
#if IS_ENABLED(CONFIG_NFS_V4)
17761776
INIT_LIST_HEAD(&nfsi->open_states);
17771777
nfsi->delegation = NULL;
1778-
nfsi->delegation_state = 0;
17791778
init_rwsem(&nfsi->rwsem);
17801779
nfsi->layout = NULL;
17811780
#endif

fs/nfs/internal.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,19 @@ void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize)
597597
sb->s_maxbytes = MAX_LFS_FILESIZE;
598598
}
599599

600+
/*
601+
* Record the page as unstable and mark its inode as dirty.
602+
*/
603+
static inline
604+
void nfs_mark_page_unstable(struct page *page)
605+
{
606+
struct inode *inode = page_file_mapping(page)->host;
607+
608+
inc_zone_page_state(page, NR_UNSTABLE_NFS);
609+
inc_bdi_stat(inode_to_bdi(inode), BDI_RECLAIMABLE);
610+
__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
611+
}
612+
600613
/*
601614
* Determine the number of bytes of data the page contains
602615
*/

fs/nfs/nfs4proc.c

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6648,47 +6648,47 @@ nfs41_same_server_scope(struct nfs41_server_scope *a,
66486648
int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred)
66496649
{
66506650
int status;
6651+
struct nfs41_bind_conn_to_session_args args = {
6652+
.client = clp,
6653+
.dir = NFS4_CDFC4_FORE_OR_BOTH,
6654+
};
66516655
struct nfs41_bind_conn_to_session_res res;
66526656
struct rpc_message msg = {
66536657
.rpc_proc =
66546658
&nfs4_procedures[NFSPROC4_CLNT_BIND_CONN_TO_SESSION],
6655-
.rpc_argp = clp,
6659+
.rpc_argp = &args,
66566660
.rpc_resp = &res,
66576661
.rpc_cred = cred,
66586662
};
66596663

66606664
dprintk("--> %s\n", __func__);
66616665

6662-
res.session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS);
6663-
if (unlikely(res.session == NULL)) {
6664-
status = -ENOMEM;
6665-
goto out;
6666-
}
6666+
nfs4_copy_sessionid(&args.sessionid, &clp->cl_session->sess_id);
6667+
if (!(clp->cl_session->flags & SESSION4_BACK_CHAN))
6668+
args.dir = NFS4_CDFC4_FORE;
66676669

66686670
status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
66696671
trace_nfs4_bind_conn_to_session(clp, status);
66706672
if (status == 0) {
6671-
if (memcmp(res.session->sess_id.data,
6673+
if (memcmp(res.sessionid.data,
66726674
clp->cl_session->sess_id.data, NFS4_MAX_SESSIONID_LEN)) {
66736675
dprintk("NFS: %s: Session ID mismatch\n", __func__);
66746676
status = -EIO;
6675-
goto out_session;
6677+
goto out;
66766678
}
6677-
if (res.dir != NFS4_CDFS4_BOTH) {
6679+
if ((res.dir & args.dir) != res.dir || res.dir == 0) {
66786680
dprintk("NFS: %s: Unexpected direction from server\n",
66796681
__func__);
66806682
status = -EIO;
6681-
goto out_session;
6683+
goto out;
66826684
}
6683-
if (res.use_conn_in_rdma_mode) {
6685+
if (res.use_conn_in_rdma_mode != args.use_conn_in_rdma_mode) {
66846686
dprintk("NFS: %s: Server returned RDMA mode = true\n",
66856687
__func__);
66866688
status = -EIO;
6687-
goto out_session;
6689+
goto out;
66886690
}
66896691
}
6690-
out_session:
6691-
kfree(res.session);
66926692
out:
66936693
dprintk("<-- %s status= %d\n", __func__, status);
66946694
return status;
@@ -7166,10 +7166,11 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)
71667166
args->bc_attrs.max_reqs);
71677167
}
71687168

7169-
static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session)
7169+
static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args,
7170+
struct nfs41_create_session_res *res)
71707171
{
71717172
struct nfs4_channel_attrs *sent = &args->fc_attrs;
7172-
struct nfs4_channel_attrs *rcvd = &session->fc_attrs;
7173+
struct nfs4_channel_attrs *rcvd = &res->fc_attrs;
71737174

71747175
if (rcvd->max_resp_sz > sent->max_resp_sz)
71757176
return -EINVAL;
@@ -7188,11 +7189,14 @@ static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args
71887189
return 0;
71897190
}
71907191

7191-
static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session)
7192+
static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args,
7193+
struct nfs41_create_session_res *res)
71927194
{
71937195
struct nfs4_channel_attrs *sent = &args->bc_attrs;
7194-
struct nfs4_channel_attrs *rcvd = &session->bc_attrs;
7196+
struct nfs4_channel_attrs *rcvd = &res->bc_attrs;
71957197

7198+
if (!(res->flags & SESSION4_BACK_CHAN))
7199+
goto out;
71967200
if (rcvd->max_rqst_sz > sent->max_rqst_sz)
71977201
return -EINVAL;
71987202
if (rcvd->max_resp_sz < sent->max_resp_sz)
@@ -7204,18 +7208,30 @@ static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args
72047208
return -EINVAL;
72057209
if (rcvd->max_reqs != sent->max_reqs)
72067210
return -EINVAL;
7211+
out:
72077212
return 0;
72087213
}
72097214

72107215
static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args,
7211-
struct nfs4_session *session)
7216+
struct nfs41_create_session_res *res)
72127217
{
72137218
int ret;
72147219

7215-
ret = nfs4_verify_fore_channel_attrs(args, session);
7220+
ret = nfs4_verify_fore_channel_attrs(args, res);
72167221
if (ret)
72177222
return ret;
7218-
return nfs4_verify_back_channel_attrs(args, session);
7223+
return nfs4_verify_back_channel_attrs(args, res);
7224+
}
7225+
7226+
static void nfs4_update_session(struct nfs4_session *session,
7227+
struct nfs41_create_session_res *res)
7228+
{
7229+
nfs4_copy_sessionid(&session->sess_id, &res->sessionid);
7230+
session->flags = res->flags;
7231+
memcpy(&session->fc_attrs, &res->fc_attrs, sizeof(session->fc_attrs));
7232+
if (res->flags & SESSION4_BACK_CHAN)
7233+
memcpy(&session->bc_attrs, &res->bc_attrs,
7234+
sizeof(session->bc_attrs));
72197235
}
72207236

72217237
static int _nfs4_proc_create_session(struct nfs_client *clp,
@@ -7224,11 +7240,12 @@ static int _nfs4_proc_create_session(struct nfs_client *clp,
72247240
struct nfs4_session *session = clp->cl_session;
72257241
struct nfs41_create_session_args args = {
72267242
.client = clp,
7243+
.clientid = clp->cl_clientid,
7244+
.seqid = clp->cl_seqid,
72277245
.cb_program = NFS4_CALLBACK,
72287246
};
7229-
struct nfs41_create_session_res res = {
7230-
.client = clp,
7231-
};
7247+
struct nfs41_create_session_res res;
7248+
72327249
struct rpc_message msg = {
72337250
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION],
72347251
.rpc_argp = &args,
@@ -7245,11 +7262,15 @@ static int _nfs4_proc_create_session(struct nfs_client *clp,
72457262

72467263
if (!status) {
72477264
/* Verify the session's negotiated channel_attrs values */
7248-
status = nfs4_verify_channel_attrs(&args, session);
7265+
status = nfs4_verify_channel_attrs(&args, &res);
72497266
/* Increment the clientid slot sequence id */
7250-
clp->cl_seqid++;
7267+
if (clp->cl_seqid == res.seqid)
7268+
clp->cl_seqid++;
7269+
if (status)
7270+
goto out;
7271+
nfs4_update_session(session, &res);
72517272
}
7252-
7273+
out:
72537274
return status;
72547275
}
72557276

fs/nfs/nfs4session.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ int nfs4_setup_session_slot_tables(struct nfs4_session *ses)
450450
tbl = &ses->fc_slot_table;
451451
tbl->session = ses;
452452
status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1);
453-
if (status) /* -ENOMEM */
453+
if (status || !(ses->flags & SESSION4_BACK_CHAN)) /* -ENOMEM */
454454
return status;
455455
/* Back channel */
456456
tbl = &ses->bc_slot_table;

0 commit comments

Comments
 (0)