diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-21 17:02:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-21 17:02:59 -0500 |
commit | 24a52e412ef22989b63c35428652598dc995812c (patch) | |
tree | d8174bc4dfb2b7913896ef46f4366087da8ca42c /fs | |
parent | cd50b70ccd5c87794ec28bfb87b7fba9961eb0ae (diff) | |
parent | 71a097c6de9a49afd0f96b3ecef70c4eb04efde7 (diff) |
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
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/callback_proc.c | 2 | ||||
-rw-r--r-- | fs/nfs/callback_xdr.c | 8 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 4 | ||||
-rw-r--r-- | fs/nfs/direct.c | 2 | ||||
-rw-r--r-- | fs/nfs/filelayout/filelayout.c | 53 | ||||
-rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayout.c | 43 | ||||
-rw-r--r-- | fs/nfs/inode.c | 1 | ||||
-rw-r--r-- | fs/nfs/internal.h | 13 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 75 | ||||
-rw-r--r-- | fs/nfs/nfs4session.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4session.h | 6 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 32 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 4 | ||||
-rw-r--r-- | fs/nfs/pnfs_nfs.c | 30 | ||||
-rw-r--r-- | fs/nfs/write.c | 16 |
15 files changed, 140 insertions, 151 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index e36a9d78ea49..197806fb87ff 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -427,6 +427,8 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
427 | if (clp == NULL) | 427 | if (clp == NULL) |
428 | goto out; | 428 | goto out; |
429 | 429 | ||
430 | if (!(clp->cl_session->flags & SESSION4_BACK_CHAN)) | ||
431 | goto out; | ||
430 | tbl = &clp->cl_session->bc_slot_table; | 432 | tbl = &clp->cl_session->bc_slot_table; |
431 | 433 | ||
432 | spin_lock(&tbl->slot_tbl_lock); | 434 | spin_lock(&tbl->slot_tbl_lock); |
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index f4ccfe6521ec..19ca95cdfd9b 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -313,7 +313,7 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp, | |||
313 | goto out; | 313 | goto out; |
314 | } | 314 | } |
315 | 315 | ||
316 | args->devs = kmalloc(n * sizeof(*args->devs), GFP_KERNEL); | 316 | args->devs = kmalloc_array(n, sizeof(*args->devs), GFP_KERNEL); |
317 | if (!args->devs) { | 317 | if (!args->devs) { |
318 | status = htonl(NFS4ERR_DELAY); | 318 | status = htonl(NFS4ERR_DELAY); |
319 | goto out; | 319 | goto out; |
@@ -415,7 +415,7 @@ static __be32 decode_rc_list(struct xdr_stream *xdr, | |||
415 | rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t)); | 415 | rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t)); |
416 | if (unlikely(p == NULL)) | 416 | if (unlikely(p == NULL)) |
417 | goto out; | 417 | goto out; |
418 | rc_list->rcl_refcalls = kmalloc(rc_list->rcl_nrefcalls * | 418 | rc_list->rcl_refcalls = kmalloc_array(rc_list->rcl_nrefcalls, |
419 | sizeof(*rc_list->rcl_refcalls), | 419 | sizeof(*rc_list->rcl_refcalls), |
420 | GFP_KERNEL); | 420 | GFP_KERNEL); |
421 | if (unlikely(rc_list->rcl_refcalls == NULL)) | 421 | if (unlikely(rc_list->rcl_refcalls == NULL)) |
@@ -464,8 +464,10 @@ static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp, | |||
464 | 464 | ||
465 | for (i = 0; i < args->csa_nrclists; i++) { | 465 | for (i = 0; i < args->csa_nrclists; i++) { |
466 | status = decode_rc_list(xdr, &args->csa_rclists[i]); | 466 | status = decode_rc_list(xdr, &args->csa_rclists[i]); |
467 | if (status) | 467 | if (status) { |
468 | args->csa_nrclists = i; | ||
468 | goto out_free; | 469 | goto out_free; |
470 | } | ||
469 | } | 471 | } |
470 | } | 472 | } |
471 | status = 0; | 473 | status = 0; |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index da5433230bb1..a1f0685b42ff 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -180,7 +180,6 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, | |||
180 | delegation->cred = get_rpccred(cred); | 180 | delegation->cred = get_rpccred(cred); |
181 | clear_bit(NFS_DELEGATION_NEED_RECLAIM, | 181 | clear_bit(NFS_DELEGATION_NEED_RECLAIM, |
182 | &delegation->flags); | 182 | &delegation->flags); |
183 | NFS_I(inode)->delegation_state = delegation->type; | ||
184 | spin_unlock(&delegation->lock); | 183 | spin_unlock(&delegation->lock); |
185 | put_rpccred(oldcred); | 184 | put_rpccred(oldcred); |
186 | rcu_read_unlock(); | 185 | rcu_read_unlock(); |
@@ -275,7 +274,6 @@ nfs_detach_delegation_locked(struct nfs_inode *nfsi, | |||
275 | set_bit(NFS_DELEGATION_RETURNING, &delegation->flags); | 274 | set_bit(NFS_DELEGATION_RETURNING, &delegation->flags); |
276 | list_del_rcu(&delegation->super_list); | 275 | list_del_rcu(&delegation->super_list); |
277 | delegation->inode = NULL; | 276 | delegation->inode = NULL; |
278 | nfsi->delegation_state = 0; | ||
279 | rcu_assign_pointer(nfsi->delegation, NULL); | 277 | rcu_assign_pointer(nfsi->delegation, NULL); |
280 | spin_unlock(&delegation->lock); | 278 | spin_unlock(&delegation->lock); |
281 | return delegation; | 279 | return delegation; |
@@ -355,7 +353,6 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
355 | &delegation->stateid)) { | 353 | &delegation->stateid)) { |
356 | nfs_update_inplace_delegation(old_delegation, | 354 | nfs_update_inplace_delegation(old_delegation, |
357 | delegation); | 355 | delegation); |
358 | nfsi->delegation_state = old_delegation->type; | ||
359 | goto out; | 356 | goto out; |
360 | } | 357 | } |
361 | /* | 358 | /* |
@@ -379,7 +376,6 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
379 | goto out; | 376 | goto out; |
380 | } | 377 | } |
381 | list_add_rcu(&delegation->super_list, &server->delegations); | 378 | list_add_rcu(&delegation->super_list, &server->delegations); |
382 | nfsi->delegation_state = delegation->type; | ||
383 | rcu_assign_pointer(nfsi->delegation, delegation); | 379 | rcu_assign_pointer(nfsi->delegation, delegation); |
384 | delegation = NULL; | 380 | delegation = NULL; |
385 | 381 | ||
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 7077521acdf4..e907c8cf732e 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -283,7 +283,7 @@ static void nfs_direct_release_pages(struct page **pages, unsigned int npages) | |||
283 | void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, | 283 | void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, |
284 | struct nfs_direct_req *dreq) | 284 | struct nfs_direct_req *dreq) |
285 | { | 285 | { |
286 | cinfo->lock = &dreq->lock; | 286 | cinfo->lock = &dreq->inode->i_lock; |
287 | cinfo->mds = &dreq->mds_cinfo; | 287 | cinfo->mds = &dreq->mds_cinfo; |
288 | cinfo->ds = &dreq->ds_cinfo; | 288 | cinfo->ds = &dreq->ds_cinfo; |
289 | cinfo->dreq = dreq; | 289 | cinfo->dreq = dreq; |
diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c index 7ae1c263c5cf..91e88a7ecef0 100644 --- a/fs/nfs/filelayout/filelayout.c +++ b/fs/nfs/filelayout/filelayout.c | |||
@@ -960,52 +960,19 @@ filelayout_mark_request_commit(struct nfs_page *req, | |||
960 | { | 960 | { |
961 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); | 961 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); |
962 | u32 i, j; | 962 | u32 i, j; |
963 | struct list_head *list; | ||
964 | struct pnfs_commit_bucket *buckets; | ||
965 | 963 | ||
966 | if (fl->commit_through_mds) { | 964 | if (fl->commit_through_mds) { |
967 | list = &cinfo->mds->list; | 965 | nfs_request_add_commit_list(req, &cinfo->mds->list, cinfo); |
968 | spin_lock(cinfo->lock); | 966 | } else { |
969 | goto mds_commit; | 967 | /* Note that we are calling nfs4_fl_calc_j_index on each page |
970 | } | 968 | * that ends up being committed to a data server. An attractive |
971 | 969 | * alternative is to add a field to nfs_write_data and nfs_page | |
972 | /* Note that we are calling nfs4_fl_calc_j_index on each page | 970 | * to store the value calculated in filelayout_write_pagelist |
973 | * that ends up being committed to a data server. An attractive | 971 | * and just use that here. |
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 | ||
989 | */ | 972 | */ |
990 | buckets[i].wlseg = pnfs_get_lseg(lseg); | 973 | j = nfs4_fl_calc_j_index(lseg, req_offset(req)); |
991 | } | 974 | i = select_bucket_index(fl, j); |
992 | set_bit(PG_COMMIT_TO_DS, &req->wb_flags); | 975 | pnfs_layout_mark_request_commit(req, lseg, cinfo, i); |
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); | ||
1009 | } | 976 | } |
1010 | } | 977 | } |
1011 | 978 | ||
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index c22ecaa86c1c..315cc68945b9 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c | |||
@@ -1332,47 +1332,6 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync) | |||
1332 | return PNFS_ATTEMPTED; | 1332 | return PNFS_ATTEMPTED; |
1333 | } | 1333 | } |
1334 | 1334 | ||
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 | |||
1376 | static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) | 1335 | static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) |
1377 | { | 1336 | { |
1378 | return i; | 1337 | return i; |
@@ -1540,7 +1499,7 @@ static struct pnfs_layoutdriver_type flexfilelayout_type = { | |||
1540 | .pg_write_ops = &ff_layout_pg_write_ops, | 1499 | .pg_write_ops = &ff_layout_pg_write_ops, |
1541 | .get_ds_info = ff_layout_get_ds_info, | 1500 | .get_ds_info = ff_layout_get_ds_info, |
1542 | .free_deviceid_node = ff_layout_free_deveiceid_node, | 1501 | .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, |
1544 | .clear_request_commit = pnfs_generic_clear_request_commit, | 1503 | .clear_request_commit = pnfs_generic_clear_request_commit, |
1545 | .scan_commit_lists = pnfs_generic_scan_commit_lists, | 1504 | .scan_commit_lists = pnfs_generic_scan_commit_lists, |
1546 | .recover_commit_reqs = pnfs_generic_recover_commit_reqs, | 1505 | .recover_commit_reqs = pnfs_generic_recover_commit_reqs, |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index e4f0dcef8f54..83107be3dd01 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -1775,7 +1775,6 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi) | |||
1775 | #if IS_ENABLED(CONFIG_NFS_V4) | 1775 | #if IS_ENABLED(CONFIG_NFS_V4) |
1776 | INIT_LIST_HEAD(&nfsi->open_states); | 1776 | INIT_LIST_HEAD(&nfsi->open_states); |
1777 | nfsi->delegation = NULL; | 1777 | nfsi->delegation = NULL; |
1778 | nfsi->delegation_state = 0; | ||
1779 | init_rwsem(&nfsi->rwsem); | 1778 | init_rwsem(&nfsi->rwsem); |
1780 | nfsi->layout = NULL; | 1779 | nfsi->layout = NULL; |
1781 | #endif | 1780 | #endif |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 212b8c883d22..b802fb3a2d99 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -598,6 +598,19 @@ void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize) | |||
598 | } | 598 | } |
599 | 599 | ||
600 | /* | 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 | |||
613 | /* | ||
601 | * Determine the number of bytes of data the page contains | 614 | * Determine the number of bytes of data the page contains |
602 | */ | 615 | */ |
603 | static inline | 616 | static inline |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 2e7c9f7a6f7c..88180ac5ea0e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -6648,47 +6648,47 @@ nfs41_same_server_scope(struct nfs41_server_scope *a, | |||
6648 | int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred) | 6648 | int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred) |
6649 | { | 6649 | { |
6650 | int status; | 6650 | int status; |
6651 | struct nfs41_bind_conn_to_session_args args = { | ||
6652 | .client = clp, | ||
6653 | .dir = NFS4_CDFC4_FORE_OR_BOTH, | ||
6654 | }; | ||
6651 | struct nfs41_bind_conn_to_session_res res; | 6655 | struct nfs41_bind_conn_to_session_res res; |
6652 | struct rpc_message msg = { | 6656 | struct rpc_message msg = { |
6653 | .rpc_proc = | 6657 | .rpc_proc = |
6654 | &nfs4_procedures[NFSPROC4_CLNT_BIND_CONN_TO_SESSION], | 6658 | &nfs4_procedures[NFSPROC4_CLNT_BIND_CONN_TO_SESSION], |
6655 | .rpc_argp = clp, | 6659 | .rpc_argp = &args, |
6656 | .rpc_resp = &res, | 6660 | .rpc_resp = &res, |
6657 | .rpc_cred = cred, | 6661 | .rpc_cred = cred, |
6658 | }; | 6662 | }; |
6659 | 6663 | ||
6660 | dprintk("--> %s\n", __func__); | 6664 | dprintk("--> %s\n", __func__); |
6661 | 6665 | ||
6662 | res.session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS); | 6666 | nfs4_copy_sessionid(&args.sessionid, &clp->cl_session->sess_id); |
6663 | if (unlikely(res.session == NULL)) { | 6667 | if (!(clp->cl_session->flags & SESSION4_BACK_CHAN)) |
6664 | status = -ENOMEM; | 6668 | args.dir = NFS4_CDFC4_FORE; |
6665 | goto out; | ||
6666 | } | ||
6667 | 6669 | ||
6668 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); | 6670 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
6669 | trace_nfs4_bind_conn_to_session(clp, status); | 6671 | trace_nfs4_bind_conn_to_session(clp, status); |
6670 | if (status == 0) { | 6672 | if (status == 0) { |
6671 | if (memcmp(res.session->sess_id.data, | 6673 | if (memcmp(res.sessionid.data, |
6672 | clp->cl_session->sess_id.data, NFS4_MAX_SESSIONID_LEN)) { | 6674 | clp->cl_session->sess_id.data, NFS4_MAX_SESSIONID_LEN)) { |
6673 | dprintk("NFS: %s: Session ID mismatch\n", __func__); | 6675 | dprintk("NFS: %s: Session ID mismatch\n", __func__); |
6674 | status = -EIO; | 6676 | status = -EIO; |
6675 | goto out_session; | 6677 | goto out; |
6676 | } | 6678 | } |
6677 | if (res.dir != NFS4_CDFS4_BOTH) { | 6679 | if ((res.dir & args.dir) != res.dir || res.dir == 0) { |
6678 | dprintk("NFS: %s: Unexpected direction from server\n", | 6680 | dprintk("NFS: %s: Unexpected direction from server\n", |
6679 | __func__); | 6681 | __func__); |
6680 | status = -EIO; | 6682 | status = -EIO; |
6681 | goto out_session; | 6683 | goto out; |
6682 | } | 6684 | } |
6683 | if (res.use_conn_in_rdma_mode) { | 6685 | if (res.use_conn_in_rdma_mode != args.use_conn_in_rdma_mode) { |
6684 | dprintk("NFS: %s: Server returned RDMA mode = true\n", | 6686 | dprintk("NFS: %s: Server returned RDMA mode = true\n", |
6685 | __func__); | 6687 | __func__); |
6686 | status = -EIO; | 6688 | status = -EIO; |
6687 | goto out_session; | 6689 | goto out; |
6688 | } | 6690 | } |
6689 | } | 6691 | } |
6690 | out_session: | ||
6691 | kfree(res.session); | ||
6692 | out: | 6692 | out: |
6693 | dprintk("<-- %s status= %d\n", __func__, status); | 6693 | dprintk("<-- %s status= %d\n", __func__, status); |
6694 | return status; | 6694 | return status; |
@@ -7166,10 +7166,11 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | |||
7166 | args->bc_attrs.max_reqs); | 7166 | args->bc_attrs.max_reqs); |
7167 | } | 7167 | } |
7168 | 7168 | ||
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) | ||
7170 | { | 7171 | { |
7171 | struct nfs4_channel_attrs *sent = &args->fc_attrs; | 7172 | 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; |
7173 | 7174 | ||
7174 | if (rcvd->max_resp_sz > sent->max_resp_sz) | 7175 | if (rcvd->max_resp_sz > sent->max_resp_sz) |
7175 | return -EINVAL; | 7176 | return -EINVAL; |
@@ -7188,11 +7189,14 @@ static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args | |||
7188 | return 0; | 7189 | return 0; |
7189 | } | 7190 | } |
7190 | 7191 | ||
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) | ||
7192 | { | 7194 | { |
7193 | struct nfs4_channel_attrs *sent = &args->bc_attrs; | 7195 | 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; |
7195 | 7197 | ||
7198 | if (!(res->flags & SESSION4_BACK_CHAN)) | ||
7199 | goto out; | ||
7196 | if (rcvd->max_rqst_sz > sent->max_rqst_sz) | 7200 | if (rcvd->max_rqst_sz > sent->max_rqst_sz) |
7197 | return -EINVAL; | 7201 | return -EINVAL; |
7198 | if (rcvd->max_resp_sz < sent->max_resp_sz) | 7202 | 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 | |||
7204 | return -EINVAL; | 7208 | return -EINVAL; |
7205 | if (rcvd->max_reqs != sent->max_reqs) | 7209 | if (rcvd->max_reqs != sent->max_reqs) |
7206 | return -EINVAL; | 7210 | return -EINVAL; |
7211 | out: | ||
7207 | return 0; | 7212 | return 0; |
7208 | } | 7213 | } |
7209 | 7214 | ||
7210 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, | 7215 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, |
7211 | struct nfs4_session *session) | 7216 | struct nfs41_create_session_res *res) |
7212 | { | 7217 | { |
7213 | int ret; | 7218 | int ret; |
7214 | 7219 | ||
7215 | ret = nfs4_verify_fore_channel_attrs(args, session); | 7220 | ret = nfs4_verify_fore_channel_attrs(args, res); |
7216 | if (ret) | 7221 | if (ret) |
7217 | return ret; | 7222 | 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)); | ||
7219 | } | 7235 | } |
7220 | 7236 | ||
7221 | static int _nfs4_proc_create_session(struct nfs_client *clp, | 7237 | static int _nfs4_proc_create_session(struct nfs_client *clp, |
@@ -7224,11 +7240,12 @@ static int _nfs4_proc_create_session(struct nfs_client *clp, | |||
7224 | struct nfs4_session *session = clp->cl_session; | 7240 | struct nfs4_session *session = clp->cl_session; |
7225 | struct nfs41_create_session_args args = { | 7241 | struct nfs41_create_session_args args = { |
7226 | .client = clp, | 7242 | .client = clp, |
7243 | .clientid = clp->cl_clientid, | ||
7244 | .seqid = clp->cl_seqid, | ||
7227 | .cb_program = NFS4_CALLBACK, | 7245 | .cb_program = NFS4_CALLBACK, |
7228 | }; | 7246 | }; |
7229 | struct nfs41_create_session_res res = { | 7247 | struct nfs41_create_session_res res; |
7230 | .client = clp, | 7248 | |
7231 | }; | ||
7232 | struct rpc_message msg = { | 7249 | struct rpc_message msg = { |
7233 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION], | 7250 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION], |
7234 | .rpc_argp = &args, | 7251 | .rpc_argp = &args, |
@@ -7245,11 +7262,15 @@ static int _nfs4_proc_create_session(struct nfs_client *clp, | |||
7245 | 7262 | ||
7246 | if (!status) { | 7263 | if (!status) { |
7247 | /* Verify the session's negotiated channel_attrs values */ | 7264 | /* Verify the session's negotiated channel_attrs values */ |
7248 | status = nfs4_verify_channel_attrs(&args, session); | 7265 | status = nfs4_verify_channel_attrs(&args, &res); |
7249 | /* Increment the clientid slot sequence id */ | 7266 | /* 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); | ||
7251 | } | 7272 | } |
7252 | 7273 | out: | |
7253 | return status; | 7274 | return status; |
7254 | } | 7275 | } |
7255 | 7276 | ||
diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c index e799dc3c3b1d..e23366effcfb 100644 --- a/fs/nfs/nfs4session.c +++ b/fs/nfs/nfs4session.c | |||
@@ -450,7 +450,7 @@ int nfs4_setup_session_slot_tables(struct nfs4_session *ses) | |||
450 | tbl = &ses->fc_slot_table; | 450 | tbl = &ses->fc_slot_table; |
451 | tbl->session = ses; | 451 | tbl->session = ses; |
452 | status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1); | 452 | 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 */ |
454 | return status; | 454 | return status; |
455 | /* Back channel */ | 455 | /* Back channel */ |
456 | tbl = &ses->bc_slot_table; | 456 | tbl = &ses->bc_slot_table; |
diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h index b34ada9bc6a2..fc46c7455898 100644 --- a/fs/nfs/nfs4session.h +++ b/fs/nfs/nfs4session.h | |||
@@ -118,6 +118,12 @@ static inline int nfs4_has_persistent_session(const struct nfs_client *clp) | |||
118 | return 0; | 118 | return 0; |
119 | } | 119 | } |
120 | 120 | ||
121 | static inline void nfs4_copy_sessionid(struct nfs4_sessionid *dst, | ||
122 | const struct nfs4_sessionid *src) | ||
123 | { | ||
124 | memcpy(dst->data, src->data, NFS4_MAX_SESSIONID_LEN); | ||
125 | } | ||
126 | |||
121 | #ifdef CONFIG_CRC32 | 127 | #ifdef CONFIG_CRC32 |
122 | /* | 128 | /* |
123 | * nfs_session_id_hash - calculate the crc32 hash for the session id | 129 | * nfs_session_id_hash - calculate the crc32 hash for the session id |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index e23a0a664e12..5c399ec41079 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -1715,17 +1715,17 @@ static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, stru | |||
1715 | #if defined(CONFIG_NFS_V4_1) | 1715 | #if defined(CONFIG_NFS_V4_1) |
1716 | /* NFSv4.1 operations */ | 1716 | /* NFSv4.1 operations */ |
1717 | static void encode_bind_conn_to_session(struct xdr_stream *xdr, | 1717 | static void encode_bind_conn_to_session(struct xdr_stream *xdr, |
1718 | struct nfs4_session *session, | 1718 | struct nfs41_bind_conn_to_session_args *args, |
1719 | struct compound_hdr *hdr) | 1719 | struct compound_hdr *hdr) |
1720 | { | 1720 | { |
1721 | __be32 *p; | 1721 | __be32 *p; |
1722 | 1722 | ||
1723 | encode_op_hdr(xdr, OP_BIND_CONN_TO_SESSION, | 1723 | encode_op_hdr(xdr, OP_BIND_CONN_TO_SESSION, |
1724 | decode_bind_conn_to_session_maxsz, hdr); | 1724 | decode_bind_conn_to_session_maxsz, hdr); |
1725 | encode_opaque_fixed(xdr, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | 1725 | encode_opaque_fixed(xdr, args->sessionid.data, NFS4_MAX_SESSIONID_LEN); |
1726 | p = xdr_reserve_space(xdr, 8); | 1726 | p = xdr_reserve_space(xdr, 8); |
1727 | *p++ = cpu_to_be32(NFS4_CDFC4_BACK_OR_BOTH); | 1727 | *p++ = cpu_to_be32(args->dir); |
1728 | *p = 0; /* use_conn_in_rdma_mode = False */ | 1728 | *p = (args->use_conn_in_rdma_mode) ? cpu_to_be32(1) : cpu_to_be32(0); |
1729 | } | 1729 | } |
1730 | 1730 | ||
1731 | static void encode_op_map(struct xdr_stream *xdr, struct nfs4_op_map *op_map) | 1731 | static void encode_op_map(struct xdr_stream *xdr, struct nfs4_op_map *op_map) |
@@ -1806,8 +1806,8 @@ static void encode_create_session(struct xdr_stream *xdr, | |||
1806 | 1806 | ||
1807 | encode_op_hdr(xdr, OP_CREATE_SESSION, decode_create_session_maxsz, hdr); | 1807 | encode_op_hdr(xdr, OP_CREATE_SESSION, decode_create_session_maxsz, hdr); |
1808 | p = reserve_space(xdr, 16 + 2*28 + 20 + clnt->cl_nodelen + 12); | 1808 | p = reserve_space(xdr, 16 + 2*28 + 20 + clnt->cl_nodelen + 12); |
1809 | p = xdr_encode_hyper(p, clp->cl_clientid); | 1809 | p = xdr_encode_hyper(p, args->clientid); |
1810 | *p++ = cpu_to_be32(clp->cl_seqid); /*Sequence id */ | 1810 | *p++ = cpu_to_be32(args->seqid); /*Sequence id */ |
1811 | *p++ = cpu_to_be32(args->flags); /*flags */ | 1811 | *p++ = cpu_to_be32(args->flags); /*flags */ |
1812 | 1812 | ||
1813 | /* Fore Channel */ | 1813 | /* Fore Channel */ |
@@ -2734,14 +2734,14 @@ static void nfs4_xdr_enc_fsid_present(struct rpc_rqst *req, | |||
2734 | */ | 2734 | */ |
2735 | static void nfs4_xdr_enc_bind_conn_to_session(struct rpc_rqst *req, | 2735 | static void nfs4_xdr_enc_bind_conn_to_session(struct rpc_rqst *req, |
2736 | struct xdr_stream *xdr, | 2736 | struct xdr_stream *xdr, |
2737 | struct nfs_client *clp) | 2737 | struct nfs41_bind_conn_to_session_args *args) |
2738 | { | 2738 | { |
2739 | struct compound_hdr hdr = { | 2739 | struct compound_hdr hdr = { |
2740 | .minorversion = clp->cl_mvops->minor_version, | 2740 | .minorversion = args->client->cl_mvops->minor_version, |
2741 | }; | 2741 | }; |
2742 | 2742 | ||
2743 | encode_compound_hdr(xdr, req, &hdr); | 2743 | encode_compound_hdr(xdr, req, &hdr); |
2744 | encode_bind_conn_to_session(xdr, clp->cl_session, &hdr); | 2744 | encode_bind_conn_to_session(xdr, args, &hdr); |
2745 | encode_nops(&hdr); | 2745 | encode_nops(&hdr); |
2746 | } | 2746 | } |
2747 | 2747 | ||
@@ -5613,7 +5613,7 @@ static int decode_bind_conn_to_session(struct xdr_stream *xdr, | |||
5613 | 5613 | ||
5614 | status = decode_op_hdr(xdr, OP_BIND_CONN_TO_SESSION); | 5614 | status = decode_op_hdr(xdr, OP_BIND_CONN_TO_SESSION); |
5615 | if (!status) | 5615 | if (!status) |
5616 | status = decode_sessionid(xdr, &res->session->sess_id); | 5616 | status = decode_sessionid(xdr, &res->sessionid); |
5617 | if (unlikely(status)) | 5617 | if (unlikely(status)) |
5618 | return status; | 5618 | return status; |
5619 | 5619 | ||
@@ -5641,12 +5641,10 @@ static int decode_create_session(struct xdr_stream *xdr, | |||
5641 | { | 5641 | { |
5642 | __be32 *p; | 5642 | __be32 *p; |
5643 | int status; | 5643 | int status; |
5644 | struct nfs_client *clp = res->client; | ||
5645 | struct nfs4_session *session = clp->cl_session; | ||
5646 | 5644 | ||
5647 | status = decode_op_hdr(xdr, OP_CREATE_SESSION); | 5645 | status = decode_op_hdr(xdr, OP_CREATE_SESSION); |
5648 | if (!status) | 5646 | if (!status) |
5649 | status = decode_sessionid(xdr, &session->sess_id); | 5647 | status = decode_sessionid(xdr, &res->sessionid); |
5650 | if (unlikely(status)) | 5648 | if (unlikely(status)) |
5651 | return status; | 5649 | return status; |
5652 | 5650 | ||
@@ -5654,13 +5652,13 @@ static int decode_create_session(struct xdr_stream *xdr, | |||
5654 | p = xdr_inline_decode(xdr, 8); | 5652 | p = xdr_inline_decode(xdr, 8); |
5655 | if (unlikely(!p)) | 5653 | if (unlikely(!p)) |
5656 | goto out_overflow; | 5654 | goto out_overflow; |
5657 | clp->cl_seqid = be32_to_cpup(p++); | 5655 | res->seqid = be32_to_cpup(p++); |
5658 | session->flags = be32_to_cpup(p); | 5656 | res->flags = be32_to_cpup(p); |
5659 | 5657 | ||
5660 | /* Channel attributes */ | 5658 | /* Channel attributes */ |
5661 | status = decode_chan_attrs(xdr, &session->fc_attrs); | 5659 | status = decode_chan_attrs(xdr, &res->fc_attrs); |
5662 | if (!status) | 5660 | if (!status) |
5663 | status = decode_chan_attrs(xdr, &session->bc_attrs); | 5661 | status = decode_chan_attrs(xdr, &res->bc_attrs); |
5664 | return status; | 5662 | return status; |
5665 | out_overflow: | 5663 | out_overflow: |
5666 | print_overflow_msg(__func__, xdr); | 5664 | print_overflow_msg(__func__, xdr); |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 797cd6253adf..635f0865671c 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -344,6 +344,10 @@ void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, | |||
344 | struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net, | 344 | struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net, |
345 | struct xdr_stream *xdr, | 345 | struct xdr_stream *xdr, |
346 | gfp_t gfp_flags); | 346 | gfp_t gfp_flags); |
347 | void pnfs_layout_mark_request_commit(struct nfs_page *req, | ||
348 | struct pnfs_layout_segment *lseg, | ||
349 | struct nfs_commit_info *cinfo, | ||
350 | u32 ds_commit_idx); | ||
347 | 351 | ||
348 | static inline bool nfs_have_layout(struct inode *inode) | 352 | static inline bool nfs_have_layout(struct inode *inode) |
349 | { | 353 | { |
diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c index fdc4f6562bb7..54e36b38fb5f 100644 --- a/fs/nfs/pnfs_nfs.c +++ b/fs/nfs/pnfs_nfs.c | |||
@@ -838,3 +838,33 @@ out_err: | |||
838 | return NULL; | 838 | return NULL; |
839 | } | 839 | } |
840 | EXPORT_SYMBOL_GPL(nfs4_decode_mp_ds_addr); | 840 | EXPORT_SYMBOL_GPL(nfs4_decode_mp_ds_addr); |
841 | |||
842 | void | ||
843 | pnfs_layout_mark_request_commit(struct nfs_page *req, | ||
844 | struct pnfs_layout_segment *lseg, | ||
845 | struct nfs_commit_info *cinfo, | ||
846 | u32 ds_commit_idx) | ||
847 | { | ||
848 | struct list_head *list; | ||
849 | struct pnfs_commit_bucket *buckets; | ||
850 | |||
851 | spin_lock(cinfo->lock); | ||
852 | buckets = cinfo->ds->buckets; | ||
853 | list = &buckets[ds_commit_idx].written; | ||
854 | if (list_empty(list)) { | ||
855 | /* Non-empty buckets hold a reference on the lseg. That ref | ||
856 | * is normally transferred to the COMMIT call and released | ||
857 | * there. It could also be released if the last req is pulled | ||
858 | * off due to a rewrite, in which case it will be done in | ||
859 | * pnfs_common_clear_request_commit | ||
860 | */ | ||
861 | WARN_ON_ONCE(buckets[ds_commit_idx].wlseg != NULL); | ||
862 | buckets[ds_commit_idx].wlseg = pnfs_get_lseg(lseg); | ||
863 | } | ||
864 | set_bit(PG_COMMIT_TO_DS, &req->wb_flags); | ||
865 | cinfo->ds->nwritten++; | ||
866 | spin_unlock(cinfo->lock); | ||
867 | |||
868 | nfs_request_add_commit_list(req, list, cinfo); | ||
869 | } | ||
870 | EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit); | ||
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 88a6d2196ece..595d81e354d1 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -789,13 +789,8 @@ nfs_request_add_commit_list(struct nfs_page *req, struct list_head *dst, | |||
789 | nfs_list_add_request(req, dst); | 789 | nfs_list_add_request(req, dst); |
790 | cinfo->mds->ncommit++; | 790 | cinfo->mds->ncommit++; |
791 | spin_unlock(cinfo->lock); | 791 | spin_unlock(cinfo->lock); |
792 | if (!cinfo->dreq) { | 792 | if (!cinfo->dreq) |
793 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 793 | nfs_mark_page_unstable(req->wb_page); |
794 | inc_bdi_stat(inode_to_bdi(page_file_mapping(req->wb_page)->host), | ||
795 | BDI_RECLAIMABLE); | ||
796 | __mark_inode_dirty(req->wb_context->dentry->d_inode, | ||
797 | I_DIRTY_DATASYNC); | ||
798 | } | ||
799 | } | 794 | } |
800 | EXPORT_SYMBOL_GPL(nfs_request_add_commit_list); | 795 | EXPORT_SYMBOL_GPL(nfs_request_add_commit_list); |
801 | 796 | ||
@@ -1605,11 +1600,8 @@ void nfs_retry_commit(struct list_head *page_list, | |||
1605 | req = nfs_list_entry(page_list->next); | 1600 | req = nfs_list_entry(page_list->next); |
1606 | nfs_list_remove_request(req); | 1601 | nfs_list_remove_request(req); |
1607 | nfs_mark_request_commit(req, lseg, cinfo, ds_commit_idx); | 1602 | nfs_mark_request_commit(req, lseg, cinfo, ds_commit_idx); |
1608 | if (!cinfo->dreq) { | 1603 | if (!cinfo->dreq) |
1609 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 1604 | nfs_clear_page_commit(req->wb_page); |
1610 | dec_bdi_stat(inode_to_bdi(page_file_mapping(req->wb_page)->host), | ||
1611 | BDI_RECLAIMABLE); | ||
1612 | } | ||
1613 | nfs_unlock_and_release_request(req); | 1605 | nfs_unlock_and_release_request(req); |
1614 | } | 1606 | } |
1615 | } | 1607 | } |