diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-23 19:03:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-23 19:03:58 -0400 |
commit | 53a01c9a5fcf74b7f855e70dd69742fb3cb84c83 (patch) | |
tree | 1de69b563fc0e5e7b852acfc33abda61fc7671ed | |
parent | 9157141c95bc3ffcdae93fde5d5aafee7ce6e39a (diff) | |
parent | 0af4c8be97a14d1df8a78b4993a09e8dff545a18 (diff) |
Merge tag 'nfs-for-4.19-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client updates from Anna Schumaker:
"These patches include adding async support for the v4.2 COPY
operation. I think Bruce is planning to send the server patches for
the next release, but I figured we could get the client side out of
the way now since it's been in my tree for a while. This shouldn't
cause any problems, since the server will still respond with
synchronous copies even if the client requests async.
Features:
- Add support for asynchronous server-side COPY operations
Stable bufixes:
- Fix an off-by-one in bl_map_stripe() (v3.17+)
- NFSv4 client live hangs after live data migration recovery (v4.9+)
- xprtrdma: Fix disconnect regression (v4.18+)
- Fix locking in pnfs_generic_recover_commit_reqs (v4.14+)
- Fix a sleep in atomic context in nfs4_callback_sequence() (v4.9+)
Other bugfixes and cleanups:
- Optimizations and fixes involving NFS v4.1 / pNFS layout handling
- Optimize lseek(fd, SEEK_CUR, 0) on directories to avoid locking
- Immediately reschedule writeback when the server replies with an
error
- Fix excessive attribute revalidation in nfs_execute_ok()
- Add error checking to nfs_idmap_prepare_message()
- Use new vm_fault_t return type
- Return a delegation when reclaiming one that the server has
recalled
- Referrals should inherit proto setting from parents
- Make rpc_auth_create_args a const
- Improvements to rpc_iostats tracking
- Fix a potential reference leak when there is an error processing a
callback
- Fix rmdir / mkdir / rename nlink accounting
- Fix updating inode change attribute
- Fix error handling in nfsn4_sp4_select_mode()
- Use an appropriate work queue for direct-write completion
- Don't busy wait if NFSv4 session draining is interrupted"
* tag 'nfs-for-4.19-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (54 commits)
pNFS: Remove unwanted optimisation of layoutget
pNFS/flexfiles: ff_layout_pg_init_read should exit on error
pNFS: Treat RECALLCONFLICT like DELAY...
pNFS: When updating the stateid in layoutreturn, also update the recall range
NFSv4: Fix a sleep in atomic context in nfs4_callback_sequence()
NFSv4: Fix locking in pnfs_generic_recover_commit_reqs
NFSv4: Fix a typo in nfs4_init_channel_attrs()
NFSv4: Don't busy wait if NFSv4 session draining is interrupted
NFS recover from destination server reboot for copies
NFS add a simple sync nfs4_proc_commit after async COPY
NFS handle COPY ERR_OFFLOAD_NO_REQS
NFS send OFFLOAD_CANCEL when COPY killed
NFS export nfs4_async_handle_error
NFS handle COPY reply CB_OFFLOAD call race
NFS add support for asynchronous COPY
NFS COPY xdr handle async reply
NFS OFFLOAD_CANCEL xdr
NFS CB_OFFLOAD xdr
NFS: Use an appropriate work queue for direct-write completion
NFSv4: Fix error handling in nfs4_sp4_select_mode()
...
52 files changed, 924 insertions, 216 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 7cb5c38c19e4..06cb0c1d9aee 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
@@ -753,6 +753,7 @@ out: | |||
753 | case -ENODEV: | 753 | case -ENODEV: |
754 | /* Our extent block devices are unavailable */ | 754 | /* Our extent block devices are unavailable */ |
755 | set_bit(NFS_LSEG_UNAVAILABLE, &lseg->pls_flags); | 755 | set_bit(NFS_LSEG_UNAVAILABLE, &lseg->pls_flags); |
756 | /* Fall through */ | ||
756 | case 0: | 757 | case 0: |
757 | return lseg; | 758 | return lseg; |
758 | default: | 759 | default: |
diff --git a/fs/nfs/blocklayout/dev.c b/fs/nfs/blocklayout/dev.c index a7efd83779d2..dec5880ac6de 100644 --- a/fs/nfs/blocklayout/dev.c +++ b/fs/nfs/blocklayout/dev.c | |||
@@ -204,7 +204,7 @@ static bool bl_map_stripe(struct pnfs_block_dev *dev, u64 offset, | |||
204 | chunk = div_u64(offset, dev->chunk_size); | 204 | chunk = div_u64(offset, dev->chunk_size); |
205 | div_u64_rem(chunk, dev->nr_children, &chunk_idx); | 205 | div_u64_rem(chunk, dev->nr_children, &chunk_idx); |
206 | 206 | ||
207 | if (chunk_idx > dev->nr_children) { | 207 | if (chunk_idx >= dev->nr_children) { |
208 | dprintk("%s: invalid chunk idx %d (%lld/%lld)\n", | 208 | dprintk("%s: invalid chunk idx %d (%lld/%lld)\n", |
209 | __func__, chunk_idx, offset, dev->chunk_size); | 209 | __func__, chunk_idx, offset, dev->chunk_size); |
210 | /* error, should not happen */ | 210 | /* error, should not happen */ |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index a20a0bce40a4..8f34daf85f70 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -184,6 +184,18 @@ struct cb_notify_lock_args { | |||
184 | extern __be32 nfs4_callback_notify_lock(void *argp, void *resp, | 184 | extern __be32 nfs4_callback_notify_lock(void *argp, void *resp, |
185 | struct cb_process_state *cps); | 185 | struct cb_process_state *cps); |
186 | #endif /* CONFIG_NFS_V4_1 */ | 186 | #endif /* CONFIG_NFS_V4_1 */ |
187 | #ifdef CONFIG_NFS_V4_2 | ||
188 | struct cb_offloadargs { | ||
189 | struct nfs_fh coa_fh; | ||
190 | nfs4_stateid coa_stateid; | ||
191 | uint32_t error; | ||
192 | uint64_t wr_count; | ||
193 | struct nfs_writeverf wr_writeverf; | ||
194 | }; | ||
195 | |||
196 | extern __be32 nfs4_callback_offload(void *args, void *dummy, | ||
197 | struct cb_process_state *cps); | ||
198 | #endif /* CONFIG_NFS_V4_2 */ | ||
187 | extern int check_gss_callback_principal(struct nfs_client *, struct svc_rqst *); | 199 | extern int check_gss_callback_principal(struct nfs_client *, struct svc_rqst *); |
188 | extern __be32 nfs4_callback_getattr(void *argp, void *resp, | 200 | extern __be32 nfs4_callback_getattr(void *argp, void *resp, |
189 | struct cb_process_state *cps); | 201 | struct cb_process_state *cps); |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 64c214fb9da6..fa515d5ea5ba 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -215,9 +215,9 @@ static u32 pnfs_check_callback_stateid(struct pnfs_layout_hdr *lo, | |||
215 | { | 215 | { |
216 | u32 oldseq, newseq; | 216 | u32 oldseq, newseq; |
217 | 217 | ||
218 | /* Is the stateid still not initialised? */ | 218 | /* Is the stateid not initialised? */ |
219 | if (!pnfs_layout_is_valid(lo)) | 219 | if (!pnfs_layout_is_valid(lo)) |
220 | return NFS4ERR_DELAY; | 220 | return NFS4ERR_NOMATCHING_LAYOUT; |
221 | 221 | ||
222 | /* Mismatched stateid? */ | 222 | /* Mismatched stateid? */ |
223 | if (!nfs4_stateid_match_other(&lo->plh_stateid, new)) | 223 | if (!nfs4_stateid_match_other(&lo->plh_stateid, new)) |
@@ -273,7 +273,6 @@ static u32 initiate_file_draining(struct nfs_client *clp, | |||
273 | rv = pnfs_check_callback_stateid(lo, &args->cbl_stateid); | 273 | rv = pnfs_check_callback_stateid(lo, &args->cbl_stateid); |
274 | if (rv != NFS_OK) | 274 | if (rv != NFS_OK) |
275 | goto unlock; | 275 | goto unlock; |
276 | pnfs_set_layout_stateid(lo, &args->cbl_stateid, true); | ||
277 | 276 | ||
278 | /* | 277 | /* |
279 | * Enforce RFC5661 Section 12.5.5.2.1.5 (Bulk Recall and Return) | 278 | * Enforce RFC5661 Section 12.5.5.2.1.5 (Bulk Recall and Return) |
@@ -283,19 +282,23 @@ static u32 initiate_file_draining(struct nfs_client *clp, | |||
283 | goto unlock; | 282 | goto unlock; |
284 | } | 283 | } |
285 | 284 | ||
286 | if (pnfs_mark_matching_lsegs_return(lo, &free_me_list, | 285 | pnfs_set_layout_stateid(lo, &args->cbl_stateid, true); |
286 | switch (pnfs_mark_matching_lsegs_return(lo, &free_me_list, | ||
287 | &args->cbl_range, | 287 | &args->cbl_range, |
288 | be32_to_cpu(args->cbl_stateid.seqid))) { | 288 | be32_to_cpu(args->cbl_stateid.seqid))) { |
289 | case 0: | ||
290 | case -EBUSY: | ||
291 | /* There are layout segments that need to be returned */ | ||
289 | rv = NFS4_OK; | 292 | rv = NFS4_OK; |
290 | goto unlock; | 293 | break; |
291 | } | 294 | case -ENOENT: |
292 | 295 | /* Embrace your forgetfulness! */ | |
293 | /* Embrace your forgetfulness! */ | 296 | rv = NFS4ERR_NOMATCHING_LAYOUT; |
294 | rv = NFS4ERR_NOMATCHING_LAYOUT; | ||
295 | 297 | ||
296 | if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) { | 298 | if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) { |
297 | NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo, | 299 | NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo, |
298 | &args->cbl_range); | 300 | &args->cbl_range); |
301 | } | ||
299 | } | 302 | } |
300 | unlock: | 303 | unlock: |
301 | spin_unlock(&ino->i_lock); | 304 | spin_unlock(&ino->i_lock); |
@@ -328,8 +331,6 @@ static u32 initiate_bulk_draining(struct nfs_client *clp, | |||
328 | static u32 do_callback_layoutrecall(struct nfs_client *clp, | 331 | static u32 do_callback_layoutrecall(struct nfs_client *clp, |
329 | struct cb_layoutrecallargs *args) | 332 | struct cb_layoutrecallargs *args) |
330 | { | 333 | { |
331 | write_seqcount_begin(&clp->cl_callback_count); | ||
332 | write_seqcount_end(&clp->cl_callback_count); | ||
333 | if (args->cbl_recall_type == RETURN_FILE) | 334 | if (args->cbl_recall_type == RETURN_FILE) |
334 | return initiate_file_draining(clp, args); | 335 | return initiate_file_draining(clp, args); |
335 | return initiate_bulk_draining(clp, args); | 336 | return initiate_bulk_draining(clp, args); |
@@ -441,11 +442,14 @@ validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot, | |||
441 | * a match. If the slot is in use and the sequence numbers match, the | 442 | * a match. If the slot is in use and the sequence numbers match, the |
442 | * client is still waiting for a response to the original request. | 443 | * client is still waiting for a response to the original request. |
443 | */ | 444 | */ |
444 | static bool referring_call_exists(struct nfs_client *clp, | 445 | static int referring_call_exists(struct nfs_client *clp, |
445 | uint32_t nrclists, | 446 | uint32_t nrclists, |
446 | struct referring_call_list *rclists) | 447 | struct referring_call_list *rclists, |
448 | spinlock_t *lock) | ||
449 | __releases(lock) | ||
450 | __acquires(lock) | ||
447 | { | 451 | { |
448 | bool status = false; | 452 | int status = 0; |
449 | int i, j; | 453 | int i, j; |
450 | struct nfs4_session *session; | 454 | struct nfs4_session *session; |
451 | struct nfs4_slot_table *tbl; | 455 | struct nfs4_slot_table *tbl; |
@@ -468,8 +472,10 @@ static bool referring_call_exists(struct nfs_client *clp, | |||
468 | 472 | ||
469 | for (j = 0; j < rclist->rcl_nrefcalls; j++) { | 473 | for (j = 0; j < rclist->rcl_nrefcalls; j++) { |
470 | ref = &rclist->rcl_refcalls[j]; | 474 | ref = &rclist->rcl_refcalls[j]; |
475 | spin_unlock(lock); | ||
471 | status = nfs4_slot_wait_on_seqid(tbl, ref->rc_slotid, | 476 | status = nfs4_slot_wait_on_seqid(tbl, ref->rc_slotid, |
472 | ref->rc_sequenceid, HZ >> 1) < 0; | 477 | ref->rc_sequenceid, HZ >> 1) < 0; |
478 | spin_lock(lock); | ||
473 | if (status) | 479 | if (status) |
474 | goto out; | 480 | goto out; |
475 | } | 481 | } |
@@ -546,7 +552,8 @@ __be32 nfs4_callback_sequence(void *argp, void *resp, | |||
546 | * related callback was received before the response to the original | 552 | * related callback was received before the response to the original |
547 | * call. | 553 | * call. |
548 | */ | 554 | */ |
549 | if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) { | 555 | if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists, |
556 | &tbl->slot_tbl_lock) < 0) { | ||
550 | status = htonl(NFS4ERR_DELAY); | 557 | status = htonl(NFS4ERR_DELAY); |
551 | goto out_unlock; | 558 | goto out_unlock; |
552 | } | 559 | } |
@@ -660,3 +667,57 @@ __be32 nfs4_callback_notify_lock(void *argp, void *resp, | |||
660 | return htonl(NFS4_OK); | 667 | return htonl(NFS4_OK); |
661 | } | 668 | } |
662 | #endif /* CONFIG_NFS_V4_1 */ | 669 | #endif /* CONFIG_NFS_V4_1 */ |
670 | #ifdef CONFIG_NFS_V4_2 | ||
671 | static void nfs4_copy_cb_args(struct nfs4_copy_state *cp_state, | ||
672 | struct cb_offloadargs *args) | ||
673 | { | ||
674 | cp_state->count = args->wr_count; | ||
675 | cp_state->error = args->error; | ||
676 | if (!args->error) { | ||
677 | cp_state->verf.committed = args->wr_writeverf.committed; | ||
678 | memcpy(&cp_state->verf.verifier.data[0], | ||
679 | &args->wr_writeverf.verifier.data[0], | ||
680 | NFS4_VERIFIER_SIZE); | ||
681 | } | ||
682 | } | ||
683 | |||
684 | __be32 nfs4_callback_offload(void *data, void *dummy, | ||
685 | struct cb_process_state *cps) | ||
686 | { | ||
687 | struct cb_offloadargs *args = data; | ||
688 | struct nfs_server *server; | ||
689 | struct nfs4_copy_state *copy; | ||
690 | bool found = false; | ||
691 | |||
692 | spin_lock(&cps->clp->cl_lock); | ||
693 | rcu_read_lock(); | ||
694 | list_for_each_entry_rcu(server, &cps->clp->cl_superblocks, | ||
695 | client_link) { | ||
696 | list_for_each_entry(copy, &server->ss_copies, copies) { | ||
697 | if (memcmp(args->coa_stateid.other, | ||
698 | copy->stateid.other, | ||
699 | sizeof(args->coa_stateid.other))) | ||
700 | continue; | ||
701 | nfs4_copy_cb_args(copy, args); | ||
702 | complete(©->completion); | ||
703 | found = true; | ||
704 | goto out; | ||
705 | } | ||
706 | } | ||
707 | out: | ||
708 | rcu_read_unlock(); | ||
709 | if (!found) { | ||
710 | copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS); | ||
711 | if (!copy) { | ||
712 | spin_unlock(&cps->clp->cl_lock); | ||
713 | return htonl(NFS4ERR_SERVERFAULT); | ||
714 | } | ||
715 | memcpy(©->stateid, &args->coa_stateid, NFS4_STATEID_SIZE); | ||
716 | nfs4_copy_cb_args(copy, args); | ||
717 | list_add_tail(©->copies, &cps->clp->pending_cb_stateids); | ||
718 | } | ||
719 | spin_unlock(&cps->clp->cl_lock); | ||
720 | |||
721 | return 0; | ||
722 | } | ||
723 | #endif /* CONFIG_NFS_V4_2 */ | ||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index a813979b5be0..a87a56273407 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -38,6 +38,9 @@ | |||
38 | #define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 38 | #define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
39 | #define CB_OP_NOTIFY_LOCK_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 39 | #define CB_OP_NOTIFY_LOCK_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
40 | #endif /* CONFIG_NFS_V4_1 */ | 40 | #endif /* CONFIG_NFS_V4_1 */ |
41 | #ifdef CONFIG_NFS_V4_2 | ||
42 | #define CB_OP_OFFLOAD_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | ||
43 | #endif /* CONFIG_NFS_V4_2 */ | ||
41 | 44 | ||
42 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 45 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
43 | 46 | ||
@@ -527,7 +530,72 @@ static __be32 decode_notify_lock_args(struct svc_rqst *rqstp, | |||
527 | } | 530 | } |
528 | 531 | ||
529 | #endif /* CONFIG_NFS_V4_1 */ | 532 | #endif /* CONFIG_NFS_V4_1 */ |
533 | #ifdef CONFIG_NFS_V4_2 | ||
534 | static __be32 decode_write_response(struct xdr_stream *xdr, | ||
535 | struct cb_offloadargs *args) | ||
536 | { | ||
537 | __be32 *p; | ||
538 | |||
539 | /* skip the always zero field */ | ||
540 | p = read_buf(xdr, 4); | ||
541 | if (unlikely(!p)) | ||
542 | goto out; | ||
543 | p++; | ||
544 | |||
545 | /* decode count, stable_how, verifier */ | ||
546 | p = xdr_inline_decode(xdr, 8 + 4); | ||
547 | if (unlikely(!p)) | ||
548 | goto out; | ||
549 | p = xdr_decode_hyper(p, &args->wr_count); | ||
550 | args->wr_writeverf.committed = be32_to_cpup(p); | ||
551 | p = xdr_inline_decode(xdr, NFS4_VERIFIER_SIZE); | ||
552 | if (likely(p)) { | ||
553 | memcpy(&args->wr_writeverf.verifier.data[0], p, | ||
554 | NFS4_VERIFIER_SIZE); | ||
555 | return 0; | ||
556 | } | ||
557 | out: | ||
558 | return htonl(NFS4ERR_RESOURCE); | ||
559 | } | ||
560 | |||
561 | static __be32 decode_offload_args(struct svc_rqst *rqstp, | ||
562 | struct xdr_stream *xdr, | ||
563 | void *data) | ||
564 | { | ||
565 | struct cb_offloadargs *args = data; | ||
566 | __be32 *p; | ||
567 | __be32 status; | ||
568 | |||
569 | /* decode fh */ | ||
570 | status = decode_fh(xdr, &args->coa_fh); | ||
571 | if (unlikely(status != 0)) | ||
572 | return status; | ||
530 | 573 | ||
574 | /* decode stateid */ | ||
575 | status = decode_stateid(xdr, &args->coa_stateid); | ||
576 | if (unlikely(status != 0)) | ||
577 | return status; | ||
578 | |||
579 | /* decode status */ | ||
580 | p = read_buf(xdr, 4); | ||
581 | if (unlikely(!p)) | ||
582 | goto out; | ||
583 | args->error = ntohl(*p++); | ||
584 | if (!args->error) { | ||
585 | status = decode_write_response(xdr, args); | ||
586 | if (unlikely(status != 0)) | ||
587 | return status; | ||
588 | } else { | ||
589 | p = xdr_inline_decode(xdr, 8); | ||
590 | if (unlikely(!p)) | ||
591 | goto out; | ||
592 | p = xdr_decode_hyper(p, &args->wr_count); | ||
593 | } | ||
594 | return 0; | ||
595 | out: | ||
596 | return htonl(NFS4ERR_RESOURCE); | ||
597 | } | ||
598 | #endif /* CONFIG_NFS_V4_2 */ | ||
531 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) | 599 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) |
532 | { | 600 | { |
533 | if (unlikely(xdr_stream_encode_opaque(xdr, str, len) < 0)) | 601 | if (unlikely(xdr_stream_encode_opaque(xdr, str, len) < 0)) |
@@ -773,7 +841,10 @@ preprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op) | |||
773 | if (status != htonl(NFS4ERR_OP_ILLEGAL)) | 841 | if (status != htonl(NFS4ERR_OP_ILLEGAL)) |
774 | return status; | 842 | return status; |
775 | 843 | ||
776 | if (op_nr == OP_CB_OFFLOAD) | 844 | if (op_nr == OP_CB_OFFLOAD) { |
845 | *op = &callback_ops[op_nr]; | ||
846 | return htonl(NFS_OK); | ||
847 | } else | ||
777 | return htonl(NFS4ERR_NOTSUPP); | 848 | return htonl(NFS4ERR_NOTSUPP); |
778 | return htonl(NFS4ERR_OP_ILLEGAL); | 849 | return htonl(NFS4ERR_OP_ILLEGAL); |
779 | } | 850 | } |
@@ -883,16 +954,21 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp) | |||
883 | 954 | ||
884 | if (hdr_arg.minorversion == 0) { | 955 | if (hdr_arg.minorversion == 0) { |
885 | cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident); | 956 | cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident); |
886 | if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) | 957 | if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) { |
958 | if (cps.clp) | ||
959 | nfs_put_client(cps.clp); | ||
887 | goto out_invalidcred; | 960 | goto out_invalidcred; |
961 | } | ||
888 | } | 962 | } |
889 | 963 | ||
890 | cps.minorversion = hdr_arg.minorversion; | 964 | cps.minorversion = hdr_arg.minorversion; |
891 | hdr_res.taglen = hdr_arg.taglen; | 965 | hdr_res.taglen = hdr_arg.taglen; |
892 | hdr_res.tag = hdr_arg.tag; | 966 | hdr_res.tag = hdr_arg.tag; |
893 | if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) | 967 | if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) { |
968 | if (cps.clp) | ||
969 | nfs_put_client(cps.clp); | ||
894 | return rpc_system_err; | 970 | return rpc_system_err; |
895 | 971 | } | |
896 | while (status == 0 && nops != hdr_arg.nops) { | 972 | while (status == 0 && nops != hdr_arg.nops) { |
897 | status = process_op(nops, rqstp, &xdr_in, | 973 | status = process_op(nops, rqstp, &xdr_in, |
898 | rqstp->rq_argp, &xdr_out, rqstp->rq_resp, | 974 | rqstp->rq_argp, &xdr_out, rqstp->rq_resp, |
@@ -969,6 +1045,13 @@ static struct callback_op callback_ops[] = { | |||
969 | .res_maxsize = CB_OP_NOTIFY_LOCK_RES_MAXSZ, | 1045 | .res_maxsize = CB_OP_NOTIFY_LOCK_RES_MAXSZ, |
970 | }, | 1046 | }, |
971 | #endif /* CONFIG_NFS_V4_1 */ | 1047 | #endif /* CONFIG_NFS_V4_1 */ |
1048 | #ifdef CONFIG_NFS_V4_2 | ||
1049 | [OP_CB_OFFLOAD] = { | ||
1050 | .process_op = nfs4_callback_offload, | ||
1051 | .decode_args = decode_offload_args, | ||
1052 | .res_maxsize = CB_OP_OFFLOAD_RES_MAXSZ, | ||
1053 | }, | ||
1054 | #endif /* CONFIG_NFS_V4_2 */ | ||
972 | }; | 1055 | }; |
973 | 1056 | ||
974 | /* | 1057 | /* |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 377a61654a88..96d5f8135eb9 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -886,6 +886,7 @@ struct nfs_server *nfs_alloc_server(void) | |||
886 | INIT_LIST_HEAD(&server->delegations); | 886 | INIT_LIST_HEAD(&server->delegations); |
887 | INIT_LIST_HEAD(&server->layouts); | 887 | INIT_LIST_HEAD(&server->layouts); |
888 | INIT_LIST_HEAD(&server->state_owners_lru); | 888 | INIT_LIST_HEAD(&server->state_owners_lru); |
889 | INIT_LIST_HEAD(&server->ss_copies); | ||
889 | 890 | ||
890 | atomic_set(&server->active, 0); | 891 | atomic_set(&server->active, 0); |
891 | 892 | ||
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d7f158c3efc8..8bfaa658b2c1 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -904,23 +904,29 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence) | |||
904 | dfprintk(FILE, "NFS: llseek dir(%pD2, %lld, %d)\n", | 904 | dfprintk(FILE, "NFS: llseek dir(%pD2, %lld, %d)\n", |
905 | filp, offset, whence); | 905 | filp, offset, whence); |
906 | 906 | ||
907 | inode_lock(inode); | ||
908 | switch (whence) { | 907 | switch (whence) { |
909 | case 1: | 908 | default: |
910 | offset += filp->f_pos; | 909 | return -EINVAL; |
911 | case 0: | 910 | case SEEK_SET: |
912 | if (offset >= 0) | 911 | if (offset < 0) |
913 | break; | 912 | return -EINVAL; |
914 | default: | 913 | inode_lock(inode); |
915 | offset = -EINVAL; | 914 | break; |
916 | goto out; | 915 | case SEEK_CUR: |
916 | if (offset == 0) | ||
917 | return filp->f_pos; | ||
918 | inode_lock(inode); | ||
919 | offset += filp->f_pos; | ||
920 | if (offset < 0) { | ||
921 | inode_unlock(inode); | ||
922 | return -EINVAL; | ||
923 | } | ||
917 | } | 924 | } |
918 | if (offset != filp->f_pos) { | 925 | if (offset != filp->f_pos) { |
919 | filp->f_pos = offset; | 926 | filp->f_pos = offset; |
920 | dir_ctx->dir_cookie = 0; | 927 | dir_ctx->dir_cookie = 0; |
921 | dir_ctx->duped = 0; | 928 | dir_ctx->duped = 0; |
922 | } | 929 | } |
923 | out: | ||
924 | inode_unlock(inode); | 930 | inode_unlock(inode); |
925 | return offset; | 931 | return offset; |
926 | } | 932 | } |
@@ -1032,7 +1038,7 @@ int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags) | |||
1032 | if (flags & LOOKUP_REVAL) | 1038 | if (flags & LOOKUP_REVAL) |
1033 | goto out_force; | 1039 | goto out_force; |
1034 | out: | 1040 | out: |
1035 | return (inode->i_nlink == 0) ? -ENOENT : 0; | 1041 | return (inode->i_nlink == 0) ? -ESTALE : 0; |
1036 | out_force: | 1042 | out_force: |
1037 | if (flags & LOOKUP_RCU) | 1043 | if (flags & LOOKUP_RCU) |
1038 | return -ECHILD; | 1044 | return -ECHILD; |
@@ -2499,7 +2505,9 @@ static int nfs_execute_ok(struct inode *inode, int mask) | |||
2499 | struct nfs_server *server = NFS_SERVER(inode); | 2505 | struct nfs_server *server = NFS_SERVER(inode); |
2500 | int ret = 0; | 2506 | int ret = 0; |
2501 | 2507 | ||
2502 | if (nfs_check_cache_invalid(inode, NFS_INO_INVALID_ACCESS)) { | 2508 | if (S_ISDIR(inode->i_mode)) |
2509 | return 0; | ||
2510 | if (nfs_check_cache_invalid(inode, NFS_INO_INVALID_OTHER)) { | ||
2503 | if (mask & MAY_NOT_BLOCK) | 2511 | if (mask & MAY_NOT_BLOCK) |
2504 | return -ECHILD; | 2512 | return -ECHILD; |
2505 | ret = __nfs_revalidate_inode(server, inode); | 2513 | ret = __nfs_revalidate_inode(server, inode); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 621c517b325c..aa12c3063bae 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -758,7 +758,7 @@ static void nfs_direct_write_schedule_work(struct work_struct *work) | |||
758 | 758 | ||
759 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq) | 759 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq) |
760 | { | 760 | { |
761 | schedule_work(&dreq->work); /* Calls nfs_direct_write_schedule_work */ | 761 | queue_work(nfsiod_workqueue, &dreq->work); /* Calls nfs_direct_write_schedule_work */ |
762 | } | 762 | } |
763 | 763 | ||
764 | static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) | 764 | static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 81cca49a8375..29553fdba8af 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -532,13 +532,13 @@ const struct address_space_operations nfs_file_aops = { | |||
532 | * writable, implying that someone is about to modify the page through a | 532 | * writable, implying that someone is about to modify the page through a |
533 | * shared-writable mapping | 533 | * shared-writable mapping |
534 | */ | 534 | */ |
535 | static int nfs_vm_page_mkwrite(struct vm_fault *vmf) | 535 | static vm_fault_t nfs_vm_page_mkwrite(struct vm_fault *vmf) |
536 | { | 536 | { |
537 | struct page *page = vmf->page; | 537 | struct page *page = vmf->page; |
538 | struct file *filp = vmf->vma->vm_file; | 538 | struct file *filp = vmf->vma->vm_file; |
539 | struct inode *inode = file_inode(filp); | 539 | struct inode *inode = file_inode(filp); |
540 | unsigned pagelen; | 540 | unsigned pagelen; |
541 | int ret = VM_FAULT_NOPAGE; | 541 | vm_fault_t ret = VM_FAULT_NOPAGE; |
542 | struct address_space *mapping; | 542 | struct address_space *mapping; |
543 | 543 | ||
544 | dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%pD2(%lu), offset %lld)\n", | 544 | dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%pD2(%lu), offset %lld)\n", |
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 8f003792ccde..cae43333ef16 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c | |||
@@ -812,7 +812,6 @@ ff_layout_pg_get_read(struct nfs_pageio_descriptor *pgio, | |||
812 | struct nfs_page *req, | 812 | struct nfs_page *req, |
813 | bool strict_iomode) | 813 | bool strict_iomode) |
814 | { | 814 | { |
815 | retry_strict: | ||
816 | pnfs_put_lseg(pgio->pg_lseg); | 815 | pnfs_put_lseg(pgio->pg_lseg); |
817 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, | 816 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, |
818 | req->wb_context, | 817 | req->wb_context, |
@@ -825,16 +824,6 @@ retry_strict: | |||
825 | pgio->pg_error = PTR_ERR(pgio->pg_lseg); | 824 | pgio->pg_error = PTR_ERR(pgio->pg_lseg); |
826 | pgio->pg_lseg = NULL; | 825 | pgio->pg_lseg = NULL; |
827 | } | 826 | } |
828 | |||
829 | /* If we don't have checking, do get a IOMODE_RW | ||
830 | * segment, and the server wants to avoid READs | ||
831 | * there, then retry! | ||
832 | */ | ||
833 | if (pgio->pg_lseg && !strict_iomode && | ||
834 | ff_layout_avoid_read_on_rw(pgio->pg_lseg)) { | ||
835 | strict_iomode = true; | ||
836 | goto retry_strict; | ||
837 | } | ||
838 | } | 827 | } |
839 | 828 | ||
840 | static void | 829 | static void |
@@ -849,14 +838,16 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio, | |||
849 | retry: | 838 | retry: |
850 | pnfs_generic_pg_check_layout(pgio); | 839 | pnfs_generic_pg_check_layout(pgio); |
851 | /* Use full layout for now */ | 840 | /* Use full layout for now */ |
852 | if (!pgio->pg_lseg) | 841 | if (!pgio->pg_lseg) { |
853 | ff_layout_pg_get_read(pgio, req, false); | 842 | ff_layout_pg_get_read(pgio, req, false); |
854 | else if (ff_layout_avoid_read_on_rw(pgio->pg_lseg)) | 843 | if (!pgio->pg_lseg) |
844 | goto out_nolseg; | ||
845 | } | ||
846 | if (ff_layout_avoid_read_on_rw(pgio->pg_lseg)) { | ||
855 | ff_layout_pg_get_read(pgio, req, true); | 847 | ff_layout_pg_get_read(pgio, req, true); |
856 | 848 | if (!pgio->pg_lseg) | |
857 | /* If no lseg, fall back to read through mds */ | 849 | goto out_nolseg; |
858 | if (pgio->pg_lseg == NULL) | 850 | } |
859 | goto out_mds; | ||
860 | 851 | ||
861 | ds = ff_layout_choose_best_ds_for_read(pgio->pg_lseg, 0, &ds_idx); | 852 | ds = ff_layout_choose_best_ds_for_read(pgio->pg_lseg, 0, &ds_idx); |
862 | if (!ds) { | 853 | if (!ds) { |
@@ -878,6 +869,9 @@ retry: | |||
878 | pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize; | 869 | pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize; |
879 | 870 | ||
880 | return; | 871 | return; |
872 | out_nolseg: | ||
873 | if (pgio->pg_error < 0) | ||
874 | return; | ||
881 | out_mds: | 875 | out_mds: |
882 | pnfs_put_lseg(pgio->pg_lseg); | 876 | pnfs_put_lseg(pgio->pg_lseg); |
883 | pgio->pg_lseg = NULL; | 877 | pgio->pg_lseg = NULL; |
@@ -1323,6 +1317,7 @@ static void ff_layout_read_record_layoutstats_done(struct rpc_task *task, | |||
1323 | FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx), | 1317 | FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx), |
1324 | hdr->args.count, | 1318 | hdr->args.count, |
1325 | hdr->res.count); | 1319 | hdr->res.count); |
1320 | set_bit(NFS_LSEG_LAYOUTRETURN, &hdr->lseg->pls_flags); | ||
1326 | } | 1321 | } |
1327 | 1322 | ||
1328 | static int ff_layout_read_prepare_common(struct rpc_task *task, | 1323 | static int ff_layout_read_prepare_common(struct rpc_task *task, |
@@ -1507,6 +1502,7 @@ static void ff_layout_write_record_layoutstats_done(struct rpc_task *task, | |||
1507 | FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx), | 1502 | FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx), |
1508 | hdr->args.count, hdr->res.count, | 1503 | hdr->args.count, hdr->res.count, |
1509 | hdr->res.verf->committed); | 1504 | hdr->res.verf->committed); |
1505 | set_bit(NFS_LSEG_LAYOUTRETURN, &hdr->lseg->pls_flags); | ||
1510 | } | 1506 | } |
1511 | 1507 | ||
1512 | static int ff_layout_write_prepare_common(struct rpc_task *task, | 1508 | static int ff_layout_write_prepare_common(struct rpc_task *task, |
@@ -1615,6 +1611,7 @@ static void ff_layout_commit_record_layoutstats_done(struct rpc_task *task, | |||
1615 | nfs4_ff_layout_stat_io_end_write(task, | 1611 | nfs4_ff_layout_stat_io_end_write(task, |
1616 | FF_LAYOUT_COMP(cdata->lseg, cdata->ds_commit_index), | 1612 | FF_LAYOUT_COMP(cdata->lseg, cdata->ds_commit_index), |
1617 | count, count, NFS_FILE_SYNC); | 1613 | count, count, NFS_FILE_SYNC); |
1614 | set_bit(NFS_LSEG_LAYOUTRETURN, &cdata->lseg->pls_flags); | ||
1618 | } | 1615 | } |
1619 | 1616 | ||
1620 | static void ff_layout_commit_prepare_common(struct rpc_task *task, | 1617 | static void ff_layout_commit_prepare_common(struct rpc_task *task, |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 7173a4ee862c..9fce18548f7e 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
@@ -108,6 +108,7 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type) | |||
108 | case -EPROTONOSUPPORT: | 108 | case -EPROTONOSUPPORT: |
109 | dprintk("NFS_V3_ACL extension not supported; disabling\n"); | 109 | dprintk("NFS_V3_ACL extension not supported; disabling\n"); |
110 | server->caps &= ~NFS_CAP_ACLS; | 110 | server->caps &= ~NFS_CAP_ACLS; |
111 | /* fall through */ | ||
111 | case -ENOTSUPP: | 112 | case -ENOTSUPP: |
112 | status = -EOPNOTSUPP; | 113 | status = -EOPNOTSUPP; |
113 | default: | 114 | default: |
@@ -229,6 +230,7 @@ static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
229 | dprintk("NFS_V3_ACL SETACL RPC not supported" | 230 | dprintk("NFS_V3_ACL SETACL RPC not supported" |
230 | "(will not retry)\n"); | 231 | "(will not retry)\n"); |
231 | server->caps &= ~NFS_CAP_ACLS; | 232 | server->caps &= ~NFS_CAP_ACLS; |
233 | /* fall through */ | ||
232 | case -ENOTSUPP: | 234 | case -ENOTSUPP: |
233 | status = -EOPNOTSUPP; | 235 | status = -EOPNOTSUPP; |
234 | } | 236 | } |
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index 5f59b6f65a42..ac5b784a1de0 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "internal.h" | 17 | #include "internal.h" |
18 | 18 | ||
19 | #define NFSDBG_FACILITY NFSDBG_PROC | 19 | #define NFSDBG_FACILITY NFSDBG_PROC |
20 | static int nfs42_do_offload_cancel_async(struct file *dst, nfs4_stateid *std); | ||
20 | 21 | ||
21 | static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, | 22 | static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, |
22 | struct nfs_lock_context *lock, loff_t offset, loff_t len) | 23 | struct nfs_lock_context *lock, loff_t offset, loff_t len) |
@@ -130,6 +131,91 @@ out_unlock: | |||
130 | return err; | 131 | return err; |
131 | } | 132 | } |
132 | 133 | ||
134 | static int handle_async_copy(struct nfs42_copy_res *res, | ||
135 | struct nfs_server *server, | ||
136 | struct file *src, | ||
137 | struct file *dst, | ||
138 | nfs4_stateid *src_stateid) | ||
139 | { | ||
140 | struct nfs4_copy_state *copy; | ||
141 | int status = NFS4_OK; | ||
142 | bool found_pending = false; | ||
143 | struct nfs_open_context *ctx = nfs_file_open_context(dst); | ||
144 | |||
145 | spin_lock(&server->nfs_client->cl_lock); | ||
146 | list_for_each_entry(copy, &server->nfs_client->pending_cb_stateids, | ||
147 | copies) { | ||
148 | if (memcmp(&res->write_res.stateid, ©->stateid, | ||
149 | NFS4_STATEID_SIZE)) | ||
150 | continue; | ||
151 | found_pending = true; | ||
152 | list_del(©->copies); | ||
153 | break; | ||
154 | } | ||
155 | if (found_pending) { | ||
156 | spin_unlock(&server->nfs_client->cl_lock); | ||
157 | goto out; | ||
158 | } | ||
159 | |||
160 | copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS); | ||
161 | if (!copy) { | ||
162 | spin_unlock(&server->nfs_client->cl_lock); | ||
163 | return -ENOMEM; | ||
164 | } | ||
165 | memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE); | ||
166 | init_completion(©->completion); | ||
167 | copy->parent_state = ctx->state; | ||
168 | |||
169 | list_add_tail(©->copies, &server->ss_copies); | ||
170 | spin_unlock(&server->nfs_client->cl_lock); | ||
171 | |||
172 | status = wait_for_completion_interruptible(©->completion); | ||
173 | spin_lock(&server->nfs_client->cl_lock); | ||
174 | list_del_init(©->copies); | ||
175 | spin_unlock(&server->nfs_client->cl_lock); | ||
176 | if (status == -ERESTARTSYS) { | ||
177 | goto out_cancel; | ||
178 | } else if (copy->flags) { | ||
179 | status = -EAGAIN; | ||
180 | goto out_cancel; | ||
181 | } | ||
182 | out: | ||
183 | res->write_res.count = copy->count; | ||
184 | memcpy(&res->write_res.verifier, ©->verf, sizeof(copy->verf)); | ||
185 | status = -copy->error; | ||
186 | |||
187 | kfree(copy); | ||
188 | return status; | ||
189 | out_cancel: | ||
190 | nfs42_do_offload_cancel_async(dst, ©->stateid); | ||
191 | kfree(copy); | ||
192 | return status; | ||
193 | } | ||
194 | |||
195 | static int process_copy_commit(struct file *dst, loff_t pos_dst, | ||
196 | struct nfs42_copy_res *res) | ||
197 | { | ||
198 | struct nfs_commitres cres; | ||
199 | int status = -ENOMEM; | ||
200 | |||
201 | cres.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS); | ||
202 | if (!cres.verf) | ||
203 | goto out; | ||
204 | |||
205 | status = nfs4_proc_commit(dst, pos_dst, res->write_res.count, &cres); | ||
206 | if (status) | ||
207 | goto out_free; | ||
208 | if (nfs_write_verifier_cmp(&res->write_res.verifier.verifier, | ||
209 | &cres.verf->verifier)) { | ||
210 | dprintk("commit verf differs from copy verf\n"); | ||
211 | status = -EAGAIN; | ||
212 | } | ||
213 | out_free: | ||
214 | kfree(cres.verf); | ||
215 | out: | ||
216 | return status; | ||
217 | } | ||
218 | |||
133 | static ssize_t _nfs42_proc_copy(struct file *src, | 219 | static ssize_t _nfs42_proc_copy(struct file *src, |
134 | struct nfs_lock_context *src_lock, | 220 | struct nfs_lock_context *src_lock, |
135 | struct file *dst, | 221 | struct file *dst, |
@@ -168,9 +254,16 @@ static ssize_t _nfs42_proc_copy(struct file *src, | |||
168 | if (status) | 254 | if (status) |
169 | return status; | 255 | return status; |
170 | 256 | ||
171 | res->commit_res.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS); | 257 | res->commit_res.verf = NULL; |
172 | if (!res->commit_res.verf) | 258 | if (args->sync) { |
173 | return -ENOMEM; | 259 | res->commit_res.verf = |
260 | kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS); | ||
261 | if (!res->commit_res.verf) | ||
262 | return -ENOMEM; | ||
263 | } | ||
264 | set_bit(NFS_CLNT_DST_SSC_COPY_STATE, | ||
265 | &dst_lock->open_context->state->flags); | ||
266 | |||
174 | status = nfs4_call_sync(server->client, server, &msg, | 267 | status = nfs4_call_sync(server->client, server, &msg, |
175 | &args->seq_args, &res->seq_res, 0); | 268 | &args->seq_args, &res->seq_res, 0); |
176 | if (status == -ENOTSUPP) | 269 | if (status == -ENOTSUPP) |
@@ -178,18 +271,34 @@ static ssize_t _nfs42_proc_copy(struct file *src, | |||
178 | if (status) | 271 | if (status) |
179 | goto out; | 272 | goto out; |
180 | 273 | ||
181 | if (nfs_write_verifier_cmp(&res->write_res.verifier.verifier, | 274 | if (args->sync && |
275 | nfs_write_verifier_cmp(&res->write_res.verifier.verifier, | ||
182 | &res->commit_res.verf->verifier)) { | 276 | &res->commit_res.verf->verifier)) { |
183 | status = -EAGAIN; | 277 | status = -EAGAIN; |
184 | goto out; | 278 | goto out; |
185 | } | 279 | } |
186 | 280 | ||
281 | if (!res->synchronous) { | ||
282 | status = handle_async_copy(res, server, src, dst, | ||
283 | &args->src_stateid); | ||
284 | if (status) | ||
285 | return status; | ||
286 | } | ||
287 | |||
288 | if ((!res->synchronous || !args->sync) && | ||
289 | res->write_res.verifier.committed != NFS_FILE_SYNC) { | ||
290 | status = process_copy_commit(dst, pos_dst, res); | ||
291 | if (status) | ||
292 | return status; | ||
293 | } | ||
294 | |||
187 | truncate_pagecache_range(dst_inode, pos_dst, | 295 | truncate_pagecache_range(dst_inode, pos_dst, |
188 | pos_dst + res->write_res.count); | 296 | pos_dst + res->write_res.count); |
189 | 297 | ||
190 | status = res->write_res.count; | 298 | status = res->write_res.count; |
191 | out: | 299 | out: |
192 | kfree(res->commit_res.verf); | 300 | if (args->sync) |
301 | kfree(res->commit_res.verf); | ||
193 | return status; | 302 | return status; |
194 | } | 303 | } |
195 | 304 | ||
@@ -206,6 +315,7 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, | |||
206 | .dst_fh = NFS_FH(file_inode(dst)), | 315 | .dst_fh = NFS_FH(file_inode(dst)), |
207 | .dst_pos = pos_dst, | 316 | .dst_pos = pos_dst, |
208 | .count = count, | 317 | .count = count, |
318 | .sync = false, | ||
209 | }; | 319 | }; |
210 | struct nfs42_copy_res res; | 320 | struct nfs42_copy_res res; |
211 | struct nfs4_exception src_exception = { | 321 | struct nfs4_exception src_exception = { |
@@ -247,7 +357,11 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, | |||
247 | if (err == -ENOTSUPP) { | 357 | if (err == -ENOTSUPP) { |
248 | err = -EOPNOTSUPP; | 358 | err = -EOPNOTSUPP; |
249 | break; | 359 | break; |
250 | } if (err == -EAGAIN) { | 360 | } else if (err == -EAGAIN) { |
361 | dst_exception.retry = 1; | ||
362 | continue; | ||
363 | } else if (err == -NFS4ERR_OFFLOAD_NO_REQS && !args.sync) { | ||
364 | args.sync = true; | ||
251 | dst_exception.retry = 1; | 365 | dst_exception.retry = 1; |
252 | continue; | 366 | continue; |
253 | } | 367 | } |
@@ -264,6 +378,89 @@ out_put_src_lock: | |||
264 | return err; | 378 | return err; |
265 | } | 379 | } |
266 | 380 | ||
381 | struct nfs42_offloadcancel_data { | ||
382 | struct nfs_server *seq_server; | ||
383 | struct nfs42_offload_status_args args; | ||
384 | struct nfs42_offload_status_res res; | ||
385 | }; | ||
386 | |||
387 | static void nfs42_offload_cancel_prepare(struct rpc_task *task, void *calldata) | ||
388 | { | ||
389 | struct nfs42_offloadcancel_data *data = calldata; | ||
390 | |||
391 | nfs4_setup_sequence(data->seq_server->nfs_client, | ||
392 | &data->args.osa_seq_args, | ||
393 | &data->res.osr_seq_res, task); | ||
394 | } | ||
395 | |||
396 | static void nfs42_offload_cancel_done(struct rpc_task *task, void *calldata) | ||
397 | { | ||
398 | struct nfs42_offloadcancel_data *data = calldata; | ||
399 | |||
400 | nfs41_sequence_done(task, &data->res.osr_seq_res); | ||
401 | if (task->tk_status && | ||
402 | nfs4_async_handle_error(task, data->seq_server, NULL, | ||
403 | NULL) == -EAGAIN) | ||
404 | rpc_restart_call_prepare(task); | ||
405 | } | ||
406 | |||
407 | static void nfs42_free_offloadcancel_data(void *data) | ||
408 | { | ||
409 | kfree(data); | ||
410 | } | ||
411 | |||
412 | static const struct rpc_call_ops nfs42_offload_cancel_ops = { | ||
413 | .rpc_call_prepare = nfs42_offload_cancel_prepare, | ||
414 | .rpc_call_done = nfs42_offload_cancel_done, | ||
415 | .rpc_release = nfs42_free_offloadcancel_data, | ||
416 | }; | ||
417 | |||
418 | static int nfs42_do_offload_cancel_async(struct file *dst, | ||
419 | nfs4_stateid *stateid) | ||
420 | { | ||
421 | struct nfs_server *dst_server = NFS_SERVER(file_inode(dst)); | ||
422 | struct nfs42_offloadcancel_data *data = NULL; | ||
423 | struct nfs_open_context *ctx = nfs_file_open_context(dst); | ||
424 | struct rpc_task *task; | ||
425 | struct rpc_message msg = { | ||
426 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OFFLOAD_CANCEL], | ||
427 | .rpc_cred = ctx->cred, | ||
428 | }; | ||
429 | struct rpc_task_setup task_setup_data = { | ||
430 | .rpc_client = dst_server->client, | ||
431 | .rpc_message = &msg, | ||
432 | .callback_ops = &nfs42_offload_cancel_ops, | ||
433 | .workqueue = nfsiod_workqueue, | ||
434 | .flags = RPC_TASK_ASYNC, | ||
435 | }; | ||
436 | int status; | ||
437 | |||
438 | if (!(dst_server->caps & NFS_CAP_OFFLOAD_CANCEL)) | ||
439 | return -EOPNOTSUPP; | ||
440 | |||
441 | data = kzalloc(sizeof(struct nfs42_offloadcancel_data), GFP_NOFS); | ||
442 | if (data == NULL) | ||
443 | return -ENOMEM; | ||
444 | |||
445 | data->seq_server = dst_server; | ||
446 | data->args.osa_src_fh = NFS_FH(file_inode(dst)); | ||
447 | memcpy(&data->args.osa_stateid, stateid, | ||
448 | sizeof(data->args.osa_stateid)); | ||
449 | msg.rpc_argp = &data->args; | ||
450 | msg.rpc_resp = &data->res; | ||
451 | task_setup_data.callback_data = data; | ||
452 | nfs4_init_sequence(&data->args.osa_seq_args, &data->res.osr_seq_res, | ||
453 | 1, 0); | ||
454 | task = rpc_run_task(&task_setup_data); | ||
455 | if (IS_ERR(task)) | ||
456 | return PTR_ERR(task); | ||
457 | status = rpc_wait_for_completion_task(task); | ||
458 | if (status == -ENOTSUPP) | ||
459 | dst_server->caps &= ~NFS_CAP_OFFLOAD_CANCEL; | ||
460 | rpc_put_task(task); | ||
461 | return status; | ||
462 | } | ||
463 | |||
267 | static loff_t _nfs42_proc_llseek(struct file *filep, | 464 | static loff_t _nfs42_proc_llseek(struct file *filep, |
268 | struct nfs_lock_context *lock, loff_t offset, int whence) | 465 | struct nfs_lock_context *lock, loff_t offset, int whence) |
269 | { | 466 | { |
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c index 5966e1e7b1f5..69f72ed2bf87 100644 --- a/fs/nfs/nfs42xdr.c +++ b/fs/nfs/nfs42xdr.c | |||
@@ -26,6 +26,9 @@ | |||
26 | NFS42_WRITE_RES_SIZE + \ | 26 | NFS42_WRITE_RES_SIZE + \ |
27 | 1 /* cr_consecutive */ + \ | 27 | 1 /* cr_consecutive */ + \ |
28 | 1 /* cr_synchronous */) | 28 | 1 /* cr_synchronous */) |
29 | #define encode_offload_cancel_maxsz (op_encode_hdr_maxsz + \ | ||
30 | XDR_QUADLEN(NFS4_STATEID_SIZE)) | ||
31 | #define decode_offload_cancel_maxsz (op_decode_hdr_maxsz) | ||
29 | #define encode_deallocate_maxsz (op_encode_hdr_maxsz + \ | 32 | #define encode_deallocate_maxsz (op_encode_hdr_maxsz + \ |
30 | encode_fallocate_maxsz) | 33 | encode_fallocate_maxsz) |
31 | #define decode_deallocate_maxsz (op_decode_hdr_maxsz) | 34 | #define decode_deallocate_maxsz (op_decode_hdr_maxsz) |
@@ -75,6 +78,12 @@ | |||
75 | decode_putfh_maxsz + \ | 78 | decode_putfh_maxsz + \ |
76 | decode_copy_maxsz + \ | 79 | decode_copy_maxsz + \ |
77 | decode_commit_maxsz) | 80 | decode_commit_maxsz) |
81 | #define NFS4_enc_offload_cancel_sz (compound_encode_hdr_maxsz + \ | ||
82 | encode_putfh_maxsz + \ | ||
83 | encode_offload_cancel_maxsz) | ||
84 | #define NFS4_dec_offload_cancel_sz (compound_decode_hdr_maxsz + \ | ||
85 | decode_putfh_maxsz + \ | ||
86 | decode_offload_cancel_maxsz) | ||
78 | #define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \ | 87 | #define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \ |
79 | encode_putfh_maxsz + \ | 88 | encode_putfh_maxsz + \ |
80 | encode_deallocate_maxsz + \ | 89 | encode_deallocate_maxsz + \ |
@@ -141,10 +150,18 @@ static void encode_copy(struct xdr_stream *xdr, | |||
141 | encode_uint64(xdr, args->count); | 150 | encode_uint64(xdr, args->count); |
142 | 151 | ||
143 | encode_uint32(xdr, 1); /* consecutive = true */ | 152 | encode_uint32(xdr, 1); /* consecutive = true */ |
144 | encode_uint32(xdr, 1); /* synchronous = true */ | 153 | encode_uint32(xdr, args->sync); |
145 | encode_uint32(xdr, 0); /* src server list */ | 154 | encode_uint32(xdr, 0); /* src server list */ |
146 | } | 155 | } |
147 | 156 | ||
157 | static void encode_offload_cancel(struct xdr_stream *xdr, | ||
158 | const struct nfs42_offload_status_args *args, | ||
159 | struct compound_hdr *hdr) | ||
160 | { | ||
161 | encode_op_hdr(xdr, OP_OFFLOAD_CANCEL, decode_offload_cancel_maxsz, hdr); | ||
162 | encode_nfs4_stateid(xdr, &args->osa_stateid); | ||
163 | } | ||
164 | |||
148 | static void encode_deallocate(struct xdr_stream *xdr, | 165 | static void encode_deallocate(struct xdr_stream *xdr, |
149 | const struct nfs42_falloc_args *args, | 166 | const struct nfs42_falloc_args *args, |
150 | struct compound_hdr *hdr) | 167 | struct compound_hdr *hdr) |
@@ -256,7 +273,27 @@ static void nfs4_xdr_enc_copy(struct rpc_rqst *req, | |||
256 | encode_savefh(xdr, &hdr); | 273 | encode_savefh(xdr, &hdr); |
257 | encode_putfh(xdr, args->dst_fh, &hdr); | 274 | encode_putfh(xdr, args->dst_fh, &hdr); |
258 | encode_copy(xdr, args, &hdr); | 275 | encode_copy(xdr, args, &hdr); |
259 | encode_copy_commit(xdr, args, &hdr); | 276 | if (args->sync) |
277 | encode_copy_commit(xdr, args, &hdr); | ||
278 | encode_nops(&hdr); | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * Encode OFFLOAD_CANEL request | ||
283 | */ | ||
284 | static void nfs4_xdr_enc_offload_cancel(struct rpc_rqst *req, | ||
285 | struct xdr_stream *xdr, | ||
286 | const void *data) | ||
287 | { | ||
288 | const struct nfs42_offload_status_args *args = data; | ||
289 | struct compound_hdr hdr = { | ||
290 | .minorversion = nfs4_xdr_minorversion(&args->osa_seq_args), | ||
291 | }; | ||
292 | |||
293 | encode_compound_hdr(xdr, req, &hdr); | ||
294 | encode_sequence(xdr, &args->osa_seq_args, &hdr); | ||
295 | encode_putfh(xdr, args->osa_src_fh, &hdr); | ||
296 | encode_offload_cancel(xdr, args, &hdr); | ||
260 | encode_nops(&hdr); | 297 | encode_nops(&hdr); |
261 | } | 298 | } |
262 | 299 | ||
@@ -353,21 +390,23 @@ static int decode_write_response(struct xdr_stream *xdr, | |||
353 | struct nfs42_write_res *res) | 390 | struct nfs42_write_res *res) |
354 | { | 391 | { |
355 | __be32 *p; | 392 | __be32 *p; |
393 | int status, count; | ||
356 | 394 | ||
357 | p = xdr_inline_decode(xdr, 4 + 8 + 4); | 395 | p = xdr_inline_decode(xdr, 4); |
358 | if (unlikely(!p)) | 396 | if (unlikely(!p)) |
359 | goto out_overflow; | 397 | goto out_overflow; |
360 | 398 | count = be32_to_cpup(p); | |
361 | /* | 399 | if (count > 1) |
362 | * We never use asynchronous mode, so warn if a server returns | ||
363 | * a stateid. | ||
364 | */ | ||
365 | if (unlikely(*p != 0)) { | ||
366 | pr_err_once("%s: server has set unrequested " | ||
367 | "asynchronous mode\n", __func__); | ||
368 | return -EREMOTEIO; | 400 | return -EREMOTEIO; |
401 | else if (count == 1) { | ||
402 | status = decode_opaque_fixed(xdr, &res->stateid, | ||
403 | NFS4_STATEID_SIZE); | ||
404 | if (unlikely(status)) | ||
405 | goto out_overflow; | ||
369 | } | 406 | } |
370 | p++; | 407 | p = xdr_inline_decode(xdr, 8 + 4); |
408 | if (unlikely(!p)) | ||
409 | goto out_overflow; | ||
371 | p = xdr_decode_hyper(p, &res->count); | 410 | p = xdr_decode_hyper(p, &res->count); |
372 | res->verifier.committed = be32_to_cpup(p); | 411 | res->verifier.committed = be32_to_cpup(p); |
373 | return decode_verifier(xdr, &res->verifier.verifier); | 412 | return decode_verifier(xdr, &res->verifier.verifier); |
@@ -413,6 +452,12 @@ static int decode_copy(struct xdr_stream *xdr, struct nfs42_copy_res *res) | |||
413 | return decode_copy_requirements(xdr, res); | 452 | return decode_copy_requirements(xdr, res); |
414 | } | 453 | } |
415 | 454 | ||
455 | static int decode_offload_cancel(struct xdr_stream *xdr, | ||
456 | struct nfs42_offload_status_res *res) | ||
457 | { | ||
458 | return decode_op_hdr(xdr, OP_OFFLOAD_CANCEL); | ||
459 | } | ||
460 | |||
416 | static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res) | 461 | static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res) |
417 | { | 462 | { |
418 | return decode_op_hdr(xdr, OP_DEALLOCATE); | 463 | return decode_op_hdr(xdr, OP_DEALLOCATE); |
@@ -507,7 +552,34 @@ static int nfs4_xdr_dec_copy(struct rpc_rqst *rqstp, | |||
507 | status = decode_copy(xdr, res); | 552 | status = decode_copy(xdr, res); |
508 | if (status) | 553 | if (status) |
509 | goto out; | 554 | goto out; |
510 | status = decode_commit(xdr, &res->commit_res); | 555 | if (res->commit_res.verf) |
556 | status = decode_commit(xdr, &res->commit_res); | ||
557 | out: | ||
558 | return status; | ||
559 | } | ||
560 | |||
561 | /* | ||
562 | * Decode OFFLOAD_CANCEL response | ||
563 | */ | ||
564 | static int nfs4_xdr_dec_offload_cancel(struct rpc_rqst *rqstp, | ||
565 | struct xdr_stream *xdr, | ||
566 | void *data) | ||
567 | { | ||
568 | struct nfs42_offload_status_res *res = data; | ||
569 | struct compound_hdr hdr; | ||
570 | int status; | ||
571 | |||
572 | status = decode_compound_hdr(xdr, &hdr); | ||
573 | if (status) | ||
574 | goto out; | ||
575 | status = decode_sequence(xdr, &res->osr_seq_res, rqstp); | ||
576 | if (status) | ||
577 | goto out; | ||
578 | status = decode_putfh(xdr); | ||
579 | if (status) | ||
580 | goto out; | ||
581 | status = decode_offload_cancel(xdr, res); | ||
582 | |||
511 | out: | 583 | out: |
512 | return status; | 584 | return status; |
513 | } | 585 | } |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 51beb6e38c90..3a6904173214 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -163,6 +163,9 @@ enum { | |||
163 | NFS_STATE_RECOVERY_FAILED, /* OPEN stateid state recovery failed */ | 163 | NFS_STATE_RECOVERY_FAILED, /* OPEN stateid state recovery failed */ |
164 | NFS_STATE_MAY_NOTIFY_LOCK, /* server may CB_NOTIFY_LOCK */ | 164 | NFS_STATE_MAY_NOTIFY_LOCK, /* server may CB_NOTIFY_LOCK */ |
165 | NFS_STATE_CHANGE_WAIT, /* A state changing operation is outstanding */ | 165 | NFS_STATE_CHANGE_WAIT, /* A state changing operation is outstanding */ |
166 | #ifdef CONFIG_NFS_V4_2 | ||
167 | NFS_CLNT_DST_SSC_COPY_STATE, /* dst server open state on client*/ | ||
168 | #endif /* CONFIG_NFS_V4_2 */ | ||
166 | }; | 169 | }; |
167 | 170 | ||
168 | struct nfs4_state { | 171 | struct nfs4_state { |
@@ -273,6 +276,9 @@ int nfs4_replace_transport(struct nfs_server *server, | |||
273 | 276 | ||
274 | /* nfs4proc.c */ | 277 | /* nfs4proc.c */ |
275 | extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception *); | 278 | extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception *); |
279 | extern int nfs4_async_handle_error(struct rpc_task *task, | ||
280 | struct nfs_server *server, | ||
281 | struct nfs4_state *state, long *timeout); | ||
276 | extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *, | 282 | extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *, |
277 | struct rpc_message *, struct nfs4_sequence_args *, | 283 | struct rpc_message *, struct nfs4_sequence_args *, |
278 | struct nfs4_sequence_res *, int); | 284 | struct nfs4_sequence_res *, int); |
@@ -505,7 +511,7 @@ extern int nfs4_sequence_done(struct rpc_task *task, | |||
505 | struct nfs4_sequence_res *res); | 511 | struct nfs4_sequence_res *res); |
506 | 512 | ||
507 | extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp); | 513 | extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp); |
508 | 514 | extern int nfs4_proc_commit(struct file *dst, __u64 offset, __u32 count, struct nfs_commitres *res); | |
509 | extern const nfs4_stateid zero_stateid; | 515 | extern const nfs4_stateid zero_stateid; |
510 | extern const nfs4_stateid invalid_stateid; | 516 | extern const nfs4_stateid invalid_stateid; |
511 | 517 | ||
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 979631411a0e..146e30862234 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
@@ -156,9 +156,23 @@ nfs4_shutdown_ds_clients(struct nfs_client *clp) | |||
156 | } | 156 | } |
157 | } | 157 | } |
158 | 158 | ||
159 | static void | ||
160 | nfs4_cleanup_callback(struct nfs_client *clp) | ||
161 | { | ||
162 | struct nfs4_copy_state *cp_state; | ||
163 | |||
164 | while (!list_empty(&clp->pending_cb_stateids)) { | ||
165 | cp_state = list_entry(clp->pending_cb_stateids.next, | ||
166 | struct nfs4_copy_state, copies); | ||
167 | list_del(&cp_state->copies); | ||
168 | kfree(cp_state); | ||
169 | } | ||
170 | } | ||
171 | |||
159 | void nfs41_shutdown_client(struct nfs_client *clp) | 172 | void nfs41_shutdown_client(struct nfs_client *clp) |
160 | { | 173 | { |
161 | if (nfs4_has_session(clp)) { | 174 | if (nfs4_has_session(clp)) { |
175 | nfs4_cleanup_callback(clp); | ||
162 | nfs4_shutdown_ds_clients(clp); | 176 | nfs4_shutdown_ds_clients(clp); |
163 | nfs4_destroy_session(clp->cl_session); | 177 | nfs4_destroy_session(clp->cl_session); |
164 | nfs4_destroy_clientid(clp); | 178 | nfs4_destroy_clientid(clp); |
@@ -202,6 +216,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init) | |||
202 | #if IS_ENABLED(CONFIG_NFS_V4_1) | 216 | #if IS_ENABLED(CONFIG_NFS_V4_1) |
203 | init_waitqueue_head(&clp->cl_lock_waitq); | 217 | init_waitqueue_head(&clp->cl_lock_waitq); |
204 | #endif | 218 | #endif |
219 | INIT_LIST_HEAD(&clp->pending_cb_stateids); | ||
205 | return clp; | 220 | return clp; |
206 | 221 | ||
207 | error: | 222 | error: |
@@ -1127,7 +1142,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1127 | nfs_server_copy_userdata(server, parent_server); | 1142 | nfs_server_copy_userdata(server, parent_server); |
1128 | 1143 | ||
1129 | /* Get a client representation */ | 1144 | /* Get a client representation */ |
1130 | #ifdef CONFIG_SUNRPC_XPRT_RDMA | 1145 | #if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA) |
1131 | rpc_set_port(data->addr, NFS_RDMA_PORT); | 1146 | rpc_set_port(data->addr, NFS_RDMA_PORT); |
1132 | error = nfs4_set_client(server, data->hostname, | 1147 | error = nfs4_set_client(server, data->hostname, |
1133 | data->addr, | 1148 | data->addr, |
@@ -1139,7 +1154,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1139 | parent_client->cl_net); | 1154 | parent_client->cl_net); |
1140 | if (!error) | 1155 | if (!error) |
1141 | goto init_server; | 1156 | goto init_server; |
1142 | #endif /* CONFIG_SUNRPC_XPRT_RDMA */ | 1157 | #endif /* IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA) */ |
1143 | 1158 | ||
1144 | rpc_set_port(data->addr, NFS_PORT); | 1159 | rpc_set_port(data->addr, NFS_PORT); |
1145 | error = nfs4_set_client(server, data->hostname, | 1160 | error = nfs4_set_client(server, data->hostname, |
@@ -1153,7 +1168,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1153 | if (error < 0) | 1168 | if (error < 0) |
1154 | goto error; | 1169 | goto error; |
1155 | 1170 | ||
1156 | #ifdef CONFIG_SUNRPC_XPRT_RDMA | 1171 | #if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA) |
1157 | init_server: | 1172 | init_server: |
1158 | #endif | 1173 | #endif |
1159 | error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); | 1174 | error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); |
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 6b3b372b59b9..4288a6ecaf75 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c | |||
@@ -133,10 +133,15 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, | |||
133 | struct file *file_out, loff_t pos_out, | 133 | struct file *file_out, loff_t pos_out, |
134 | size_t count, unsigned int flags) | 134 | size_t count, unsigned int flags) |
135 | { | 135 | { |
136 | ssize_t ret; | ||
137 | |||
136 | if (file_inode(file_in) == file_inode(file_out)) | 138 | if (file_inode(file_in) == file_inode(file_out)) |
137 | return -EINVAL; | 139 | return -EINVAL; |
138 | 140 | retry: | |
139 | return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count); | 141 | ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count); |
142 | if (ret == -EAGAIN) | ||
143 | goto retry; | ||
144 | return ret; | ||
140 | } | 145 | } |
141 | 146 | ||
142 | static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) | 147 | static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) |
@@ -149,6 +154,7 @@ static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) | |||
149 | ret = nfs42_proc_llseek(filep, offset, whence); | 154 | ret = nfs42_proc_llseek(filep, offset, whence); |
150 | if (ret != -ENOTSUPP) | 155 | if (ret != -ENOTSUPP) |
151 | return ret; | 156 | return ret; |
157 | /* Fall through */ | ||
152 | default: | 158 | default: |
153 | return nfs_file_llseek(filep, offset, whence); | 159 | return nfs_file_llseek(filep, offset, whence); |
154 | } | 160 | } |
diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c index b6f9d84ba19b..3f23b6840547 100644 --- a/fs/nfs/nfs4idmap.c +++ b/fs/nfs/nfs4idmap.c | |||
@@ -506,6 +506,7 @@ static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap, | |||
506 | switch (token) { | 506 | switch (token) { |
507 | case Opt_find_uid: | 507 | case Opt_find_uid: |
508 | im->im_type = IDMAP_TYPE_USER; | 508 | im->im_type = IDMAP_TYPE_USER; |
509 | /* Fall through */ | ||
509 | case Opt_find_gid: | 510 | case Opt_find_gid: |
510 | im->im_conv = IDMAP_CONV_NAMETOID; | 511 | im->im_conv = IDMAP_CONV_NAMETOID; |
511 | ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ); | 512 | ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ); |
@@ -513,9 +514,12 @@ static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap, | |||
513 | 514 | ||
514 | case Opt_find_user: | 515 | case Opt_find_user: |
515 | im->im_type = IDMAP_TYPE_USER; | 516 | im->im_type = IDMAP_TYPE_USER; |
517 | /* Fall through */ | ||
516 | case Opt_find_group: | 518 | case Opt_find_group: |
517 | im->im_conv = IDMAP_CONV_IDTONAME; | 519 | im->im_conv = IDMAP_CONV_IDTONAME; |
518 | ret = match_int(&substr, &im->im_id); | 520 | ret = match_int(&substr, &im->im_id); |
521 | if (ret) | ||
522 | goto out; | ||
519 | break; | 523 | break; |
520 | 524 | ||
521 | default: | 525 | default: |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index b790976d3913..34830f6457ea 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -449,6 +449,7 @@ static int nfs4_do_handle_exception(struct nfs_server *server, | |||
449 | stateid); | 449 | stateid); |
450 | goto wait_on_recovery; | 450 | goto wait_on_recovery; |
451 | } | 451 | } |
452 | /* Fall through */ | ||
452 | case -NFS4ERR_OPENMODE: | 453 | case -NFS4ERR_OPENMODE: |
453 | if (inode) { | 454 | if (inode) { |
454 | int err; | 455 | int err; |
@@ -501,8 +502,10 @@ static int nfs4_do_handle_exception(struct nfs_server *server, | |||
501 | ret = -EBUSY; | 502 | ret = -EBUSY; |
502 | break; | 503 | break; |
503 | } | 504 | } |
505 | /* Fall through */ | ||
504 | case -NFS4ERR_DELAY: | 506 | case -NFS4ERR_DELAY: |
505 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 507 | nfs_inc_server_stats(server, NFSIOS_DELAY); |
508 | /* Fall through */ | ||
506 | case -NFS4ERR_GRACE: | 509 | case -NFS4ERR_GRACE: |
507 | case -NFS4ERR_LAYOUTTRYLATER: | 510 | case -NFS4ERR_LAYOUTTRYLATER: |
508 | case -NFS4ERR_RECALLCONFLICT: | 511 | case -NFS4ERR_RECALLCONFLICT: |
@@ -581,12 +584,19 @@ nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server, | |||
581 | ret = -EIO; | 584 | ret = -EIO; |
582 | return ret; | 585 | return ret; |
583 | out_retry: | 586 | out_retry: |
584 | if (ret == 0) | 587 | if (ret == 0) { |
585 | exception->retry = 1; | 588 | exception->retry = 1; |
589 | /* | ||
590 | * For NFS4ERR_MOVED, the client transport will need to | ||
591 | * be recomputed after migration recovery has completed. | ||
592 | */ | ||
593 | if (errorcode == -NFS4ERR_MOVED) | ||
594 | rpc_task_release_transport(task); | ||
595 | } | ||
586 | return ret; | 596 | return ret; |
587 | } | 597 | } |
588 | 598 | ||
589 | static int | 599 | int |
590 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server, | 600 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server, |
591 | struct nfs4_state *state, long *timeout) | 601 | struct nfs4_state *state, long *timeout) |
592 | { | 602 | { |
@@ -1071,15 +1081,30 @@ int nfs4_call_sync(struct rpc_clnt *clnt, | |||
1071 | return nfs4_call_sync_sequence(clnt, server, msg, args, res); | 1081 | return nfs4_call_sync_sequence(clnt, server, msg, args, res); |
1072 | } | 1082 | } |
1073 | 1083 | ||
1074 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo, | 1084 | static void |
1075 | unsigned long timestamp) | 1085 | nfs4_inc_nlink_locked(struct inode *inode) |
1086 | { | ||
1087 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER; | ||
1088 | inc_nlink(inode); | ||
1089 | } | ||
1090 | |||
1091 | static void | ||
1092 | nfs4_dec_nlink_locked(struct inode *inode) | ||
1093 | { | ||
1094 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER; | ||
1095 | drop_nlink(inode); | ||
1096 | } | ||
1097 | |||
1098 | static void | ||
1099 | update_changeattr_locked(struct inode *dir, struct nfs4_change_info *cinfo, | ||
1100 | unsigned long timestamp, unsigned long cache_validity) | ||
1076 | { | 1101 | { |
1077 | struct nfs_inode *nfsi = NFS_I(dir); | 1102 | struct nfs_inode *nfsi = NFS_I(dir); |
1078 | 1103 | ||
1079 | spin_lock(&dir->i_lock); | ||
1080 | nfsi->cache_validity |= NFS_INO_INVALID_CTIME | 1104 | nfsi->cache_validity |= NFS_INO_INVALID_CTIME |
1081 | | NFS_INO_INVALID_MTIME | 1105 | | NFS_INO_INVALID_MTIME |
1082 | | NFS_INO_INVALID_DATA; | 1106 | | NFS_INO_INVALID_DATA |
1107 | | cache_validity; | ||
1083 | if (cinfo->atomic && cinfo->before == inode_peek_iversion_raw(dir)) { | 1108 | if (cinfo->atomic && cinfo->before == inode_peek_iversion_raw(dir)) { |
1084 | nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE; | 1109 | nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE; |
1085 | nfsi->attrtimeo_timestamp = jiffies; | 1110 | nfsi->attrtimeo_timestamp = jiffies; |
@@ -1092,7 +1117,16 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo, | |||
1092 | inode_set_iversion_raw(dir, cinfo->after); | 1117 | inode_set_iversion_raw(dir, cinfo->after); |
1093 | nfsi->read_cache_jiffies = timestamp; | 1118 | nfsi->read_cache_jiffies = timestamp; |
1094 | nfsi->attr_gencount = nfs_inc_attr_generation_counter(); | 1119 | nfsi->attr_gencount = nfs_inc_attr_generation_counter(); |
1120 | nfsi->cache_validity &= ~NFS_INO_INVALID_CHANGE; | ||
1095 | nfs_fscache_invalidate(dir); | 1121 | nfs_fscache_invalidate(dir); |
1122 | } | ||
1123 | |||
1124 | static void | ||
1125 | update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo, | ||
1126 | unsigned long timestamp, unsigned long cache_validity) | ||
1127 | { | ||
1128 | spin_lock(&dir->i_lock); | ||
1129 | update_changeattr_locked(dir, cinfo, timestamp, cache_validity); | ||
1096 | spin_unlock(&dir->i_lock); | 1130 | spin_unlock(&dir->i_lock); |
1097 | } | 1131 | } |
1098 | 1132 | ||
@@ -1354,6 +1388,7 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode, | |||
1354 | case NFS4_OPEN_CLAIM_PREVIOUS: | 1388 | case NFS4_OPEN_CLAIM_PREVIOUS: |
1355 | if (!test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) | 1389 | if (!test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) |
1356 | break; | 1390 | break; |
1391 | /* Fall through */ | ||
1357 | default: | 1392 | default: |
1358 | return 0; | 1393 | return 0; |
1359 | } | 1394 | } |
@@ -1773,6 +1808,10 @@ nfs4_opendata_check_deleg(struct nfs4_opendata *data, struct nfs4_state *state) | |||
1773 | data->o_res.delegation_type, | 1808 | data->o_res.delegation_type, |
1774 | &data->o_res.delegation, | 1809 | &data->o_res.delegation, |
1775 | data->o_res.pagemod_limit); | 1810 | data->o_res.pagemod_limit); |
1811 | |||
1812 | if (data->o_res.do_recall) | ||
1813 | nfs_async_inode_return_delegation(state->inode, | ||
1814 | &data->o_res.delegation); | ||
1776 | } | 1815 | } |
1777 | 1816 | ||
1778 | /* | 1817 | /* |
@@ -2119,6 +2158,7 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, | |||
2119 | err = nfs4_open_recover_helper(opendata, FMODE_WRITE); | 2158 | err = nfs4_open_recover_helper(opendata, FMODE_WRITE); |
2120 | if (err) | 2159 | if (err) |
2121 | break; | 2160 | break; |
2161 | /* Fall through */ | ||
2122 | case FMODE_READ: | 2162 | case FMODE_READ: |
2123 | err = nfs4_open_recover_helper(opendata, FMODE_READ); | 2163 | err = nfs4_open_recover_helper(opendata, FMODE_READ); |
2124 | } | 2164 | } |
@@ -2248,6 +2288,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
2248 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: | 2288 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: |
2249 | case NFS4_OPEN_CLAIM_DELEG_PREV_FH: | 2289 | case NFS4_OPEN_CLAIM_DELEG_PREV_FH: |
2250 | data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0]; | 2290 | data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0]; |
2291 | /* Fall through */ | ||
2251 | case NFS4_OPEN_CLAIM_FH: | 2292 | case NFS4_OPEN_CLAIM_FH: |
2252 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | 2293 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; |
2253 | } | 2294 | } |
@@ -2481,7 +2522,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data, | |||
2481 | if (data->file_created || | 2522 | if (data->file_created || |
2482 | inode_peek_iversion_raw(dir) != o_res->cinfo.after) | 2523 | inode_peek_iversion_raw(dir) != o_res->cinfo.after) |
2483 | update_changeattr(dir, &o_res->cinfo, | 2524 | update_changeattr(dir, &o_res->cinfo, |
2484 | o_res->f_attr->time_start); | 2525 | o_res->f_attr->time_start, 0); |
2485 | } | 2526 | } |
2486 | if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0) | 2527 | if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0) |
2487 | server->caps &= ~NFS_CAP_POSIX_LOCK; | 2528 | server->caps &= ~NFS_CAP_POSIX_LOCK; |
@@ -2843,6 +2884,9 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, | |||
2843 | nfs_save_change_attribute(d_inode(opendata->dir))); | 2884 | nfs_save_change_attribute(d_inode(opendata->dir))); |
2844 | } | 2885 | } |
2845 | 2886 | ||
2887 | /* Parse layoutget results before we check for access */ | ||
2888 | pnfs_parse_lgopen(state->inode, opendata->lgp, ctx); | ||
2889 | |||
2846 | ret = nfs4_opendata_access(sp->so_cred, opendata, state, fmode, flags); | 2890 | ret = nfs4_opendata_access(sp->so_cred, opendata, state, fmode, flags); |
2847 | if (ret != 0) | 2891 | if (ret != 0) |
2848 | goto out; | 2892 | goto out; |
@@ -2851,8 +2895,6 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, | |||
2851 | nfs_inode_attach_open_context(ctx); | 2895 | nfs_inode_attach_open_context(ctx); |
2852 | if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) | 2896 | if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) |
2853 | nfs4_schedule_stateid_recovery(server, state); | 2897 | nfs4_schedule_stateid_recovery(server, state); |
2854 | else | ||
2855 | pnfs_parse_lgopen(state->inode, opendata->lgp, ctx); | ||
2856 | } | 2898 | } |
2857 | 2899 | ||
2858 | out: | 2900 | out: |
@@ -3220,7 +3262,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
3220 | calldata->res.lr_res = NULL; | 3262 | calldata->res.lr_res = NULL; |
3221 | break; | 3263 | break; |
3222 | case -NFS4ERR_OLD_STATEID: | 3264 | case -NFS4ERR_OLD_STATEID: |
3223 | if (nfs4_refresh_layout_stateid(&calldata->arg.lr_args->stateid, | 3265 | if (nfs4_layoutreturn_refresh_stateid(&calldata->arg.lr_args->stateid, |
3266 | &calldata->arg.lr_args->range, | ||
3224 | calldata->inode)) | 3267 | calldata->inode)) |
3225 | goto lr_restart; | 3268 | goto lr_restart; |
3226 | /* Fallthrough */ | 3269 | /* Fallthrough */ |
@@ -4236,7 +4279,8 @@ out: | |||
4236 | return status; | 4279 | return status; |
4237 | } | 4280 | } |
4238 | 4281 | ||
4239 | static int _nfs4_proc_remove(struct inode *dir, const struct qstr *name) | 4282 | static int |
4283 | _nfs4_proc_remove(struct inode *dir, const struct qstr *name, u32 ftype) | ||
4240 | { | 4284 | { |
4241 | struct nfs_server *server = NFS_SERVER(dir); | 4285 | struct nfs_server *server = NFS_SERVER(dir); |
4242 | struct nfs_removeargs args = { | 4286 | struct nfs_removeargs args = { |
@@ -4255,8 +4299,14 @@ static int _nfs4_proc_remove(struct inode *dir, const struct qstr *name) | |||
4255 | int status; | 4299 | int status; |
4256 | 4300 | ||
4257 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); | 4301 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); |
4258 | if (status == 0) | 4302 | if (status == 0) { |
4259 | update_changeattr(dir, &res.cinfo, timestamp); | 4303 | spin_lock(&dir->i_lock); |
4304 | update_changeattr_locked(dir, &res.cinfo, timestamp, 0); | ||
4305 | /* Removing a directory decrements nlink in the parent */ | ||
4306 | if (ftype == NF4DIR && dir->i_nlink > 2) | ||
4307 | nfs4_dec_nlink_locked(dir); | ||
4308 | spin_unlock(&dir->i_lock); | ||
4309 | } | ||
4260 | return status; | 4310 | return status; |
4261 | } | 4311 | } |
4262 | 4312 | ||
@@ -4273,7 +4323,7 @@ static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry) | |||
4273 | nfs4_inode_make_writeable(inode); | 4323 | nfs4_inode_make_writeable(inode); |
4274 | } | 4324 | } |
4275 | do { | 4325 | do { |
4276 | err = _nfs4_proc_remove(dir, &dentry->d_name); | 4326 | err = _nfs4_proc_remove(dir, &dentry->d_name, NF4REG); |
4277 | trace_nfs4_remove(dir, &dentry->d_name, err); | 4327 | trace_nfs4_remove(dir, &dentry->d_name, err); |
4278 | err = nfs4_handle_exception(NFS_SERVER(dir), err, | 4328 | err = nfs4_handle_exception(NFS_SERVER(dir), err, |
4279 | &exception); | 4329 | &exception); |
@@ -4287,7 +4337,7 @@ static int nfs4_proc_rmdir(struct inode *dir, const struct qstr *name) | |||
4287 | int err; | 4337 | int err; |
4288 | 4338 | ||
4289 | do { | 4339 | do { |
4290 | err = _nfs4_proc_remove(dir, name); | 4340 | err = _nfs4_proc_remove(dir, name, NF4DIR); |
4291 | trace_nfs4_remove(dir, name, err); | 4341 | trace_nfs4_remove(dir, name, err); |
4292 | err = nfs4_handle_exception(NFS_SERVER(dir), err, | 4342 | err = nfs4_handle_exception(NFS_SERVER(dir), err, |
4293 | &exception); | 4343 | &exception); |
@@ -4331,7 +4381,8 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
4331 | &data->timeout) == -EAGAIN) | 4381 | &data->timeout) == -EAGAIN) |
4332 | return 0; | 4382 | return 0; |
4333 | if (task->tk_status == 0) | 4383 | if (task->tk_status == 0) |
4334 | update_changeattr(dir, &res->cinfo, res->dir_attr->time_start); | 4384 | update_changeattr(dir, &res->cinfo, |
4385 | res->dir_attr->time_start, 0); | ||
4335 | return 1; | 4386 | return 1; |
4336 | } | 4387 | } |
4337 | 4388 | ||
@@ -4373,9 +4424,18 @@ static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir, | |||
4373 | return 0; | 4424 | return 0; |
4374 | 4425 | ||
4375 | if (task->tk_status == 0) { | 4426 | if (task->tk_status == 0) { |
4376 | update_changeattr(old_dir, &res->old_cinfo, res->old_fattr->time_start); | 4427 | if (new_dir != old_dir) { |
4377 | if (new_dir != old_dir) | 4428 | /* Note: If we moved a directory, nlink will change */ |
4378 | update_changeattr(new_dir, &res->new_cinfo, res->new_fattr->time_start); | 4429 | update_changeattr(old_dir, &res->old_cinfo, |
4430 | res->old_fattr->time_start, | ||
4431 | NFS_INO_INVALID_OTHER); | ||
4432 | update_changeattr(new_dir, &res->new_cinfo, | ||
4433 | res->new_fattr->time_start, | ||
4434 | NFS_INO_INVALID_OTHER); | ||
4435 | } else | ||
4436 | update_changeattr(old_dir, &res->old_cinfo, | ||
4437 | res->old_fattr->time_start, | ||
4438 | 0); | ||
4379 | } | 4439 | } |
4380 | return 1; | 4440 | return 1; |
4381 | } | 4441 | } |
@@ -4416,7 +4476,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct | |||
4416 | 4476 | ||
4417 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); | 4477 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
4418 | if (!status) { | 4478 | if (!status) { |
4419 | update_changeattr(dir, &res.cinfo, res.fattr->time_start); | 4479 | update_changeattr(dir, &res.cinfo, res.fattr->time_start, 0); |
4420 | status = nfs_post_op_update_inode(inode, res.fattr); | 4480 | status = nfs_post_op_update_inode(inode, res.fattr); |
4421 | if (!status) | 4481 | if (!status) |
4422 | nfs_setsecurity(inode, res.fattr, res.label); | 4482 | nfs_setsecurity(inode, res.fattr, res.label); |
@@ -4491,8 +4551,13 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_ | |||
4491 | int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg, | 4551 | int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg, |
4492 | &data->arg.seq_args, &data->res.seq_res, 1); | 4552 | &data->arg.seq_args, &data->res.seq_res, 1); |
4493 | if (status == 0) { | 4553 | if (status == 0) { |
4494 | update_changeattr(dir, &data->res.dir_cinfo, | 4554 | spin_lock(&dir->i_lock); |
4495 | data->res.fattr->time_start); | 4555 | update_changeattr_locked(dir, &data->res.dir_cinfo, |
4556 | data->res.fattr->time_start, 0); | ||
4557 | /* Creating a directory bumps nlink in the parent */ | ||
4558 | if (data->arg.ftype == NF4DIR) | ||
4559 | nfs4_inc_nlink_locked(dir); | ||
4560 | spin_unlock(&dir->i_lock); | ||
4496 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label); | 4561 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label); |
4497 | } | 4562 | } |
4498 | return status; | 4563 | return status; |
@@ -5073,6 +5138,40 @@ static void nfs4_proc_commit_setup(struct nfs_commit_data *data, struct rpc_mess | |||
5073 | nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_COMMIT, clnt, msg); | 5138 | nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_COMMIT, clnt, msg); |
5074 | } | 5139 | } |
5075 | 5140 | ||
5141 | static int _nfs4_proc_commit(struct file *dst, struct nfs_commitargs *args, | ||
5142 | struct nfs_commitres *res) | ||
5143 | { | ||
5144 | struct inode *dst_inode = file_inode(dst); | ||
5145 | struct nfs_server *server = NFS_SERVER(dst_inode); | ||
5146 | struct rpc_message msg = { | ||
5147 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT], | ||
5148 | .rpc_argp = args, | ||
5149 | .rpc_resp = res, | ||
5150 | }; | ||
5151 | |||
5152 | args->fh = NFS_FH(dst_inode); | ||
5153 | return nfs4_call_sync(server->client, server, &msg, | ||
5154 | &args->seq_args, &res->seq_res, 1); | ||
5155 | } | ||
5156 | |||
5157 | int nfs4_proc_commit(struct file *dst, __u64 offset, __u32 count, struct nfs_commitres *res) | ||
5158 | { | ||
5159 | struct nfs_commitargs args = { | ||
5160 | .offset = offset, | ||
5161 | .count = count, | ||
5162 | }; | ||
5163 | struct nfs_server *dst_server = NFS_SERVER(file_inode(dst)); | ||
5164 | struct nfs4_exception exception = { }; | ||
5165 | int status; | ||
5166 | |||
5167 | do { | ||
5168 | status = _nfs4_proc_commit(dst, &args, res); | ||
5169 | status = nfs4_handle_exception(dst_server, status, &exception); | ||
5170 | } while (exception.retry); | ||
5171 | |||
5172 | return status; | ||
5173 | } | ||
5174 | |||
5076 | struct nfs4_renewdata { | 5175 | struct nfs4_renewdata { |
5077 | struct nfs_client *client; | 5176 | struct nfs_client *client; |
5078 | unsigned long timestamp; | 5177 | unsigned long timestamp; |
@@ -5902,7 +6001,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
5902 | data->res.lr_res = NULL; | 6001 | data->res.lr_res = NULL; |
5903 | break; | 6002 | break; |
5904 | case -NFS4ERR_OLD_STATEID: | 6003 | case -NFS4ERR_OLD_STATEID: |
5905 | if (nfs4_refresh_layout_stateid(&data->args.lr_args->stateid, | 6004 | if (nfs4_layoutreturn_refresh_stateid(&data->args.lr_args->stateid, |
6005 | &data->args.lr_args->range, | ||
5906 | data->inode)) | 6006 | data->inode)) |
5907 | goto lr_restart; | 6007 | goto lr_restart; |
5908 | /* Fallthrough */ | 6008 | /* Fallthrough */ |
@@ -6209,11 +6309,13 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
6209 | if (nfs4_update_lock_stateid(calldata->lsp, | 6309 | if (nfs4_update_lock_stateid(calldata->lsp, |
6210 | &calldata->res.stateid)) | 6310 | &calldata->res.stateid)) |
6211 | break; | 6311 | break; |
6312 | /* Fall through */ | ||
6212 | case -NFS4ERR_ADMIN_REVOKED: | 6313 | case -NFS4ERR_ADMIN_REVOKED: |
6213 | case -NFS4ERR_EXPIRED: | 6314 | case -NFS4ERR_EXPIRED: |
6214 | nfs4_free_revoked_stateid(calldata->server, | 6315 | nfs4_free_revoked_stateid(calldata->server, |
6215 | &calldata->arg.stateid, | 6316 | &calldata->arg.stateid, |
6216 | task->tk_msg.rpc_cred); | 6317 | task->tk_msg.rpc_cred); |
6318 | /* Fall through */ | ||
6217 | case -NFS4ERR_BAD_STATEID: | 6319 | case -NFS4ERR_BAD_STATEID: |
6218 | case -NFS4ERR_OLD_STATEID: | 6320 | case -NFS4ERR_OLD_STATEID: |
6219 | case -NFS4ERR_STALE_STATEID: | 6321 | case -NFS4ERR_STALE_STATEID: |
@@ -7727,7 +7829,7 @@ static int nfs4_sp4_select_mode(struct nfs_client *clp, | |||
7727 | } | 7829 | } |
7728 | out: | 7830 | out: |
7729 | clp->cl_sp4_flags = flags; | 7831 | clp->cl_sp4_flags = flags; |
7730 | return 0; | 7832 | return ret; |
7731 | } | 7833 | } |
7732 | 7834 | ||
7733 | struct nfs41_exchange_id_data { | 7835 | struct nfs41_exchange_id_data { |
@@ -8168,7 +8270,7 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args, | |||
8168 | args->bc_attrs.max_resp_sz = max_bc_payload; | 8270 | args->bc_attrs.max_resp_sz = max_bc_payload; |
8169 | args->bc_attrs.max_resp_sz_cached = 0; | 8271 | args->bc_attrs.max_resp_sz_cached = 0; |
8170 | args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS; | 8272 | args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS; |
8171 | args->bc_attrs.max_reqs = min_t(unsigned short, max_session_cb_slots, 1); | 8273 | args->bc_attrs.max_reqs = max_t(unsigned short, max_session_cb_slots, 1); |
8172 | 8274 | ||
8173 | dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u " | 8275 | dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u " |
8174 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | 8276 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", |
@@ -8851,7 +8953,8 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) | |||
8851 | server = NFS_SERVER(lrp->args.inode); | 8953 | server = NFS_SERVER(lrp->args.inode); |
8852 | switch (task->tk_status) { | 8954 | switch (task->tk_status) { |
8853 | case -NFS4ERR_OLD_STATEID: | 8955 | case -NFS4ERR_OLD_STATEID: |
8854 | if (nfs4_refresh_layout_stateid(&lrp->args.stateid, | 8956 | if (nfs4_layoutreturn_refresh_stateid(&lrp->args.stateid, |
8957 | &lrp->args.range, | ||
8855 | lrp->args.inode)) | 8958 | lrp->args.inode)) |
8856 | goto out_restart; | 8959 | goto out_restart; |
8857 | /* Fallthrough */ | 8960 | /* Fallthrough */ |
@@ -9554,6 +9657,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { | |||
9554 | | NFS_CAP_LGOPEN | 9657 | | NFS_CAP_LGOPEN |
9555 | | NFS_CAP_ALLOCATE | 9658 | | NFS_CAP_ALLOCATE |
9556 | | NFS_CAP_COPY | 9659 | | NFS_CAP_COPY |
9660 | | NFS_CAP_OFFLOAD_CANCEL | ||
9557 | | NFS_CAP_DEALLOCATE | 9661 | | NFS_CAP_DEALLOCATE |
9558 | | NFS_CAP_SEEK | 9662 | | NFS_CAP_SEEK |
9559 | | NFS_CAP_LAYOUTSTATS | 9663 | | NFS_CAP_LAYOUTSTATS |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 2bf2eaa08ca7..3df0eb52da1c 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -274,7 +274,7 @@ static int nfs4_drain_slot_tbl(struct nfs4_slot_table *tbl) | |||
274 | static int nfs4_begin_drain_session(struct nfs_client *clp) | 274 | static int nfs4_begin_drain_session(struct nfs_client *clp) |
275 | { | 275 | { |
276 | struct nfs4_session *ses = clp->cl_session; | 276 | struct nfs4_session *ses = clp->cl_session; |
277 | int ret = 0; | 277 | int ret; |
278 | 278 | ||
279 | if (clp->cl_slot_tbl) | 279 | if (clp->cl_slot_tbl) |
280 | return nfs4_drain_slot_tbl(clp->cl_slot_tbl); | 280 | return nfs4_drain_slot_tbl(clp->cl_slot_tbl); |
@@ -1525,6 +1525,7 @@ restart: | |||
1525 | default: | 1525 | default: |
1526 | pr_err("NFS: %s: unhandled error %d\n", | 1526 | pr_err("NFS: %s: unhandled error %d\n", |
1527 | __func__, status); | 1527 | __func__, status); |
1528 | /* Fall through */ | ||
1528 | case -ENOMEM: | 1529 | case -ENOMEM: |
1529 | case -NFS4ERR_DENIED: | 1530 | case -NFS4ERR_DENIED: |
1530 | case -NFS4ERR_RECLAIM_BAD: | 1531 | case -NFS4ERR_RECLAIM_BAD: |
@@ -1588,6 +1589,22 @@ restart: | |||
1588 | } | 1589 | } |
1589 | clear_bit(NFS_STATE_RECLAIM_NOGRACE, | 1590 | clear_bit(NFS_STATE_RECLAIM_NOGRACE, |
1590 | &state->flags); | 1591 | &state->flags); |
1592 | #ifdef CONFIG_NFS_V4_2 | ||
1593 | if (test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags)) { | ||
1594 | struct nfs4_copy_state *copy; | ||
1595 | |||
1596 | spin_lock(&sp->so_server->nfs_client->cl_lock); | ||
1597 | list_for_each_entry(copy, &sp->so_server->ss_copies, copies) { | ||
1598 | if (memcmp(&state->stateid.other, ©->parent_state->stateid.other, NFS4_STATEID_SIZE)) | ||
1599 | continue; | ||
1600 | copy->flags = 1; | ||
1601 | complete(©->completion); | ||
1602 | printk("AGLO: server rebooted waking up the copy\n"); | ||
1603 | break; | ||
1604 | } | ||
1605 | spin_unlock(&sp->so_server->nfs_client->cl_lock); | ||
1606 | } | ||
1607 | #endif /* CONFIG_NFS_V4_2 */ | ||
1591 | nfs4_put_open_state(state); | 1608 | nfs4_put_open_state(state); |
1592 | spin_lock(&sp->so_lock); | 1609 | spin_lock(&sp->so_lock); |
1593 | goto restart; | 1610 | goto restart; |
@@ -1597,6 +1614,7 @@ restart: | |||
1597 | default: | 1614 | default: |
1598 | printk(KERN_ERR "NFS: %s: unhandled error %d\n", | 1615 | printk(KERN_ERR "NFS: %s: unhandled error %d\n", |
1599 | __func__, status); | 1616 | __func__, status); |
1617 | /* Fall through */ | ||
1600 | case -ENOENT: | 1618 | case -ENOENT: |
1601 | case -ENOMEM: | 1619 | case -ENOMEM: |
1602 | case -EACCES: | 1620 | case -EACCES: |
@@ -1608,6 +1626,7 @@ restart: | |||
1608 | break; | 1626 | break; |
1609 | case -EAGAIN: | 1627 | case -EAGAIN: |
1610 | ssleep(1); | 1628 | ssleep(1); |
1629 | /* Fall through */ | ||
1611 | case -NFS4ERR_ADMIN_REVOKED: | 1630 | case -NFS4ERR_ADMIN_REVOKED: |
1612 | case -NFS4ERR_STALE_STATEID: | 1631 | case -NFS4ERR_STALE_STATEID: |
1613 | case -NFS4ERR_OLD_STATEID: | 1632 | case -NFS4ERR_OLD_STATEID: |
@@ -1939,7 +1958,9 @@ static int nfs4_establish_lease(struct nfs_client *clp) | |||
1939 | clp->cl_mvops->reboot_recovery_ops; | 1958 | clp->cl_mvops->reboot_recovery_ops; |
1940 | int status; | 1959 | int status; |
1941 | 1960 | ||
1942 | nfs4_begin_drain_session(clp); | 1961 | status = nfs4_begin_drain_session(clp); |
1962 | if (status != 0) | ||
1963 | return status; | ||
1943 | cred = nfs4_get_clid_cred(clp); | 1964 | cred = nfs4_get_clid_cred(clp); |
1944 | if (cred == NULL) | 1965 | if (cred == NULL) |
1945 | return -ENOENT; | 1966 | return -ENOENT; |
@@ -2027,7 +2048,9 @@ static int nfs4_try_migration(struct nfs_server *server, struct rpc_cred *cred) | |||
2027 | goto out; | 2048 | goto out; |
2028 | } | 2049 | } |
2029 | 2050 | ||
2030 | nfs4_begin_drain_session(clp); | 2051 | status = nfs4_begin_drain_session(clp); |
2052 | if (status != 0) | ||
2053 | return status; | ||
2031 | 2054 | ||
2032 | status = nfs4_replace_transport(server, locations); | 2055 | status = nfs4_replace_transport(server, locations); |
2033 | if (status != 0) { | 2056 | if (status != 0) { |
@@ -2190,9 +2213,11 @@ again: | |||
2190 | case -ETIMEDOUT: | 2213 | case -ETIMEDOUT: |
2191 | if (clnt->cl_softrtry) | 2214 | if (clnt->cl_softrtry) |
2192 | break; | 2215 | break; |
2216 | /* Fall through */ | ||
2193 | case -NFS4ERR_DELAY: | 2217 | case -NFS4ERR_DELAY: |
2194 | case -EAGAIN: | 2218 | case -EAGAIN: |
2195 | ssleep(1); | 2219 | ssleep(1); |
2220 | /* Fall through */ | ||
2196 | case -NFS4ERR_STALE_CLIENTID: | 2221 | case -NFS4ERR_STALE_CLIENTID: |
2197 | dprintk("NFS: %s after status %d, retrying\n", | 2222 | dprintk("NFS: %s after status %d, retrying\n", |
2198 | __func__, status); | 2223 | __func__, status); |
@@ -2204,6 +2229,7 @@ again: | |||
2204 | } | 2229 | } |
2205 | if (clnt->cl_auth->au_flavor == RPC_AUTH_UNIX) | 2230 | if (clnt->cl_auth->au_flavor == RPC_AUTH_UNIX) |
2206 | break; | 2231 | break; |
2232 | /* Fall through */ | ||
2207 | case -NFS4ERR_CLID_INUSE: | 2233 | case -NFS4ERR_CLID_INUSE: |
2208 | case -NFS4ERR_WRONGSEC: | 2234 | case -NFS4ERR_WRONGSEC: |
2209 | /* No point in retrying if we already used RPC_AUTH_UNIX */ | 2235 | /* No point in retrying if we already used RPC_AUTH_UNIX */ |
@@ -2374,7 +2400,9 @@ static int nfs4_reset_session(struct nfs_client *clp) | |||
2374 | 2400 | ||
2375 | if (!nfs4_has_session(clp)) | 2401 | if (!nfs4_has_session(clp)) |
2376 | return 0; | 2402 | return 0; |
2377 | nfs4_begin_drain_session(clp); | 2403 | status = nfs4_begin_drain_session(clp); |
2404 | if (status != 0) | ||
2405 | return status; | ||
2378 | cred = nfs4_get_clid_cred(clp); | 2406 | cred = nfs4_get_clid_cred(clp); |
2379 | status = nfs4_proc_destroy_session(clp->cl_session, cred); | 2407 | status = nfs4_proc_destroy_session(clp->cl_session, cred); |
2380 | switch (status) { | 2408 | switch (status) { |
@@ -2417,7 +2445,9 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp) | |||
2417 | 2445 | ||
2418 | if (!nfs4_has_session(clp)) | 2446 | if (!nfs4_has_session(clp)) |
2419 | return 0; | 2447 | return 0; |
2420 | nfs4_begin_drain_session(clp); | 2448 | ret = nfs4_begin_drain_session(clp); |
2449 | if (ret != 0) | ||
2450 | return ret; | ||
2421 | cred = nfs4_get_clid_cred(clp); | 2451 | cred = nfs4_get_clid_cred(clp); |
2422 | ret = nfs4_proc_bind_conn_to_session(clp, cred); | 2452 | ret = nfs4_proc_bind_conn_to_session(clp, cred); |
2423 | if (cred) | 2453 | if (cred) |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index cd41d2577a04..b7bde12d8cd5 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -7789,6 +7789,7 @@ const struct rpc_procinfo nfs4_procedures[] = { | |||
7789 | PROC42(LAYOUTSTATS, enc_layoutstats, dec_layoutstats), | 7789 | PROC42(LAYOUTSTATS, enc_layoutstats, dec_layoutstats), |
7790 | PROC42(CLONE, enc_clone, dec_clone), | 7790 | PROC42(CLONE, enc_clone, dec_clone), |
7791 | PROC42(COPY, enc_copy, dec_copy), | 7791 | PROC42(COPY, enc_copy, dec_copy), |
7792 | PROC42(OFFLOAD_CANCEL, enc_offload_cancel, dec_offload_cancel), | ||
7792 | PROC(LOOKUPP, enc_lookupp, dec_lookupp), | 7793 | PROC(LOOKUPP, enc_lookupp, dec_lookupp), |
7793 | }; | 7794 | }; |
7794 | 7795 | ||
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 67d19cd92e44..bb5476a6d264 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -561,6 +561,7 @@ static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr, | |||
561 | case FLUSH_COND_STABLE: | 561 | case FLUSH_COND_STABLE: |
562 | if (nfs_reqs_to_commit(cinfo)) | 562 | if (nfs_reqs_to_commit(cinfo)) |
563 | break; | 563 | break; |
564 | /* fall through */ | ||
564 | default: | 565 | default: |
565 | hdr->args.stable = NFS_FILE_SYNC; | 566 | hdr->args.stable = NFS_FILE_SYNC; |
566 | } | 567 | } |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index bcc3addec3c5..e8f232de484f 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -361,18 +361,32 @@ pnfs_clear_lseg_state(struct pnfs_layout_segment *lseg, | |||
361 | /* | 361 | /* |
362 | * Update the seqid of a layout stateid | 362 | * Update the seqid of a layout stateid |
363 | */ | 363 | */ |
364 | bool nfs4_refresh_layout_stateid(nfs4_stateid *dst, struct inode *inode) | 364 | bool nfs4_layoutreturn_refresh_stateid(nfs4_stateid *dst, |
365 | struct pnfs_layout_range *dst_range, | ||
366 | struct inode *inode) | ||
365 | { | 367 | { |
366 | struct pnfs_layout_hdr *lo; | 368 | struct pnfs_layout_hdr *lo; |
369 | struct pnfs_layout_range range = { | ||
370 | .iomode = IOMODE_ANY, | ||
371 | .offset = 0, | ||
372 | .length = NFS4_MAX_UINT64, | ||
373 | }; | ||
367 | bool ret = false; | 374 | bool ret = false; |
375 | LIST_HEAD(head); | ||
376 | int err; | ||
368 | 377 | ||
369 | spin_lock(&inode->i_lock); | 378 | spin_lock(&inode->i_lock); |
370 | lo = NFS_I(inode)->layout; | 379 | lo = NFS_I(inode)->layout; |
371 | if (lo && nfs4_stateid_match_other(dst, &lo->plh_stateid)) { | 380 | if (lo && nfs4_stateid_match_other(dst, &lo->plh_stateid)) { |
372 | dst->seqid = lo->plh_stateid.seqid; | 381 | err = pnfs_mark_matching_lsegs_return(lo, &head, &range, 0); |
373 | ret = true; | 382 | if (err != -EBUSY) { |
383 | dst->seqid = lo->plh_stateid.seqid; | ||
384 | *dst_range = range; | ||
385 | ret = true; | ||
386 | } | ||
374 | } | 387 | } |
375 | spin_unlock(&inode->i_lock); | 388 | spin_unlock(&inode->i_lock); |
389 | pnfs_free_lseg_list(&head); | ||
376 | return ret; | 390 | return ret; |
377 | } | 391 | } |
378 | 392 | ||
@@ -1018,7 +1032,6 @@ pnfs_alloc_init_layoutget_args(struct inode *ino, | |||
1018 | nfs4_stateid_copy(&lgp->args.stateid, stateid); | 1032 | nfs4_stateid_copy(&lgp->args.stateid, stateid); |
1019 | lgp->gfp_flags = gfp_flags; | 1033 | lgp->gfp_flags = gfp_flags; |
1020 | lgp->cred = get_rpccred(ctx->cred); | 1034 | lgp->cred = get_rpccred(ctx->cred); |
1021 | lgp->callback_count = raw_seqcount_begin(&server->nfs_client->cl_callback_count); | ||
1022 | return lgp; | 1035 | return lgp; |
1023 | } | 1036 | } |
1024 | 1037 | ||
@@ -1160,12 +1173,21 @@ static bool | |||
1160 | pnfs_layout_need_return(struct pnfs_layout_hdr *lo) | 1173 | pnfs_layout_need_return(struct pnfs_layout_hdr *lo) |
1161 | { | 1174 | { |
1162 | struct pnfs_layout_segment *s; | 1175 | struct pnfs_layout_segment *s; |
1176 | enum pnfs_iomode iomode; | ||
1177 | u32 seq; | ||
1163 | 1178 | ||
1164 | if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags)) | 1179 | if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags)) |
1165 | return false; | 1180 | return false; |
1166 | 1181 | ||
1167 | /* Defer layoutreturn until all lsegs are done */ | 1182 | seq = lo->plh_return_seq; |
1183 | iomode = lo->plh_return_iomode; | ||
1184 | |||
1185 | /* Defer layoutreturn until all recalled lsegs are done */ | ||
1168 | list_for_each_entry(s, &lo->plh_segs, pls_list) { | 1186 | list_for_each_entry(s, &lo->plh_segs, pls_list) { |
1187 | if (seq && pnfs_seqid_is_newer(s->pls_seq, seq)) | ||
1188 | continue; | ||
1189 | if (iomode != IOMODE_ANY && s->pls_range.iomode != iomode) | ||
1190 | continue; | ||
1169 | if (test_bit(NFS_LSEG_LAYOUTRETURN, &s->pls_flags)) | 1191 | if (test_bit(NFS_LSEG_LAYOUTRETURN, &s->pls_flags)) |
1170 | return false; | 1192 | return false; |
1171 | } | 1193 | } |
@@ -1609,7 +1631,7 @@ pnfs_lseg_range_match(const struct pnfs_layout_range *ls_range, | |||
1609 | (range->iomode != ls_range->iomode && | 1631 | (range->iomode != ls_range->iomode && |
1610 | strict_iomode) || | 1632 | strict_iomode) || |
1611 | !pnfs_lseg_range_intersecting(ls_range, range)) | 1633 | !pnfs_lseg_range_intersecting(ls_range, range)) |
1612 | return 0; | 1634 | return false; |
1613 | 1635 | ||
1614 | /* range1 covers only the first byte in the range */ | 1636 | /* range1 covers only the first byte in the range */ |
1615 | range1 = *range; | 1637 | range1 = *range; |
@@ -1631,7 +1653,6 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, | |||
1631 | 1653 | ||
1632 | list_for_each_entry(lseg, &lo->plh_segs, pls_list) { | 1654 | list_for_each_entry(lseg, &lo->plh_segs, pls_list) { |
1633 | if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) && | 1655 | if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) && |
1634 | !test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags) && | ||
1635 | pnfs_lseg_range_match(&lseg->pls_range, range, | 1656 | pnfs_lseg_range_match(&lseg->pls_range, range, |
1636 | strict_iomode)) { | 1657 | strict_iomode)) { |
1637 | ret = pnfs_get_lseg(lseg); | 1658 | ret = pnfs_get_lseg(lseg); |
@@ -1731,6 +1752,17 @@ static bool pnfs_prepare_to_retry_layoutget(struct pnfs_layout_hdr *lo) | |||
1731 | TASK_UNINTERRUPTIBLE); | 1752 | TASK_UNINTERRUPTIBLE); |
1732 | } | 1753 | } |
1733 | 1754 | ||
1755 | static void nfs_layoutget_begin(struct pnfs_layout_hdr *lo) | ||
1756 | { | ||
1757 | atomic_inc(&lo->plh_outstanding); | ||
1758 | } | ||
1759 | |||
1760 | static void nfs_layoutget_end(struct pnfs_layout_hdr *lo) | ||
1761 | { | ||
1762 | if (atomic_dec_and_test(&lo->plh_outstanding)) | ||
1763 | wake_up_var(&lo->plh_outstanding); | ||
1764 | } | ||
1765 | |||
1734 | static void pnfs_clear_first_layoutget(struct pnfs_layout_hdr *lo) | 1766 | static void pnfs_clear_first_layoutget(struct pnfs_layout_hdr *lo) |
1735 | { | 1767 | { |
1736 | unsigned long *bitlock = &lo->plh_flags; | 1768 | unsigned long *bitlock = &lo->plh_flags; |
@@ -1791,12 +1823,6 @@ pnfs_update_layout(struct inode *ino, | |||
1791 | goto out; | 1823 | goto out; |
1792 | } | 1824 | } |
1793 | 1825 | ||
1794 | if (iomode == IOMODE_READ && i_size_read(ino) == 0) { | ||
1795 | trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg, | ||
1796 | PNFS_UPDATE_LAYOUT_RD_ZEROLEN); | ||
1797 | goto out; | ||
1798 | } | ||
1799 | |||
1800 | if (pnfs_within_mdsthreshold(ctx, ino, iomode)) { | 1826 | if (pnfs_within_mdsthreshold(ctx, ino, iomode)) { |
1801 | trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg, | 1827 | trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg, |
1802 | PNFS_UPDATE_LAYOUT_MDSTHRESH); | 1828 | PNFS_UPDATE_LAYOUT_MDSTHRESH); |
@@ -1830,6 +1856,21 @@ lookup_again: | |||
1830 | goto out_unlock; | 1856 | goto out_unlock; |
1831 | } | 1857 | } |
1832 | 1858 | ||
1859 | /* | ||
1860 | * If the layout segment list is empty, but there are outstanding | ||
1861 | * layoutget calls, then they might be subject to a layoutrecall. | ||
1862 | */ | ||
1863 | if (list_empty(&lo->plh_segs) && | ||
1864 | atomic_read(&lo->plh_outstanding) != 0) { | ||
1865 | spin_unlock(&ino->i_lock); | ||
1866 | if (wait_var_event_killable(&lo->plh_outstanding, | ||
1867 | atomic_read(&lo->plh_outstanding) == 0 | ||
1868 | || !list_empty(&lo->plh_segs))) | ||
1869 | goto out_put_layout_hdr; | ||
1870 | pnfs_put_layout_hdr(lo); | ||
1871 | goto lookup_again; | ||
1872 | } | ||
1873 | |||
1833 | lseg = pnfs_find_lseg(lo, &arg, strict_iomode); | 1874 | lseg = pnfs_find_lseg(lo, &arg, strict_iomode); |
1834 | if (lseg) { | 1875 | if (lseg) { |
1835 | trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg, | 1876 | trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg, |
@@ -1903,7 +1944,7 @@ lookup_again: | |||
1903 | PNFS_UPDATE_LAYOUT_BLOCKED); | 1944 | PNFS_UPDATE_LAYOUT_BLOCKED); |
1904 | goto out_unlock; | 1945 | goto out_unlock; |
1905 | } | 1946 | } |
1906 | atomic_inc(&lo->plh_outstanding); | 1947 | nfs_layoutget_begin(lo); |
1907 | spin_unlock(&ino->i_lock); | 1948 | spin_unlock(&ino->i_lock); |
1908 | 1949 | ||
1909 | _add_to_server_list(lo, server); | 1950 | _add_to_server_list(lo, server); |
@@ -1920,14 +1961,14 @@ lookup_again: | |||
1920 | if (!lgp) { | 1961 | if (!lgp) { |
1921 | trace_pnfs_update_layout(ino, pos, count, iomode, lo, NULL, | 1962 | trace_pnfs_update_layout(ino, pos, count, iomode, lo, NULL, |
1922 | PNFS_UPDATE_LAYOUT_NOMEM); | 1963 | PNFS_UPDATE_LAYOUT_NOMEM); |
1923 | atomic_dec(&lo->plh_outstanding); | 1964 | nfs_layoutget_end(lo); |
1924 | goto out_put_layout_hdr; | 1965 | goto out_put_layout_hdr; |
1925 | } | 1966 | } |
1926 | 1967 | ||
1927 | lseg = nfs4_proc_layoutget(lgp, &timeout); | 1968 | lseg = nfs4_proc_layoutget(lgp, &timeout); |
1928 | trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg, | 1969 | trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg, |
1929 | PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET); | 1970 | PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET); |
1930 | atomic_dec(&lo->plh_outstanding); | 1971 | nfs_layoutget_end(lo); |
1931 | if (IS_ERR(lseg)) { | 1972 | if (IS_ERR(lseg)) { |
1932 | switch(PTR_ERR(lseg)) { | 1973 | switch(PTR_ERR(lseg)) { |
1933 | case -EBUSY: | 1974 | case -EBUSY: |
@@ -1935,15 +1976,6 @@ lookup_again: | |||
1935 | lseg = NULL; | 1976 | lseg = NULL; |
1936 | break; | 1977 | break; |
1937 | case -ERECALLCONFLICT: | 1978 | case -ERECALLCONFLICT: |
1938 | /* Huh? We hold no layouts, how is there a recall? */ | ||
1939 | if (first) { | ||
1940 | lseg = NULL; | ||
1941 | break; | ||
1942 | } | ||
1943 | /* Destroy the existing layout and start over */ | ||
1944 | if (time_after(jiffies, giveup)) | ||
1945 | pnfs_destroy_layout(NFS_I(ino)); | ||
1946 | /* Fallthrough */ | ||
1947 | case -EAGAIN: | 1979 | case -EAGAIN: |
1948 | break; | 1980 | break; |
1949 | default: | 1981 | default: |
@@ -2022,7 +2054,7 @@ _pnfs_grab_empty_layout(struct inode *ino, struct nfs_open_context *ctx) | |||
2022 | goto out_unlock; | 2054 | goto out_unlock; |
2023 | if (test_and_set_bit(NFS_LAYOUT_FIRST_LAYOUTGET, &lo->plh_flags)) | 2055 | if (test_and_set_bit(NFS_LAYOUT_FIRST_LAYOUTGET, &lo->plh_flags)) |
2024 | goto out_unlock; | 2056 | goto out_unlock; |
2025 | atomic_inc(&lo->plh_outstanding); | 2057 | nfs_layoutget_begin(lo); |
2026 | spin_unlock(&ino->i_lock); | 2058 | spin_unlock(&ino->i_lock); |
2027 | _add_to_server_list(lo, NFS_SERVER(ino)); | 2059 | _add_to_server_list(lo, NFS_SERVER(ino)); |
2028 | return lo; | 2060 | return lo; |
@@ -2146,9 +2178,6 @@ void pnfs_parse_lgopen(struct inode *ino, struct nfs4_layoutget *lgp, | |||
2146 | } else | 2178 | } else |
2147 | lo = NFS_I(lgp->args.inode)->layout; | 2179 | lo = NFS_I(lgp->args.inode)->layout; |
2148 | 2180 | ||
2149 | if (read_seqcount_retry(&srv->nfs_client->cl_callback_count, | ||
2150 | lgp->callback_count)) | ||
2151 | return; | ||
2152 | lseg = pnfs_layout_process(lgp); | 2181 | lseg = pnfs_layout_process(lgp); |
2153 | if (!IS_ERR(lseg)) { | 2182 | if (!IS_ERR(lseg)) { |
2154 | iomode = lgp->args.range.iomode; | 2183 | iomode = lgp->args.range.iomode; |
@@ -2163,8 +2192,8 @@ void nfs4_lgopen_release(struct nfs4_layoutget *lgp) | |||
2163 | struct inode *inode = lgp->args.inode; | 2192 | struct inode *inode = lgp->args.inode; |
2164 | if (inode) { | 2193 | if (inode) { |
2165 | struct pnfs_layout_hdr *lo = NFS_I(inode)->layout; | 2194 | struct pnfs_layout_hdr *lo = NFS_I(inode)->layout; |
2166 | atomic_dec(&lo->plh_outstanding); | ||
2167 | pnfs_clear_first_layoutget(lo); | 2195 | pnfs_clear_first_layoutget(lo); |
2196 | nfs_layoutget_end(lo); | ||
2168 | } | 2197 | } |
2169 | pnfs_layoutget_free(lgp); | 2198 | pnfs_layoutget_free(lgp); |
2170 | } | 2199 | } |
@@ -2238,15 +2267,31 @@ out_forget: | |||
2238 | return ERR_PTR(-EAGAIN); | 2267 | return ERR_PTR(-EAGAIN); |
2239 | } | 2268 | } |
2240 | 2269 | ||
2270 | static int | ||
2271 | mark_lseg_invalid_or_return(struct pnfs_layout_segment *lseg, | ||
2272 | struct list_head *tmp_list) | ||
2273 | { | ||
2274 | if (!mark_lseg_invalid(lseg, tmp_list)) | ||
2275 | return 0; | ||
2276 | pnfs_cache_lseg_for_layoutreturn(lseg->pls_layout, lseg); | ||
2277 | return 1; | ||
2278 | } | ||
2279 | |||
2241 | /** | 2280 | /** |
2242 | * pnfs_mark_matching_lsegs_return - Free or return matching layout segments | 2281 | * pnfs_mark_matching_lsegs_return - Free or return matching layout segments |
2243 | * @lo: pointer to layout header | 2282 | * @lo: pointer to layout header |
2244 | * @tmp_list: list header to be used with pnfs_free_lseg_list() | 2283 | * @tmp_list: list header to be used with pnfs_free_lseg_list() |
2245 | * @return_range: describe layout segment ranges to be returned | 2284 | * @return_range: describe layout segment ranges to be returned |
2285 | * @seq: stateid seqid to match | ||
2246 | * | 2286 | * |
2247 | * This function is mainly intended for use by layoutrecall. It attempts | 2287 | * This function is mainly intended for use by layoutrecall. It attempts |
2248 | * to free the layout segment immediately, or else to mark it for return | 2288 | * to free the layout segment immediately, or else to mark it for return |
2249 | * as soon as its reference count drops to zero. | 2289 | * as soon as its reference count drops to zero. |
2290 | * | ||
2291 | * Returns | ||
2292 | * - 0: a layoutreturn needs to be scheduled. | ||
2293 | * - EBUSY: there are layout segment that are still in use. | ||
2294 | * - ENOENT: there are no layout segments that need to be returned. | ||
2250 | */ | 2295 | */ |
2251 | int | 2296 | int |
2252 | pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, | 2297 | pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, |
@@ -2259,9 +2304,6 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, | |||
2259 | 2304 | ||
2260 | dprintk("%s:Begin lo %p\n", __func__, lo); | 2305 | dprintk("%s:Begin lo %p\n", __func__, lo); |
2261 | 2306 | ||
2262 | if (list_empty(&lo->plh_segs)) | ||
2263 | return 0; | ||
2264 | |||
2265 | assert_spin_locked(&lo->plh_inode->i_lock); | 2307 | assert_spin_locked(&lo->plh_inode->i_lock); |
2266 | 2308 | ||
2267 | list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) | 2309 | list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) |
@@ -2271,16 +2313,23 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, | |||
2271 | lseg, lseg->pls_range.iomode, | 2313 | lseg, lseg->pls_range.iomode, |
2272 | lseg->pls_range.offset, | 2314 | lseg->pls_range.offset, |
2273 | lseg->pls_range.length); | 2315 | lseg->pls_range.length); |
2274 | if (mark_lseg_invalid(lseg, tmp_list)) | 2316 | if (mark_lseg_invalid_or_return(lseg, tmp_list)) |
2275 | continue; | 2317 | continue; |
2276 | remaining++; | 2318 | remaining++; |
2277 | set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags); | 2319 | set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags); |
2278 | } | 2320 | } |
2279 | 2321 | ||
2280 | if (remaining) | 2322 | if (remaining) { |
2281 | pnfs_set_plh_return_info(lo, return_range->iomode, seq); | 2323 | pnfs_set_plh_return_info(lo, return_range->iomode, seq); |
2324 | return -EBUSY; | ||
2325 | } | ||
2282 | 2326 | ||
2283 | return remaining; | 2327 | if (!list_empty(&lo->plh_return_segs)) { |
2328 | pnfs_set_plh_return_info(lo, return_range->iomode, seq); | ||
2329 | return 0; | ||
2330 | } | ||
2331 | |||
2332 | return -ENOENT; | ||
2284 | } | 2333 | } |
2285 | 2334 | ||
2286 | void pnfs_error_mark_layout_for_return(struct inode *inode, | 2335 | void pnfs_error_mark_layout_for_return(struct inode *inode, |
@@ -2305,7 +2354,7 @@ void pnfs_error_mark_layout_for_return(struct inode *inode, | |||
2305 | * segments at hand when sending layoutreturn. See pnfs_put_lseg() | 2354 | * segments at hand when sending layoutreturn. See pnfs_put_lseg() |
2306 | * for how it works. | 2355 | * for how it works. |
2307 | */ | 2356 | */ |
2308 | if (!pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs, &range, 0)) { | 2357 | if (pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs, &range, 0) != -EBUSY) { |
2309 | nfs4_stateid stateid; | 2358 | nfs4_stateid stateid; |
2310 | enum pnfs_iomode iomode; | 2359 | enum pnfs_iomode iomode; |
2311 | 2360 | ||
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 3fe81424337d..ece367ebde69 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -259,7 +259,9 @@ int pnfs_destroy_layouts_byfsid(struct nfs_client *clp, | |||
259 | bool is_recall); | 259 | bool is_recall); |
260 | int pnfs_destroy_layouts_byclid(struct nfs_client *clp, | 260 | int pnfs_destroy_layouts_byclid(struct nfs_client *clp, |
261 | bool is_recall); | 261 | bool is_recall); |
262 | bool nfs4_refresh_layout_stateid(nfs4_stateid *dst, struct inode *inode); | 262 | bool nfs4_layoutreturn_refresh_stateid(nfs4_stateid *dst, |
263 | struct pnfs_layout_range *dst_range, | ||
264 | struct inode *inode); | ||
263 | void pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo); | 265 | void pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo); |
264 | void pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, | 266 | void pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, |
265 | const nfs4_stateid *new, | 267 | const nfs4_stateid *new, |
@@ -780,7 +782,8 @@ static inline void nfs4_pnfs_v3_ds_connect_unload(void) | |||
780 | { | 782 | { |
781 | } | 783 | } |
782 | 784 | ||
783 | static inline bool nfs4_refresh_layout_stateid(nfs4_stateid *dst, | 785 | static inline bool nfs4_layoutreturn_refresh_stateid(nfs4_stateid *dst, |
786 | struct pnfs_layout_range *dst_range, | ||
784 | struct inode *inode) | 787 | struct inode *inode) |
785 | { | 788 | { |
786 | return false; | 789 | return false; |
diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c index 32ba2d471853..d5e4d3cd8c7f 100644 --- a/fs/nfs/pnfs_nfs.c +++ b/fs/nfs/pnfs_nfs.c | |||
@@ -61,7 +61,7 @@ EXPORT_SYMBOL_GPL(pnfs_generic_commit_release); | |||
61 | 61 | ||
62 | /* The generic layer is about to remove the req from the commit list. | 62 | /* The generic layer is about to remove the req from the commit list. |
63 | * If this will make the bucket empty, it will need to put the lseg reference. | 63 | * If this will make the bucket empty, it will need to put the lseg reference. |
64 | * Note this must be called holding i_lock | 64 | * Note this must be called holding nfsi->commit_mutex |
65 | */ | 65 | */ |
66 | void | 66 | void |
67 | pnfs_generic_clear_request_commit(struct nfs_page *req, | 67 | pnfs_generic_clear_request_commit(struct nfs_page *req, |
@@ -149,9 +149,7 @@ restart: | |||
149 | if (list_empty(&b->written)) { | 149 | if (list_empty(&b->written)) { |
150 | freeme = b->wlseg; | 150 | freeme = b->wlseg; |
151 | b->wlseg = NULL; | 151 | b->wlseg = NULL; |
152 | spin_unlock(&cinfo->inode->i_lock); | ||
153 | pnfs_put_lseg(freeme); | 152 | pnfs_put_lseg(freeme); |
154 | spin_lock(&cinfo->inode->i_lock); | ||
155 | goto restart; | 153 | goto restart; |
156 | } | 154 | } |
157 | } | 155 | } |
@@ -167,7 +165,7 @@ static void pnfs_generic_retry_commit(struct nfs_commit_info *cinfo, int idx) | |||
167 | LIST_HEAD(pages); | 165 | LIST_HEAD(pages); |
168 | int i; | 166 | int i; |
169 | 167 | ||
170 | spin_lock(&cinfo->inode->i_lock); | 168 | mutex_lock(&NFS_I(cinfo->inode)->commit_mutex); |
171 | for (i = idx; i < fl_cinfo->nbuckets; i++) { | 169 | for (i = idx; i < fl_cinfo->nbuckets; i++) { |
172 | bucket = &fl_cinfo->buckets[i]; | 170 | bucket = &fl_cinfo->buckets[i]; |
173 | if (list_empty(&bucket->committing)) | 171 | if (list_empty(&bucket->committing)) |
@@ -177,12 +175,12 @@ static void pnfs_generic_retry_commit(struct nfs_commit_info *cinfo, int idx) | |||
177 | list_for_each(pos, &bucket->committing) | 175 | list_for_each(pos, &bucket->committing) |
178 | cinfo->ds->ncommitting--; | 176 | cinfo->ds->ncommitting--; |
179 | list_splice_init(&bucket->committing, &pages); | 177 | list_splice_init(&bucket->committing, &pages); |
180 | spin_unlock(&cinfo->inode->i_lock); | 178 | mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex); |
181 | nfs_retry_commit(&pages, freeme, cinfo, i); | 179 | nfs_retry_commit(&pages, freeme, cinfo, i); |
182 | pnfs_put_lseg(freeme); | 180 | pnfs_put_lseg(freeme); |
183 | spin_lock(&cinfo->inode->i_lock); | 181 | mutex_lock(&NFS_I(cinfo->inode)->commit_mutex); |
184 | } | 182 | } |
185 | spin_unlock(&cinfo->inode->i_lock); | 183 | mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex); |
186 | } | 184 | } |
187 | 185 | ||
188 | static unsigned int | 186 | static unsigned int |
@@ -222,13 +220,13 @@ void pnfs_fetch_commit_bucket_list(struct list_head *pages, | |||
222 | struct list_head *pos; | 220 | struct list_head *pos; |
223 | 221 | ||
224 | bucket = &cinfo->ds->buckets[data->ds_commit_index]; | 222 | bucket = &cinfo->ds->buckets[data->ds_commit_index]; |
225 | spin_lock(&cinfo->inode->i_lock); | 223 | mutex_lock(&NFS_I(cinfo->inode)->commit_mutex); |
226 | list_for_each(pos, &bucket->committing) | 224 | list_for_each(pos, &bucket->committing) |
227 | cinfo->ds->ncommitting--; | 225 | cinfo->ds->ncommitting--; |
228 | list_splice_init(&bucket->committing, pages); | 226 | list_splice_init(&bucket->committing, pages); |
229 | data->lseg = bucket->clseg; | 227 | data->lseg = bucket->clseg; |
230 | bucket->clseg = NULL; | 228 | bucket->clseg = NULL; |
231 | spin_unlock(&cinfo->inode->i_lock); | 229 | mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex); |
232 | 230 | ||
233 | } | 231 | } |
234 | 232 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 5e470e233c83..ac4b2f005778 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -884,7 +884,7 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root) | |||
884 | #endif | 884 | #endif |
885 | seq_printf(m, "\n"); | 885 | seq_printf(m, "\n"); |
886 | 886 | ||
887 | rpc_print_iostats(m, nfss->client); | 887 | rpc_clnt_show_stats(m, nfss->client); |
888 | 888 | ||
889 | return 0; | 889 | return 0; |
890 | } | 890 | } |
@@ -2899,7 +2899,7 @@ static int param_set_portnr(const char *val, const struct kernel_param *kp) | |||
2899 | if (!val) | 2899 | if (!val) |
2900 | return -EINVAL; | 2900 | return -EINVAL; |
2901 | ret = kstrtoul(val, 0, &num); | 2901 | ret = kstrtoul(val, 0, &num); |
2902 | if (ret == -EINVAL || num > NFS_CALLBACK_MAXPORTNR) | 2902 | if (ret || num > NFS_CALLBACK_MAXPORTNR) |
2903 | return -EINVAL; | 2903 | return -EINVAL; |
2904 | *((unsigned int *)kp->arg) = num; | 2904 | *((unsigned int *)kp->arg) = num; |
2905 | return 0; | 2905 | return 0; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index a057b4f45a46..586726a590d8 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1406,6 +1406,8 @@ static void nfs_async_write_error(struct list_head *head) | |||
1406 | static void nfs_async_write_reschedule_io(struct nfs_pgio_header *hdr) | 1406 | static void nfs_async_write_reschedule_io(struct nfs_pgio_header *hdr) |
1407 | { | 1407 | { |
1408 | nfs_async_write_error(&hdr->pages); | 1408 | nfs_async_write_error(&hdr->pages); |
1409 | filemap_fdatawrite_range(hdr->inode->i_mapping, hdr->args.offset, | ||
1410 | hdr->args.offset + hdr->args.count - 1); | ||
1409 | } | 1411 | } |
1410 | 1412 | ||
1411 | static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops = { | 1413 | static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops = { |
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 0877ed333733..1b06f0b28453 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h | |||
@@ -535,6 +535,7 @@ enum { | |||
535 | NFSPROC4_CLNT_LAYOUTSTATS, | 535 | NFSPROC4_CLNT_LAYOUTSTATS, |
536 | NFSPROC4_CLNT_CLONE, | 536 | NFSPROC4_CLNT_CLONE, |
537 | NFSPROC4_CLNT_COPY, | 537 | NFSPROC4_CLNT_COPY, |
538 | NFSPROC4_CLNT_OFFLOAD_CANCEL, | ||
538 | 539 | ||
539 | NFSPROC4_CLNT_LOOKUPP, | 540 | NFSPROC4_CLNT_LOOKUPP, |
540 | }; | 541 | }; |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 2f129bbfaae8..a0831e9d19c9 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -185,6 +185,17 @@ struct nfs_inode { | |||
185 | struct inode vfs_inode; | 185 | struct inode vfs_inode; |
186 | }; | 186 | }; |
187 | 187 | ||
188 | struct nfs4_copy_state { | ||
189 | struct list_head copies; | ||
190 | nfs4_stateid stateid; | ||
191 | struct completion completion; | ||
192 | uint64_t count; | ||
193 | struct nfs_writeverf verf; | ||
194 | int error; | ||
195 | int flags; | ||
196 | struct nfs4_state *parent_state; | ||
197 | }; | ||
198 | |||
188 | /* | 199 | /* |
189 | * Access bit flags | 200 | * Access bit flags |
190 | */ | 201 | */ |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 74ae3e1d19a0..bf39d9c92201 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
@@ -28,7 +28,6 @@ struct nfs41_impl_id; | |||
28 | struct nfs_client { | 28 | struct nfs_client { |
29 | refcount_t cl_count; | 29 | refcount_t cl_count; |
30 | atomic_t cl_mds_count; | 30 | atomic_t cl_mds_count; |
31 | seqcount_t cl_callback_count; | ||
32 | int cl_cons_state; /* current construction state (-ve: init error) */ | 31 | int cl_cons_state; /* current construction state (-ve: init error) */ |
33 | #define NFS_CS_READY 0 /* ready to be used */ | 32 | #define NFS_CS_READY 0 /* ready to be used */ |
34 | #define NFS_CS_INITING 1 /* busy initialising */ | 33 | #define NFS_CS_INITING 1 /* busy initialising */ |
@@ -122,6 +121,7 @@ struct nfs_client { | |||
122 | #endif | 121 | #endif |
123 | 122 | ||
124 | struct net *cl_net; | 123 | struct net *cl_net; |
124 | struct list_head pending_cb_stateids; | ||
125 | }; | 125 | }; |
126 | 126 | ||
127 | /* | 127 | /* |
@@ -209,6 +209,7 @@ struct nfs_server { | |||
209 | struct list_head state_owners_lru; | 209 | struct list_head state_owners_lru; |
210 | struct list_head layouts; | 210 | struct list_head layouts; |
211 | struct list_head delegations; | 211 | struct list_head delegations; |
212 | struct list_head ss_copies; | ||
212 | 213 | ||
213 | unsigned long mig_gen; | 214 | unsigned long mig_gen; |
214 | unsigned long mig_status; | 215 | unsigned long mig_status; |
@@ -256,5 +257,6 @@ struct nfs_server { | |||
256 | #define NFS_CAP_LAYOUTSTATS (1U << 22) | 257 | #define NFS_CAP_LAYOUTSTATS (1U << 22) |
257 | #define NFS_CAP_CLONE (1U << 23) | 258 | #define NFS_CAP_CLONE (1U << 23) |
258 | #define NFS_CAP_COPY (1U << 24) | 259 | #define NFS_CAP_COPY (1U << 24) |
260 | #define NFS_CAP_OFFLOAD_CANCEL (1U << 25) | ||
259 | 261 | ||
260 | #endif | 262 | #endif |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 712eed156d09..bd1c889a9ed9 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -271,7 +271,6 @@ struct nfs4_layoutget { | |||
271 | struct nfs4_layoutget_args args; | 271 | struct nfs4_layoutget_args args; |
272 | struct nfs4_layoutget_res res; | 272 | struct nfs4_layoutget_res res; |
273 | struct rpc_cred *cred; | 273 | struct rpc_cred *cred; |
274 | unsigned callback_count; | ||
275 | gfp_t gfp_flags; | 274 | gfp_t gfp_flags; |
276 | }; | 275 | }; |
277 | 276 | ||
@@ -1389,9 +1388,11 @@ struct nfs42_copy_args { | |||
1389 | u64 dst_pos; | 1388 | u64 dst_pos; |
1390 | 1389 | ||
1391 | u64 count; | 1390 | u64 count; |
1391 | bool sync; | ||
1392 | }; | 1392 | }; |
1393 | 1393 | ||
1394 | struct nfs42_write_res { | 1394 | struct nfs42_write_res { |
1395 | nfs4_stateid stateid; | ||
1395 | u64 count; | 1396 | u64 count; |
1396 | struct nfs_writeverf verifier; | 1397 | struct nfs_writeverf verifier; |
1397 | }; | 1398 | }; |
@@ -1404,6 +1405,18 @@ struct nfs42_copy_res { | |||
1404 | struct nfs_commitres commit_res; | 1405 | struct nfs_commitres commit_res; |
1405 | }; | 1406 | }; |
1406 | 1407 | ||
1408 | struct nfs42_offload_status_args { | ||
1409 | struct nfs4_sequence_args osa_seq_args; | ||
1410 | struct nfs_fh *osa_src_fh; | ||
1411 | nfs4_stateid osa_stateid; | ||
1412 | }; | ||
1413 | |||
1414 | struct nfs42_offload_status_res { | ||
1415 | struct nfs4_sequence_res osr_seq_res; | ||
1416 | uint64_t osr_count; | ||
1417 | int osr_status; | ||
1418 | }; | ||
1419 | |||
1407 | struct nfs42_seek_args { | 1420 | struct nfs42_seek_args { |
1408 | struct nfs4_sequence_args seq_args; | 1421 | struct nfs4_sequence_args seq_args; |
1409 | 1422 | ||
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index d9af474a857d..58a6765c1c5e 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h | |||
@@ -125,7 +125,8 @@ struct rpc_authops { | |||
125 | struct module *owner; | 125 | struct module *owner; |
126 | rpc_authflavor_t au_flavor; /* flavor (RPC_AUTH_*) */ | 126 | rpc_authflavor_t au_flavor; /* flavor (RPC_AUTH_*) */ |
127 | char * au_name; | 127 | char * au_name; |
128 | struct rpc_auth * (*create)(struct rpc_auth_create_args *, struct rpc_clnt *); | 128 | struct rpc_auth * (*create)(const struct rpc_auth_create_args *, |
129 | struct rpc_clnt *); | ||
129 | void (*destroy)(struct rpc_auth *); | 130 | void (*destroy)(struct rpc_auth *); |
130 | 131 | ||
131 | int (*hash_cred)(struct auth_cred *, unsigned int); | 132 | int (*hash_cred)(struct auth_cred *, unsigned int); |
@@ -174,7 +175,7 @@ struct rpc_cred * rpc_lookup_generic_cred(struct auth_cred *, int, gfp_t); | |||
174 | struct rpc_cred * rpc_lookup_machine_cred(const char *service_name); | 175 | struct rpc_cred * rpc_lookup_machine_cred(const char *service_name); |
175 | int rpcauth_register(const struct rpc_authops *); | 176 | int rpcauth_register(const struct rpc_authops *); |
176 | int rpcauth_unregister(const struct rpc_authops *); | 177 | int rpcauth_unregister(const struct rpc_authops *); |
177 | struct rpc_auth * rpcauth_create(struct rpc_auth_create_args *, | 178 | struct rpc_auth * rpcauth_create(const struct rpc_auth_create_args *, |
178 | struct rpc_clnt *); | 179 | struct rpc_clnt *); |
179 | void rpcauth_release(struct rpc_auth *); | 180 | void rpcauth_release(struct rpc_auth *); |
180 | rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t, | 181 | rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t, |
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 9b11b6a0978c..73d5c4a870fa 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
@@ -156,6 +156,7 @@ int rpc_switch_client_transport(struct rpc_clnt *, | |||
156 | 156 | ||
157 | void rpc_shutdown_client(struct rpc_clnt *); | 157 | void rpc_shutdown_client(struct rpc_clnt *); |
158 | void rpc_release_client(struct rpc_clnt *); | 158 | void rpc_release_client(struct rpc_clnt *); |
159 | void rpc_task_release_transport(struct rpc_task *); | ||
159 | void rpc_task_release_client(struct rpc_task *); | 160 | void rpc_task_release_client(struct rpc_task *); |
160 | 161 | ||
161 | int rpcb_create_local(struct net *); | 162 | int rpcb_create_local(struct net *); |
diff --git a/include/linux/sunrpc/metrics.h b/include/linux/sunrpc/metrics.h index 9baed7b355b2..1b3751327575 100644 --- a/include/linux/sunrpc/metrics.h +++ b/include/linux/sunrpc/metrics.h | |||
@@ -82,7 +82,7 @@ void rpc_count_iostats(const struct rpc_task *, | |||
82 | struct rpc_iostats *); | 82 | struct rpc_iostats *); |
83 | void rpc_count_iostats_metrics(const struct rpc_task *, | 83 | void rpc_count_iostats_metrics(const struct rpc_task *, |
84 | struct rpc_iostats *); | 84 | struct rpc_iostats *); |
85 | void rpc_print_iostats(struct seq_file *, struct rpc_clnt *); | 85 | void rpc_clnt_show_stats(struct seq_file *, struct rpc_clnt *); |
86 | void rpc_free_iostats(struct rpc_iostats *); | 86 | void rpc_free_iostats(struct rpc_iostats *); |
87 | 87 | ||
88 | #else /* CONFIG_PROC_FS */ | 88 | #else /* CONFIG_PROC_FS */ |
@@ -95,7 +95,7 @@ static inline void rpc_count_iostats_metrics(const struct rpc_task *task, | |||
95 | { | 95 | { |
96 | } | 96 | } |
97 | 97 | ||
98 | static inline void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) {} | 98 | static inline void rpc_clnt_show_stats(struct seq_file *seq, struct rpc_clnt *clnt) {} |
99 | static inline void rpc_free_iostats(struct rpc_iostats *stats) {} | 99 | static inline void rpc_free_iostats(struct rpc_iostats *stats) {} |
100 | 100 | ||
101 | #endif /* CONFIG_PROC_FS */ | 101 | #endif /* CONFIG_PROC_FS */ |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index d2623b9f23d6..305ecea92170 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -50,7 +50,7 @@ static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp) | |||
50 | if (!val) | 50 | if (!val) |
51 | goto out_inval; | 51 | goto out_inval; |
52 | ret = kstrtoul(val, 0, &num); | 52 | ret = kstrtoul(val, 0, &num); |
53 | if (ret == -EINVAL) | 53 | if (ret) |
54 | goto out_inval; | 54 | goto out_inval; |
55 | nbits = fls(num - 1); | 55 | nbits = fls(num - 1); |
56 | if (nbits > MAX_HASHTABLE_BITS || nbits < 2) | 56 | if (nbits > MAX_HASHTABLE_BITS || nbits < 2) |
@@ -253,7 +253,7 @@ rpcauth_list_flavors(rpc_authflavor_t *array, int size) | |||
253 | EXPORT_SYMBOL_GPL(rpcauth_list_flavors); | 253 | EXPORT_SYMBOL_GPL(rpcauth_list_flavors); |
254 | 254 | ||
255 | struct rpc_auth * | 255 | struct rpc_auth * |
256 | rpcauth_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | 256 | rpcauth_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) |
257 | { | 257 | { |
258 | struct rpc_auth *auth; | 258 | struct rpc_auth *auth; |
259 | const struct rpc_authops *ops; | 259 | const struct rpc_authops *ops; |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 962afb8912d5..21c0aa0a0d1d 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -1016,7 +1016,7 @@ static void gss_pipe_free(struct gss_pipe *p) | |||
1016 | * parameters based on the input flavor (which must be a pseudoflavor) | 1016 | * parameters based on the input flavor (which must be a pseudoflavor) |
1017 | */ | 1017 | */ |
1018 | static struct gss_auth * | 1018 | static struct gss_auth * |
1019 | gss_create_new(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | 1019 | gss_create_new(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) |
1020 | { | 1020 | { |
1021 | rpc_authflavor_t flavor = args->pseudoflavor; | 1021 | rpc_authflavor_t flavor = args->pseudoflavor; |
1022 | struct gss_auth *gss_auth; | 1022 | struct gss_auth *gss_auth; |
@@ -1163,7 +1163,7 @@ gss_destroy(struct rpc_auth *auth) | |||
1163 | * (which is guaranteed to last as long as any of its descendants). | 1163 | * (which is guaranteed to last as long as any of its descendants). |
1164 | */ | 1164 | */ |
1165 | static struct gss_auth * | 1165 | static struct gss_auth * |
1166 | gss_auth_find_or_add_hashed(struct rpc_auth_create_args *args, | 1166 | gss_auth_find_or_add_hashed(const struct rpc_auth_create_args *args, |
1167 | struct rpc_clnt *clnt, | 1167 | struct rpc_clnt *clnt, |
1168 | struct gss_auth *new) | 1168 | struct gss_auth *new) |
1169 | { | 1169 | { |
@@ -1200,7 +1200,8 @@ out: | |||
1200 | } | 1200 | } |
1201 | 1201 | ||
1202 | static struct gss_auth * | 1202 | static struct gss_auth * |
1203 | gss_create_hashed(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | 1203 | gss_create_hashed(const struct rpc_auth_create_args *args, |
1204 | struct rpc_clnt *clnt) | ||
1204 | { | 1205 | { |
1205 | struct gss_auth *gss_auth; | 1206 | struct gss_auth *gss_auth; |
1206 | struct gss_auth *new; | 1207 | struct gss_auth *new; |
@@ -1219,7 +1220,7 @@ out: | |||
1219 | } | 1220 | } |
1220 | 1221 | ||
1221 | static struct rpc_auth * | 1222 | static struct rpc_auth * |
1222 | gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | 1223 | gss_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) |
1223 | { | 1224 | { |
1224 | struct gss_auth *gss_auth; | 1225 | struct gss_auth *gss_auth; |
1225 | struct rpc_xprt_switch *xps = rcu_access_pointer(clnt->cl_xpi.xpi_xpswitch); | 1226 | struct rpc_xprt_switch *xps = rcu_access_pointer(clnt->cl_xpi.xpi_xpswitch); |
@@ -1602,7 +1603,7 @@ static int gss_cred_is_negative_entry(struct rpc_cred *cred) | |||
1602 | if (test_bit(RPCAUTH_CRED_NEGATIVE, &cred->cr_flags)) { | 1603 | if (test_bit(RPCAUTH_CRED_NEGATIVE, &cred->cr_flags)) { |
1603 | unsigned long now = jiffies; | 1604 | unsigned long now = jiffies; |
1604 | unsigned long begin, expire; | 1605 | unsigned long begin, expire; |
1605 | struct gss_cred *gss_cred; | 1606 | struct gss_cred *gss_cred; |
1606 | 1607 | ||
1607 | gss_cred = container_of(cred, struct gss_cred, gc_base); | 1608 | gss_cred = container_of(cred, struct gss_cred, gc_base); |
1608 | begin = gss_cred->gc_upcall_timestamp; | 1609 | begin = gss_cred->gc_upcall_timestamp; |
diff --git a/net/sunrpc/auth_gss/gss_generic_token.c b/net/sunrpc/auth_gss/gss_generic_token.c index 254defe446a7..fe97f3106536 100644 --- a/net/sunrpc/auth_gss/gss_generic_token.c +++ b/net/sunrpc/auth_gss/gss_generic_token.c | |||
@@ -231,4 +231,3 @@ g_verify_token_header(struct xdr_netobj *mech, int *body_size, | |||
231 | } | 231 | } |
232 | 232 | ||
233 | EXPORT_SYMBOL_GPL(g_verify_token_header); | 233 | EXPORT_SYMBOL_GPL(g_verify_token_header); |
234 | |||
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index d31f868b643c..0220e1ca5280 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c | |||
@@ -1081,4 +1081,3 @@ out_err: | |||
1081 | dprintk("%s: returning %d\n", __func__, err); | 1081 | dprintk("%s: returning %d\n", __func__, err); |
1082 | return err; | 1082 | return err; |
1083 | } | 1083 | } |
1084 | |||
diff --git a/net/sunrpc/auth_gss/gss_krb5_keys.c b/net/sunrpc/auth_gss/gss_krb5_keys.c index 870133146026..f7fe2d2b851f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_keys.c +++ b/net/sunrpc/auth_gss/gss_krb5_keys.c | |||
@@ -324,4 +324,3 @@ u32 gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e, | |||
324 | err_out: | 324 | err_out: |
325 | return ret; | 325 | return ret; |
326 | } | 326 | } |
327 | |||
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 94a2b3f082a8..eaad9bc7a0bd 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c | |||
@@ -229,4 +229,3 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, | |||
229 | return gss_get_mic_v2(ctx, text, token); | 229 | return gss_get_mic_v2(ctx, text, token); |
230 | } | 230 | } |
231 | } | 231 | } |
232 | |||
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index b601a73cc9db..ef2b25b86d2f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c | |||
@@ -225,4 +225,3 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, | |||
225 | return gss_verify_mic_v2(ctx, message_buffer, read_token); | 225 | return gss_verify_mic_v2(ctx, message_buffer, read_token); |
226 | } | 226 | } |
227 | } | 227 | } |
228 | |||
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 9a1347fec6f4..39a2e672900b 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c | |||
@@ -621,4 +621,3 @@ gss_unwrap_kerberos(struct gss_ctx *gctx, int offset, struct xdr_buf *buf) | |||
621 | return gss_unwrap_kerberos_v2(kctx, offset, buf); | 621 | return gss_unwrap_kerberos_v2(kctx, offset, buf); |
622 | } | 622 | } |
623 | } | 623 | } |
624 | |||
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 5089dbb96d58..860f2a1bbb67 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
@@ -1389,7 +1389,7 @@ static void destroy_use_gss_proxy_proc_entry(struct net *net) | |||
1389 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1389 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
1390 | 1390 | ||
1391 | if (sn->use_gssp_proc) { | 1391 | if (sn->use_gssp_proc) { |
1392 | remove_proc_entry("use-gss-proxy", sn->proc_net_rpc); | 1392 | remove_proc_entry("use-gss-proxy", sn->proc_net_rpc); |
1393 | clear_gssp_clnt(sn); | 1393 | clear_gssp_clnt(sn); |
1394 | } | 1394 | } |
1395 | } | 1395 | } |
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index 75d72e109a04..4b48228ee8c7 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c | |||
@@ -19,7 +19,7 @@ static struct rpc_auth null_auth; | |||
19 | static struct rpc_cred null_cred; | 19 | static struct rpc_cred null_cred; |
20 | 20 | ||
21 | static struct rpc_auth * | 21 | static struct rpc_auth * |
22 | nul_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | 22 | nul_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) |
23 | { | 23 | { |
24 | atomic_inc(&null_auth.au_count); | 24 | atomic_inc(&null_auth.au_count); |
25 | return &null_auth; | 25 | return &null_auth; |
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index dafd6b870ba3..185e56d4f9ae 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c | |||
@@ -30,7 +30,7 @@ static struct rpc_auth unix_auth; | |||
30 | static const struct rpc_credops unix_credops; | 30 | static const struct rpc_credops unix_credops; |
31 | 31 | ||
32 | static struct rpc_auth * | 32 | static struct rpc_auth * |
33 | unx_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | 33 | unx_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt) |
34 | { | 34 | { |
35 | dprintk("RPC: creating UNIX authenticator for client %p\n", | 35 | dprintk("RPC: creating UNIX authenticator for client %p\n", |
36 | clnt); | 36 | clnt); |
diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index c2c68a15b59d..3c15a99b9700 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c | |||
@@ -362,4 +362,3 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied) | |||
362 | wake_up(&bc_serv->sv_cb_waitq); | 362 | wake_up(&bc_serv->sv_cb_waitq); |
363 | spin_unlock(&bc_serv->sv_cb_lock); | 363 | spin_unlock(&bc_serv->sv_cb_lock); |
364 | } | 364 | } |
365 | |||
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index d839c33ae7d9..8ea2f5fadd96 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -892,7 +892,7 @@ rpc_free_client(struct rpc_clnt *clnt) | |||
892 | /* | 892 | /* |
893 | * Free an RPC client | 893 | * Free an RPC client |
894 | */ | 894 | */ |
895 | static struct rpc_clnt * | 895 | static struct rpc_clnt * |
896 | rpc_free_auth(struct rpc_clnt *clnt) | 896 | rpc_free_auth(struct rpc_clnt *clnt) |
897 | { | 897 | { |
898 | if (clnt->cl_auth == NULL) | 898 | if (clnt->cl_auth == NULL) |
@@ -965,10 +965,20 @@ out: | |||
965 | } | 965 | } |
966 | EXPORT_SYMBOL_GPL(rpc_bind_new_program); | 966 | EXPORT_SYMBOL_GPL(rpc_bind_new_program); |
967 | 967 | ||
968 | void rpc_task_release_transport(struct rpc_task *task) | ||
969 | { | ||
970 | struct rpc_xprt *xprt = task->tk_xprt; | ||
971 | |||
972 | if (xprt) { | ||
973 | task->tk_xprt = NULL; | ||
974 | xprt_put(xprt); | ||
975 | } | ||
976 | } | ||
977 | EXPORT_SYMBOL_GPL(rpc_task_release_transport); | ||
978 | |||
968 | void rpc_task_release_client(struct rpc_task *task) | 979 | void rpc_task_release_client(struct rpc_task *task) |
969 | { | 980 | { |
970 | struct rpc_clnt *clnt = task->tk_client; | 981 | struct rpc_clnt *clnt = task->tk_client; |
971 | struct rpc_xprt *xprt = task->tk_xprt; | ||
972 | 982 | ||
973 | if (clnt != NULL) { | 983 | if (clnt != NULL) { |
974 | /* Remove from client task list */ | 984 | /* Remove from client task list */ |
@@ -979,12 +989,14 @@ void rpc_task_release_client(struct rpc_task *task) | |||
979 | 989 | ||
980 | rpc_release_client(clnt); | 990 | rpc_release_client(clnt); |
981 | } | 991 | } |
992 | rpc_task_release_transport(task); | ||
993 | } | ||
982 | 994 | ||
983 | if (xprt != NULL) { | 995 | static |
984 | task->tk_xprt = NULL; | 996 | void rpc_task_set_transport(struct rpc_task *task, struct rpc_clnt *clnt) |
985 | 997 | { | |
986 | xprt_put(xprt); | 998 | if (!task->tk_xprt) |
987 | } | 999 | task->tk_xprt = xprt_iter_get_next(&clnt->cl_xpi); |
988 | } | 1000 | } |
989 | 1001 | ||
990 | static | 1002 | static |
@@ -992,8 +1004,7 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt) | |||
992 | { | 1004 | { |
993 | 1005 | ||
994 | if (clnt != NULL) { | 1006 | if (clnt != NULL) { |
995 | if (task->tk_xprt == NULL) | 1007 | rpc_task_set_transport(task, clnt); |
996 | task->tk_xprt = xprt_iter_get_next(&clnt->cl_xpi); | ||
997 | task->tk_client = clnt; | 1008 | task->tk_client = clnt; |
998 | atomic_inc(&clnt->cl_count); | 1009 | atomic_inc(&clnt->cl_count); |
999 | if (clnt->cl_softrtry) | 1010 | if (clnt->cl_softrtry) |
@@ -1512,6 +1523,7 @@ call_start(struct rpc_task *task) | |||
1512 | clnt->cl_program->version[clnt->cl_vers]->counts[idx]++; | 1523 | clnt->cl_program->version[clnt->cl_vers]->counts[idx]++; |
1513 | clnt->cl_stats->rpccnt++; | 1524 | clnt->cl_stats->rpccnt++; |
1514 | task->tk_action = call_reserve; | 1525 | task->tk_action = call_reserve; |
1526 | rpc_task_set_transport(task, clnt); | ||
1515 | } | 1527 | } |
1516 | 1528 | ||
1517 | /* | 1529 | /* |
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index c526f8fb37c9..c7872bc13860 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -213,7 +213,7 @@ static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt, | |||
213 | sn->rpcb_local_clnt = clnt; | 213 | sn->rpcb_local_clnt = clnt; |
214 | sn->rpcb_local_clnt4 = clnt4; | 214 | sn->rpcb_local_clnt4 = clnt4; |
215 | sn->rpcb_is_af_local = is_af_local ? 1 : 0; | 215 | sn->rpcb_is_af_local = is_af_local ? 1 : 0; |
216 | smp_wmb(); | 216 | smp_wmb(); |
217 | sn->rpcb_users = 1; | 217 | sn->rpcb_users = 1; |
218 | dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: " | 218 | dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: " |
219 | "%p, rpcb_local_clnt4: %p) for net %x%s\n", | 219 | "%p, rpcb_local_clnt4: %p) for net %x%s\n", |
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index f68aa46c9dd7..71166b393732 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c | |||
@@ -208,13 +208,39 @@ static void _print_name(struct seq_file *seq, unsigned int op, | |||
208 | seq_printf(seq, "\t%12u: ", op); | 208 | seq_printf(seq, "\t%12u: ", op); |
209 | } | 209 | } |
210 | 210 | ||
211 | void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) | 211 | static void _add_rpc_iostats(struct rpc_iostats *a, struct rpc_iostats *b) |
212 | { | ||
213 | a->om_ops += b->om_ops; | ||
214 | a->om_ntrans += b->om_ntrans; | ||
215 | a->om_timeouts += b->om_timeouts; | ||
216 | a->om_bytes_sent += b->om_bytes_sent; | ||
217 | a->om_bytes_recv += b->om_bytes_recv; | ||
218 | a->om_queue = ktime_add(a->om_queue, b->om_queue); | ||
219 | a->om_rtt = ktime_add(a->om_rtt, b->om_rtt); | ||
220 | a->om_execute = ktime_add(a->om_execute, b->om_execute); | ||
221 | } | ||
222 | |||
223 | static void _print_rpc_iostats(struct seq_file *seq, struct rpc_iostats *stats, | ||
224 | int op, const struct rpc_procinfo *procs) | ||
225 | { | ||
226 | _print_name(seq, op, procs); | ||
227 | seq_printf(seq, "%lu %lu %lu %Lu %Lu %Lu %Lu %Lu\n", | ||
228 | stats->om_ops, | ||
229 | stats->om_ntrans, | ||
230 | stats->om_timeouts, | ||
231 | stats->om_bytes_sent, | ||
232 | stats->om_bytes_recv, | ||
233 | ktime_to_ms(stats->om_queue), | ||
234 | ktime_to_ms(stats->om_rtt), | ||
235 | ktime_to_ms(stats->om_execute)); | ||
236 | } | ||
237 | |||
238 | void rpc_clnt_show_stats(struct seq_file *seq, struct rpc_clnt *clnt) | ||
212 | { | 239 | { |
213 | struct rpc_iostats *stats = clnt->cl_metrics; | ||
214 | struct rpc_xprt *xprt; | 240 | struct rpc_xprt *xprt; |
215 | unsigned int op, maxproc = clnt->cl_maxproc; | 241 | unsigned int op, maxproc = clnt->cl_maxproc; |
216 | 242 | ||
217 | if (!stats) | 243 | if (!clnt->cl_metrics) |
218 | return; | 244 | return; |
219 | 245 | ||
220 | seq_printf(seq, "\tRPC iostats version: %s ", RPC_IOSTATS_VERS); | 246 | seq_printf(seq, "\tRPC iostats version: %s ", RPC_IOSTATS_VERS); |
@@ -229,20 +255,18 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) | |||
229 | 255 | ||
230 | seq_printf(seq, "\tper-op statistics\n"); | 256 | seq_printf(seq, "\tper-op statistics\n"); |
231 | for (op = 0; op < maxproc; op++) { | 257 | for (op = 0; op < maxproc; op++) { |
232 | struct rpc_iostats *metrics = &stats[op]; | 258 | struct rpc_iostats stats = {}; |
233 | _print_name(seq, op, clnt->cl_procinfo); | 259 | struct rpc_clnt *next = clnt; |
234 | seq_printf(seq, "%lu %lu %lu %Lu %Lu %Lu %Lu %Lu\n", | 260 | do { |
235 | metrics->om_ops, | 261 | _add_rpc_iostats(&stats, &next->cl_metrics[op]); |
236 | metrics->om_ntrans, | 262 | if (next == next->cl_parent) |
237 | metrics->om_timeouts, | 263 | break; |
238 | metrics->om_bytes_sent, | 264 | next = next->cl_parent; |
239 | metrics->om_bytes_recv, | 265 | } while (next); |
240 | ktime_to_ms(metrics->om_queue), | 266 | _print_rpc_iostats(seq, &stats, op, clnt->cl_procinfo); |
241 | ktime_to_ms(metrics->om_rtt), | ||
242 | ktime_to_ms(metrics->om_execute)); | ||
243 | } | 267 | } |
244 | } | 268 | } |
245 | EXPORT_SYMBOL_GPL(rpc_print_iostats); | 269 | EXPORT_SYMBOL_GPL(rpc_clnt_show_stats); |
246 | 270 | ||
247 | /* | 271 | /* |
248 | * Register/unregister RPC proc files | 272 | * Register/unregister RPC proc files |
@@ -310,4 +334,3 @@ void rpc_proc_exit(struct net *net) | |||
310 | dprintk("RPC: unregistering /proc/net/rpc\n"); | 334 | dprintk("RPC: unregistering /proc/net/rpc\n"); |
311 | remove_proc_entry("rpc", net->proc_net); | 335 | remove_proc_entry("rpc", net->proc_net); |
312 | } | 336 | } |
313 | |||
diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h index 09a0315ea77b..c9bacb3c930f 100644 --- a/net/sunrpc/sunrpc.h +++ b/net/sunrpc/sunrpc.h | |||
@@ -57,4 +57,3 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr, | |||
57 | int rpc_clients_notifier_register(void); | 57 | int rpc_clients_notifier_register(void); |
58 | void rpc_clients_notifier_unregister(void); | 58 | void rpc_clients_notifier_unregister(void); |
59 | #endif /* _NET_SUNRPC_SUNRPC_H */ | 59 | #endif /* _NET_SUNRPC_SUNRPC_H */ |
60 | |||
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 3fabf9f6a0f9..a8db2e3f8904 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -880,7 +880,7 @@ static void xprt_wait_on_pinned_rqst(struct rpc_rqst *req) | |||
880 | __must_hold(&req->rq_xprt->recv_lock) | 880 | __must_hold(&req->rq_xprt->recv_lock) |
881 | { | 881 | { |
882 | struct rpc_task *task = req->rq_task; | 882 | struct rpc_task *task = req->rq_task; |
883 | 883 | ||
884 | if (task && test_bit(RPC_TASK_MSG_RECV, &task->tk_runstate)) { | 884 | if (task && test_bit(RPC_TASK_MSG_RECV, &task->tk_runstate)) { |
885 | spin_unlock(&req->rq_xprt->recv_lock); | 885 | spin_unlock(&req->rq_xprt->recv_lock); |
886 | set_bit(RPC_TASK_MSG_RECV_WAIT, &task->tk_runstate); | 886 | set_bit(RPC_TASK_MSG_RECV_WAIT, &task->tk_runstate); |
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 5efeba08918b..956a5ea47b58 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
@@ -280,7 +280,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) | |||
280 | ++xprt->rx_xprt.connect_cookie; | 280 | ++xprt->rx_xprt.connect_cookie; |
281 | connstate = -ECONNABORTED; | 281 | connstate = -ECONNABORTED; |
282 | connected: | 282 | connected: |
283 | xprt->rx_buf.rb_credits = 1; | ||
284 | ep->rep_connected = connstate; | 283 | ep->rep_connected = connstate; |
285 | rpcrdma_conn_func(ep); | 284 | rpcrdma_conn_func(ep); |
286 | wake_up_all(&ep->rep_connect_wait); | 285 | wake_up_all(&ep->rep_connect_wait); |
@@ -755,6 +754,7 @@ retry: | |||
755 | } | 754 | } |
756 | 755 | ||
757 | ep->rep_connected = 0; | 756 | ep->rep_connected = 0; |
757 | rpcrdma_post_recvs(r_xprt, true); | ||
758 | 758 | ||
759 | rc = rdma_connect(ia->ri_id, &ep->rep_remote_cma); | 759 | rc = rdma_connect(ia->ri_id, &ep->rep_remote_cma); |
760 | if (rc) { | 760 | if (rc) { |
@@ -773,8 +773,6 @@ retry: | |||
773 | 773 | ||
774 | dprintk("RPC: %s: connected\n", __func__); | 774 | dprintk("RPC: %s: connected\n", __func__); |
775 | 775 | ||
776 | rpcrdma_post_recvs(r_xprt, true); | ||
777 | |||
778 | out: | 776 | out: |
779 | if (rc) | 777 | if (rc) |
780 | ep->rep_connected = rc; | 778 | ep->rep_connected = rc; |
@@ -1171,6 +1169,7 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt) | |||
1171 | list_add(&req->rl_list, &buf->rb_send_bufs); | 1169 | list_add(&req->rl_list, &buf->rb_send_bufs); |
1172 | } | 1170 | } |
1173 | 1171 | ||
1172 | buf->rb_credits = 1; | ||
1174 | buf->rb_posted_receives = 0; | 1173 | buf->rb_posted_receives = 0; |
1175 | INIT_LIST_HEAD(&buf->rb_recv_bufs); | 1174 | INIT_LIST_HEAD(&buf->rb_recv_bufs); |
1176 | 1175 | ||
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 9e1c5024aba9..6b7539c0466e 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -3375,4 +3375,3 @@ module_param_named(tcp_max_slot_table_entries, xprt_max_tcp_slot_table_entries, | |||
3375 | max_slot_table_size, 0644); | 3375 | max_slot_table_size, 0644); |
3376 | module_param_named(udp_slot_table_entries, xprt_udp_slot_table_entries, | 3376 | module_param_named(udp_slot_table_entries, xprt_udp_slot_table_entries, |
3377 | slot_table_size, 0644); | 3377 | slot_table_size, 0644); |
3378 | |||