diff options
| -rw-r--r-- | fs/nfs/callback_proc.c | 52 | ||||
| -rw-r--r-- | fs/nfs/direct.c | 33 | ||||
| -rw-r--r-- | fs/nfs/file.c | 2 | ||||
| -rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayout.c | 13 | ||||
| -rw-r--r-- | fs/nfs/internal.h | 7 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 12 | ||||
| -rw-r--r-- | fs/nfs/nfs4trace.h | 69 | ||||
| -rw-r--r-- | fs/nfs/nfstrace.h | 1 | ||||
| -rw-r--r-- | fs/nfs/pagelist.c | 6 | ||||
| -rw-r--r-- | fs/nfs/pnfs.c | 82 | ||||
| -rw-r--r-- | fs/nfs/pnfs.h | 33 | ||||
| -rw-r--r-- | fs/nfs/pnfs_nfs.c | 10 | ||||
| -rw-r--r-- | fs/nfs/write.c | 88 | ||||
| -rw-r--r-- | include/linux/nfs_fs.h | 1 | ||||
| -rw-r--r-- | include/linux/nfs_xdr.h | 4 |
15 files changed, 296 insertions, 117 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 807eb6ef4f91..f0939d097406 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
| @@ -83,8 +83,11 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, | |||
| 83 | 83 | ||
| 84 | res = htonl(NFS4ERR_BADHANDLE); | 84 | res = htonl(NFS4ERR_BADHANDLE); |
| 85 | inode = nfs_delegation_find_inode(cps->clp, &args->fh); | 85 | inode = nfs_delegation_find_inode(cps->clp, &args->fh); |
| 86 | if (inode == NULL) | 86 | if (inode == NULL) { |
| 87 | trace_nfs4_cb_recall(cps->clp, &args->fh, NULL, | ||
| 88 | &args->stateid, -ntohl(res)); | ||
| 87 | goto out; | 89 | goto out; |
| 90 | } | ||
| 88 | /* Set up a helper thread to actually return the delegation */ | 91 | /* Set up a helper thread to actually return the delegation */ |
| 89 | switch (nfs_async_inode_return_delegation(inode, &args->stateid)) { | 92 | switch (nfs_async_inode_return_delegation(inode, &args->stateid)) { |
| 90 | case 0: | 93 | case 0: |
| @@ -96,7 +99,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, | |||
| 96 | default: | 99 | default: |
| 97 | res = htonl(NFS4ERR_RESOURCE); | 100 | res = htonl(NFS4ERR_RESOURCE); |
| 98 | } | 101 | } |
| 99 | trace_nfs4_recall_delegation(inode, -ntohl(res)); | 102 | trace_nfs4_cb_recall(cps->clp, &args->fh, inode, |
| 103 | &args->stateid, -ntohl(res)); | ||
| 100 | iput(inode); | 104 | iput(inode); |
| 101 | out: | 105 | out: |
| 102 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); | 106 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); |
| @@ -160,6 +164,22 @@ static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, | |||
| 160 | return lo; | 164 | return lo; |
| 161 | } | 165 | } |
| 162 | 166 | ||
| 167 | /* | ||
| 168 | * Enforce RFC5661 section 12.5.5.2.1. (Layout Recall and Return Sequencing) | ||
| 169 | */ | ||
| 170 | static bool pnfs_check_stateid_sequence(struct pnfs_layout_hdr *lo, | ||
| 171 | const nfs4_stateid *new) | ||
| 172 | { | ||
| 173 | u32 oldseq, newseq; | ||
| 174 | |||
| 175 | oldseq = be32_to_cpu(lo->plh_stateid.seqid); | ||
| 176 | newseq = be32_to_cpu(new->seqid); | ||
| 177 | |||
| 178 | if (newseq > oldseq + 1) | ||
| 179 | return false; | ||
| 180 | return true; | ||
| 181 | } | ||
| 182 | |||
| 163 | static u32 initiate_file_draining(struct nfs_client *clp, | 183 | static u32 initiate_file_draining(struct nfs_client *clp, |
| 164 | struct cb_layoutrecallargs *args) | 184 | struct cb_layoutrecallargs *args) |
| 165 | { | 185 | { |
| @@ -169,34 +189,52 @@ static u32 initiate_file_draining(struct nfs_client *clp, | |||
| 169 | LIST_HEAD(free_me_list); | 189 | LIST_HEAD(free_me_list); |
| 170 | 190 | ||
| 171 | lo = get_layout_by_fh(clp, &args->cbl_fh, &args->cbl_stateid); | 191 | lo = get_layout_by_fh(clp, &args->cbl_fh, &args->cbl_stateid); |
| 172 | if (!lo) | 192 | if (!lo) { |
| 193 | trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, NULL, | ||
| 194 | &args->cbl_stateid, -rv); | ||
| 173 | goto out; | 195 | goto out; |
| 196 | } | ||
| 174 | 197 | ||
| 175 | ino = lo->plh_inode; | 198 | ino = lo->plh_inode; |
| 176 | 199 | ||
| 177 | spin_lock(&ino->i_lock); | 200 | spin_lock(&ino->i_lock); |
| 201 | if (!pnfs_check_stateid_sequence(lo, &args->cbl_stateid)) { | ||
| 202 | rv = NFS4ERR_DELAY; | ||
| 203 | goto unlock; | ||
| 204 | } | ||
| 178 | pnfs_set_layout_stateid(lo, &args->cbl_stateid, true); | 205 | pnfs_set_layout_stateid(lo, &args->cbl_stateid, true); |
| 179 | spin_unlock(&ino->i_lock); | 206 | spin_unlock(&ino->i_lock); |
| 180 | 207 | ||
| 181 | pnfs_layoutcommit_inode(ino, false); | 208 | pnfs_layoutcommit_inode(ino, false); |
| 182 | 209 | ||
| 183 | spin_lock(&ino->i_lock); | 210 | spin_lock(&ino->i_lock); |
| 184 | if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) || | 211 | /* |
| 185 | pnfs_mark_matching_lsegs_invalid(lo, &free_me_list, | 212 | * Enforce RFC5661 Section 12.5.5.2.1.5 (Bulk Recall and Return) |
| 186 | &args->cbl_range)) { | 213 | */ |
| 214 | if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { | ||
| 187 | rv = NFS4ERR_DELAY; | 215 | rv = NFS4ERR_DELAY; |
| 188 | goto unlock; | 216 | goto unlock; |
| 189 | } | 217 | } |
| 190 | 218 | ||
| 219 | if (pnfs_mark_matching_lsegs_return(lo, &free_me_list, | ||
| 220 | &args->cbl_range)) { | ||
| 221 | rv = NFS4_OK; | ||
| 222 | goto unlock; | ||
| 223 | } | ||
| 224 | |||
| 191 | if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) { | 225 | if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) { |
| 192 | NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo, | 226 | NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo, |
| 193 | &args->cbl_range); | 227 | &args->cbl_range); |
| 194 | } | 228 | } |
| 229 | pnfs_mark_layout_returned_if_empty(lo); | ||
| 195 | unlock: | 230 | unlock: |
| 196 | spin_unlock(&ino->i_lock); | 231 | spin_unlock(&ino->i_lock); |
| 197 | pnfs_free_lseg_list(&free_me_list); | 232 | pnfs_free_lseg_list(&free_me_list); |
| 233 | /* Free all lsegs that are attached to commit buckets */ | ||
| 234 | nfs_commit_inode(ino, 0); | ||
| 198 | pnfs_put_layout_hdr(lo); | 235 | pnfs_put_layout_hdr(lo); |
| 199 | trace_nfs4_cb_layoutrecall_inode(clp, &args->cbl_fh, ino, -rv); | 236 | trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, ino, |
| 237 | &args->cbl_stateid, -rv); | ||
| 200 | iput(ino); | 238 | iput(ino); |
| 201 | out: | 239 | out: |
| 202 | return rv; | 240 | return rv; |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 2e7142bcb4c8..7ab7ec9f4eed 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
| @@ -117,12 +117,6 @@ static inline int put_dreq(struct nfs_direct_req *dreq) | |||
| 117 | return atomic_dec_and_test(&dreq->io_count); | 117 | return atomic_dec_and_test(&dreq->io_count); |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | void nfs_direct_set_resched_writes(struct nfs_direct_req *dreq) | ||
| 121 | { | ||
| 122 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | ||
| 123 | } | ||
| 124 | EXPORT_SYMBOL_GPL(nfs_direct_set_resched_writes); | ||
| 125 | |||
| 126 | static void | 120 | static void |
| 127 | nfs_direct_good_bytes(struct nfs_direct_req *dreq, struct nfs_pgio_header *hdr) | 121 | nfs_direct_good_bytes(struct nfs_direct_req *dreq, struct nfs_pgio_header *hdr) |
| 128 | { | 122 | { |
| @@ -735,14 +729,20 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) | |||
| 735 | nfs_direct_write_complete(dreq, data->inode); | 729 | nfs_direct_write_complete(dreq, data->inode); |
| 736 | } | 730 | } |
| 737 | 731 | ||
| 738 | static void nfs_direct_error_cleanup(struct nfs_inode *nfsi) | 732 | static void nfs_direct_resched_write(struct nfs_commit_info *cinfo, |
| 733 | struct nfs_page *req) | ||
| 739 | { | 734 | { |
| 740 | /* There is no lock to clear */ | 735 | struct nfs_direct_req *dreq = cinfo->dreq; |
| 736 | |||
| 737 | spin_lock(&dreq->lock); | ||
| 738 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | ||
| 739 | spin_unlock(&dreq->lock); | ||
| 740 | nfs_mark_request_commit(req, NULL, cinfo, 0); | ||
| 741 | } | 741 | } |
| 742 | 742 | ||
| 743 | static const struct nfs_commit_completion_ops nfs_direct_commit_completion_ops = { | 743 | static const struct nfs_commit_completion_ops nfs_direct_commit_completion_ops = { |
| 744 | .completion = nfs_direct_commit_complete, | 744 | .completion = nfs_direct_commit_complete, |
| 745 | .error_cleanup = nfs_direct_error_cleanup, | 745 | .resched_write = nfs_direct_resched_write, |
| 746 | }; | 746 | }; |
| 747 | 747 | ||
| 748 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | 748 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) |
| @@ -847,10 +847,25 @@ static void nfs_write_sync_pgio_error(struct list_head *head) | |||
| 847 | } | 847 | } |
| 848 | } | 848 | } |
| 849 | 849 | ||
| 850 | static void nfs_direct_write_reschedule_io(struct nfs_pgio_header *hdr) | ||
| 851 | { | ||
| 852 | struct nfs_direct_req *dreq = hdr->dreq; | ||
| 853 | |||
| 854 | spin_lock(&dreq->lock); | ||
| 855 | if (dreq->error == 0) { | ||
| 856 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | ||
| 857 | /* fake unstable write to let common nfs resend pages */ | ||
| 858 | hdr->verf.committed = NFS_UNSTABLE; | ||
| 859 | hdr->good_bytes = hdr->args.count; | ||
| 860 | } | ||
| 861 | spin_unlock(&dreq->lock); | ||
| 862 | } | ||
| 863 | |||
| 850 | static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = { | 864 | static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = { |
| 851 | .error_cleanup = nfs_write_sync_pgio_error, | 865 | .error_cleanup = nfs_write_sync_pgio_error, |
| 852 | .init_hdr = nfs_direct_pgio_init, | 866 | .init_hdr = nfs_direct_pgio_init, |
| 853 | .completion = nfs_direct_write_completion, | 867 | .completion = nfs_direct_write_completion, |
| 868 | .reschedule_io = nfs_direct_write_reschedule_io, | ||
| 854 | }; | 869 | }; |
| 855 | 870 | ||
| 856 | 871 | ||
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index f188dd071dfc..178ec8da028f 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -514,7 +514,7 @@ static void nfs_check_dirty_writeback(struct page *page, | |||
| 514 | * so it will not block due to pages that will shortly be freeable. | 514 | * so it will not block due to pages that will shortly be freeable. |
| 515 | */ | 515 | */ |
| 516 | nfsi = NFS_I(mapping->host); | 516 | nfsi = NFS_I(mapping->host); |
| 517 | if (test_bit(NFS_INO_COMMIT, &nfsi->flags)) { | 517 | if (atomic_read(&nfsi->commit_info.rpcs_out)) { |
| 518 | *writeback = true; | 518 | *writeback = true; |
| 519 | return; | 519 | return; |
| 520 | } | 520 | } |
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 2981cd190bfd..18c329b84ffb 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c | |||
| @@ -941,18 +941,7 @@ static void ff_layout_reset_write(struct nfs_pgio_header *hdr, bool retry_pnfs) | |||
| 941 | hdr->args.count, | 941 | hdr->args.count, |
| 942 | (unsigned long long)hdr->args.offset); | 942 | (unsigned long long)hdr->args.offset); |
| 943 | 943 | ||
| 944 | if (!hdr->dreq) { | 944 | hdr->completion_ops->reschedule_io(hdr); |
| 945 | struct nfs_open_context *ctx; | ||
| 946 | |||
| 947 | ctx = nfs_list_entry(hdr->pages.next)->wb_context; | ||
| 948 | set_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags); | ||
| 949 | hdr->completion_ops->error_cleanup(&hdr->pages); | ||
| 950 | } else { | ||
| 951 | nfs_direct_set_resched_writes(hdr->dreq); | ||
| 952 | /* fake unstable write to let common nfs resend pages */ | ||
| 953 | hdr->verf.committed = NFS_UNSTABLE; | ||
| 954 | hdr->good_bytes = hdr->args.count; | ||
| 955 | } | ||
| 956 | return; | 945 | return; |
| 957 | } | 946 | } |
| 958 | 947 | ||
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 68f773dc226e..ee81792d2886 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -264,6 +264,12 @@ static inline bool nfs_pgio_has_mirroring(struct nfs_pageio_descriptor *desc) | |||
| 264 | return desc->pg_mirror_count > 1; | 264 | return desc->pg_mirror_count > 1; |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | static inline bool nfs_match_open_context(const struct nfs_open_context *ctx1, | ||
| 268 | const struct nfs_open_context *ctx2) | ||
| 269 | { | ||
| 270 | return ctx1->cred == ctx2->cred && ctx1->state == ctx2->state; | ||
| 271 | } | ||
| 272 | |||
| 267 | /* nfs2xdr.c */ | 273 | /* nfs2xdr.c */ |
| 268 | extern struct rpc_procinfo nfs_procedures[]; | 274 | extern struct rpc_procinfo nfs_procedures[]; |
| 269 | extern int nfs2_decode_dirent(struct xdr_stream *, | 275 | extern int nfs2_decode_dirent(struct xdr_stream *, |
| @@ -519,7 +525,6 @@ static inline void nfs_inode_dio_wait(struct inode *inode) | |||
| 519 | inode_dio_wait(inode); | 525 | inode_dio_wait(inode); |
| 520 | } | 526 | } |
| 521 | extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq); | 527 | extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq); |
| 522 | extern void nfs_direct_set_resched_writes(struct nfs_direct_req *dreq); | ||
| 523 | 528 | ||
| 524 | /* nfs4proc.c */ | 529 | /* nfs4proc.c */ |
| 525 | extern void __nfs4_read_done_cb(struct nfs_pgio_header *); | 530 | extern void __nfs4_read_done_cb(struct nfs_pgio_header *); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index adae525edec4..5e5062c9b92b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -7776,6 +7776,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata) | |||
| 7776 | struct nfs4_layoutget *lgp = calldata; | 7776 | struct nfs4_layoutget *lgp = calldata; |
| 7777 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | 7777 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); |
| 7778 | struct nfs4_session *session = nfs4_get_session(server); | 7778 | struct nfs4_session *session = nfs4_get_session(server); |
| 7779 | int ret; | ||
| 7779 | 7780 | ||
| 7780 | dprintk("--> %s\n", __func__); | 7781 | dprintk("--> %s\n", __func__); |
| 7781 | /* Note the is a race here, where a CB_LAYOUTRECALL can come in | 7782 | /* Note the is a race here, where a CB_LAYOUTRECALL can come in |
| @@ -7786,12 +7787,12 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata) | |||
| 7786 | if (nfs41_setup_sequence(session, &lgp->args.seq_args, | 7787 | if (nfs41_setup_sequence(session, &lgp->args.seq_args, |
| 7787 | &lgp->res.seq_res, task)) | 7788 | &lgp->res.seq_res, task)) |
| 7788 | return; | 7789 | return; |
| 7789 | if (pnfs_choose_layoutget_stateid(&lgp->args.stateid, | 7790 | ret = pnfs_choose_layoutget_stateid(&lgp->args.stateid, |
| 7790 | NFS_I(lgp->args.inode)->layout, | 7791 | NFS_I(lgp->args.inode)->layout, |
| 7791 | &lgp->args.range, | 7792 | &lgp->args.range, |
| 7792 | lgp->args.ctx->state)) { | 7793 | lgp->args.ctx->state); |
| 7793 | rpc_exit(task, NFS4_OK); | 7794 | if (ret < 0) |
| 7794 | } | 7795 | rpc_exit(task, ret); |
| 7795 | } | 7796 | } |
| 7796 | 7797 | ||
| 7797 | static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) | 7798 | static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) |
| @@ -8073,9 +8074,10 @@ static void nfs4_layoutreturn_release(void *calldata) | |||
| 8073 | 8074 | ||
| 8074 | dprintk("--> %s\n", __func__); | 8075 | dprintk("--> %s\n", __func__); |
| 8075 | spin_lock(&lo->plh_inode->i_lock); | 8076 | spin_lock(&lo->plh_inode->i_lock); |
| 8077 | pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range); | ||
| 8078 | pnfs_mark_layout_returned_if_empty(lo); | ||
| 8076 | if (lrp->res.lrs_present) | 8079 | if (lrp->res.lrs_present) |
| 8077 | pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); | 8080 | pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); |
| 8078 | pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range); | ||
| 8079 | pnfs_clear_layoutreturn_waitbit(lo); | 8081 | pnfs_clear_layoutreturn_waitbit(lo); |
| 8080 | lo->plh_block_lgets--; | 8082 | lo->plh_block_lgets--; |
| 8081 | spin_unlock(&lo->plh_inode->i_lock); | 8083 | spin_unlock(&lo->plh_inode->i_lock); |
diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h index d08d0c84b778..88b6b14ce71b 100644 --- a/fs/nfs/nfs4trace.h +++ b/fs/nfs/nfs4trace.h | |||
| @@ -982,7 +982,6 @@ DEFINE_NFS4_INODE_EVENT(nfs4_set_acl); | |||
| 982 | DEFINE_NFS4_INODE_EVENT(nfs4_get_security_label); | 982 | DEFINE_NFS4_INODE_EVENT(nfs4_get_security_label); |
| 983 | DEFINE_NFS4_INODE_EVENT(nfs4_set_security_label); | 983 | DEFINE_NFS4_INODE_EVENT(nfs4_set_security_label); |
| 984 | #endif /* CONFIG_NFS_V4_SECURITY_LABEL */ | 984 | #endif /* CONFIG_NFS_V4_SECURITY_LABEL */ |
| 985 | DEFINE_NFS4_INODE_EVENT(nfs4_recall_delegation); | ||
| 986 | 985 | ||
| 987 | DECLARE_EVENT_CLASS(nfs4_inode_stateid_event, | 986 | DECLARE_EVENT_CLASS(nfs4_inode_stateid_event, |
| 988 | TP_PROTO( | 987 | TP_PROTO( |
| @@ -1145,8 +1144,74 @@ DECLARE_EVENT_CLASS(nfs4_inode_callback_event, | |||
| 1145 | ), \ | 1144 | ), \ |
| 1146 | TP_ARGS(clp, fhandle, inode, error)) | 1145 | TP_ARGS(clp, fhandle, inode, error)) |
| 1147 | DEFINE_NFS4_INODE_CALLBACK_EVENT(nfs4_cb_getattr); | 1146 | DEFINE_NFS4_INODE_CALLBACK_EVENT(nfs4_cb_getattr); |
| 1148 | DEFINE_NFS4_INODE_CALLBACK_EVENT(nfs4_cb_layoutrecall_inode); | ||
| 1149 | 1147 | ||
| 1148 | DECLARE_EVENT_CLASS(nfs4_inode_stateid_callback_event, | ||
| 1149 | TP_PROTO( | ||
| 1150 | const struct nfs_client *clp, | ||
| 1151 | const struct nfs_fh *fhandle, | ||
| 1152 | const struct inode *inode, | ||
| 1153 | const nfs4_stateid *stateid, | ||
| 1154 | int error | ||
| 1155 | ), | ||
| 1156 | |||
| 1157 | TP_ARGS(clp, fhandle, inode, stateid, error), | ||
| 1158 | |||
| 1159 | TP_STRUCT__entry( | ||
| 1160 | __field(int, error) | ||
| 1161 | __field(dev_t, dev) | ||
| 1162 | __field(u32, fhandle) | ||
| 1163 | __field(u64, fileid) | ||
| 1164 | __string(dstaddr, clp ? | ||
| 1165 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
| 1166 | RPC_DISPLAY_ADDR) : "unknown") | ||
| 1167 | __field(int, stateid_seq) | ||
| 1168 | __field(u32, stateid_hash) | ||
| 1169 | ), | ||
| 1170 | |||
| 1171 | TP_fast_assign( | ||
| 1172 | __entry->error = error; | ||
| 1173 | __entry->fhandle = nfs_fhandle_hash(fhandle); | ||
| 1174 | if (inode != NULL) { | ||
| 1175 | __entry->fileid = NFS_FILEID(inode); | ||
| 1176 | __entry->dev = inode->i_sb->s_dev; | ||
| 1177 | } else { | ||
| 1178 | __entry->fileid = 0; | ||
| 1179 | __entry->dev = 0; | ||
| 1180 | } | ||
| 1181 | __assign_str(dstaddr, clp ? | ||
| 1182 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
| 1183 | RPC_DISPLAY_ADDR) : "unknown") | ||
| 1184 | __entry->stateid_seq = | ||
| 1185 | be32_to_cpu(stateid->seqid); | ||
| 1186 | __entry->stateid_hash = | ||
| 1187 | nfs_stateid_hash(stateid); | ||
| 1188 | ), | ||
| 1189 | |||
| 1190 | TP_printk( | ||
| 1191 | "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x " | ||
| 1192 | "stateid=%d:0x%08x dstaddr=%s", | ||
| 1193 | __entry->error, | ||
| 1194 | show_nfsv4_errors(__entry->error), | ||
| 1195 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
| 1196 | (unsigned long long)__entry->fileid, | ||
| 1197 | __entry->fhandle, | ||
| 1198 | __entry->stateid_seq, __entry->stateid_hash, | ||
| 1199 | __get_str(dstaddr) | ||
| 1200 | ) | ||
| 1201 | ); | ||
| 1202 | |||
| 1203 | #define DEFINE_NFS4_INODE_STATEID_CALLBACK_EVENT(name) \ | ||
| 1204 | DEFINE_EVENT(nfs4_inode_stateid_callback_event, name, \ | ||
| 1205 | TP_PROTO( \ | ||
| 1206 | const struct nfs_client *clp, \ | ||
| 1207 | const struct nfs_fh *fhandle, \ | ||
| 1208 | const struct inode *inode, \ | ||
| 1209 | const nfs4_stateid *stateid, \ | ||
| 1210 | int error \ | ||
| 1211 | ), \ | ||
| 1212 | TP_ARGS(clp, fhandle, inode, stateid, error)) | ||
| 1213 | DEFINE_NFS4_INODE_STATEID_CALLBACK_EVENT(nfs4_cb_recall); | ||
| 1214 | DEFINE_NFS4_INODE_STATEID_CALLBACK_EVENT(nfs4_cb_layoutrecall_file); | ||
| 1150 | 1215 | ||
| 1151 | DECLARE_EVENT_CLASS(nfs4_idmap_event, | 1216 | DECLARE_EVENT_CLASS(nfs4_idmap_event, |
| 1152 | TP_PROTO( | 1217 | TP_PROTO( |
diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h index 59f838cdc009..9f80a086b612 100644 --- a/fs/nfs/nfstrace.h +++ b/fs/nfs/nfstrace.h | |||
| @@ -39,7 +39,6 @@ | |||
| 39 | { 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \ | 39 | { 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \ |
| 40 | { 1 << NFS_INO_FLUSHING, "FLUSHING" }, \ | 40 | { 1 << NFS_INO_FLUSHING, "FLUSHING" }, \ |
| 41 | { 1 << NFS_INO_FSCACHE, "FSCACHE" }, \ | 41 | { 1 << NFS_INO_FSCACHE, "FSCACHE" }, \ |
| 42 | { 1 << NFS_INO_COMMIT, "COMMIT" }, \ | ||
| 43 | { 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \ | 42 | { 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \ |
| 44 | { 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" }) | 43 | { 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" }) |
| 45 | 44 | ||
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 7c71b71016b5..eeddbf0bf4c4 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
| @@ -899,12 +899,6 @@ static void nfs_pageio_cleanup_mirroring(struct nfs_pageio_descriptor *pgio) | |||
| 899 | pgio->pg_mirrors_dynamic = NULL; | 899 | pgio->pg_mirrors_dynamic = NULL; |
| 900 | } | 900 | } |
| 901 | 901 | ||
| 902 | static bool nfs_match_open_context(const struct nfs_open_context *ctx1, | ||
| 903 | const struct nfs_open_context *ctx2) | ||
| 904 | { | ||
| 905 | return ctx1->cred == ctx2->cred && ctx1->state == ctx2->state; | ||
| 906 | } | ||
| 907 | |||
| 908 | static bool nfs_match_lock_context(const struct nfs_lock_context *l1, | 902 | static bool nfs_match_lock_context(const struct nfs_lock_context *l1, |
| 909 | const struct nfs_lock_context *l2) | 903 | const struct nfs_lock_context *l2) |
| 910 | { | 904 | { |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 113c3b327e24..a3592cc34a20 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
| @@ -53,7 +53,7 @@ static DEFINE_SPINLOCK(pnfs_spinlock); | |||
| 53 | static LIST_HEAD(pnfs_modules_tbl); | 53 | static LIST_HEAD(pnfs_modules_tbl); |
| 54 | 54 | ||
| 55 | static int | 55 | static int |
| 56 | pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, nfs4_stateid stateid, | 56 | pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid, |
| 57 | enum pnfs_iomode iomode, bool sync); | 57 | enum pnfs_iomode iomode, bool sync); |
| 58 | 58 | ||
| 59 | /* Return the registered pnfs layout driver module matching given id */ | 59 | /* Return the registered pnfs layout driver module matching given id */ |
| @@ -385,13 +385,13 @@ static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg, | |||
| 385 | enum pnfs_iomode iomode; | 385 | enum pnfs_iomode iomode; |
| 386 | bool send; | 386 | bool send; |
| 387 | 387 | ||
| 388 | stateid = lo->plh_stateid; | 388 | nfs4_stateid_copy(&stateid, &lo->plh_stateid); |
| 389 | iomode = lo->plh_return_iomode; | 389 | iomode = lo->plh_return_iomode; |
| 390 | send = pnfs_prepare_layoutreturn(lo); | 390 | send = pnfs_prepare_layoutreturn(lo); |
| 391 | spin_unlock(&inode->i_lock); | 391 | spin_unlock(&inode->i_lock); |
| 392 | if (send) { | 392 | if (send) { |
| 393 | /* Send an async layoutreturn so we dont deadlock */ | 393 | /* Send an async layoutreturn so we dont deadlock */ |
| 394 | pnfs_send_layoutreturn(lo, stateid, iomode, false); | 394 | pnfs_send_layoutreturn(lo, &stateid, iomode, false); |
| 395 | } | 395 | } |
| 396 | } else | 396 | } else |
| 397 | spin_unlock(&inode->i_lock); | 397 | spin_unlock(&inode->i_lock); |
| @@ -566,10 +566,10 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, | |||
| 566 | int | 566 | int |
| 567 | pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, | 567 | pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, |
| 568 | struct list_head *tmp_list, | 568 | struct list_head *tmp_list, |
| 569 | struct pnfs_layout_range *recall_range) | 569 | const struct pnfs_layout_range *recall_range) |
| 570 | { | 570 | { |
| 571 | struct pnfs_layout_segment *lseg, *next; | 571 | struct pnfs_layout_segment *lseg, *next; |
| 572 | int invalid = 0, removed = 0; | 572 | int remaining = 0; |
| 573 | 573 | ||
| 574 | dprintk("%s:Begin lo %p\n", __func__, lo); | 574 | dprintk("%s:Begin lo %p\n", __func__, lo); |
| 575 | 575 | ||
| @@ -582,11 +582,11 @@ pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, | |||
| 582 | "offset %llu length %llu\n", __func__, | 582 | "offset %llu length %llu\n", __func__, |
| 583 | lseg, lseg->pls_range.iomode, lseg->pls_range.offset, | 583 | lseg, lseg->pls_range.iomode, lseg->pls_range.offset, |
| 584 | lseg->pls_range.length); | 584 | lseg->pls_range.length); |
| 585 | invalid++; | 585 | if (!mark_lseg_invalid(lseg, tmp_list)) |
| 586 | removed += mark_lseg_invalid(lseg, tmp_list); | 586 | remaining++; |
| 587 | } | 587 | } |
| 588 | dprintk("%s:Return %i\n", __func__, invalid - removed); | 588 | dprintk("%s:Return %i\n", __func__, remaining); |
| 589 | return invalid - removed; | 589 | return remaining; |
| 590 | } | 590 | } |
| 591 | 591 | ||
| 592 | /* note free_me must contain lsegs from a single layout_hdr */ | 592 | /* note free_me must contain lsegs from a single layout_hdr */ |
| @@ -702,6 +702,8 @@ pnfs_layout_free_bulk_destroy_list(struct list_head *layout_list, | |||
| 702 | ret = -EAGAIN; | 702 | ret = -EAGAIN; |
| 703 | spin_unlock(&inode->i_lock); | 703 | spin_unlock(&inode->i_lock); |
| 704 | pnfs_free_lseg_list(&lseg_list); | 704 | pnfs_free_lseg_list(&lseg_list); |
| 705 | /* Free all lsegs that are attached to commit buckets */ | ||
| 706 | nfs_commit_inode(inode, 0); | ||
| 705 | pnfs_put_layout_hdr(lo); | 707 | pnfs_put_layout_hdr(lo); |
| 706 | iput(inode); | 708 | iput(inode); |
| 707 | } | 709 | } |
| @@ -825,7 +827,7 @@ pnfs_layoutgets_blocked(const struct pnfs_layout_hdr *lo) | |||
| 825 | 827 | ||
| 826 | int | 828 | int |
| 827 | pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo, | 829 | pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo, |
| 828 | struct pnfs_layout_range *range, | 830 | const struct pnfs_layout_range *range, |
| 829 | struct nfs4_state *open_state) | 831 | struct nfs4_state *open_state) |
| 830 | { | 832 | { |
| 831 | int status = 0; | 833 | int status = 0; |
| @@ -860,7 +862,7 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo, | |||
| 860 | static struct pnfs_layout_segment * | 862 | static struct pnfs_layout_segment * |
| 861 | send_layoutget(struct pnfs_layout_hdr *lo, | 863 | send_layoutget(struct pnfs_layout_hdr *lo, |
| 862 | struct nfs_open_context *ctx, | 864 | struct nfs_open_context *ctx, |
| 863 | struct pnfs_layout_range *range, | 865 | const struct pnfs_layout_range *range, |
| 864 | gfp_t gfp_flags) | 866 | gfp_t gfp_flags) |
| 865 | { | 867 | { |
| 866 | struct inode *ino = lo->plh_inode; | 868 | struct inode *ino = lo->plh_inode; |
| @@ -893,7 +895,7 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
| 893 | lgp->args.minlength = i_size - range->offset; | 895 | lgp->args.minlength = i_size - range->offset; |
| 894 | } | 896 | } |
| 895 | lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; | 897 | lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; |
| 896 | lgp->args.range = *range; | 898 | pnfs_copy_range(&lgp->args.range, range); |
| 897 | lgp->args.type = server->pnfs_curr_ld->id; | 899 | lgp->args.type = server->pnfs_curr_ld->id; |
| 898 | lgp->args.inode = ino; | 900 | lgp->args.inode = ino; |
| 899 | lgp->args.ctx = get_nfs_open_context(ctx); | 901 | lgp->args.ctx = get_nfs_open_context(ctx); |
| @@ -936,7 +938,7 @@ void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo) | |||
| 936 | } | 938 | } |
| 937 | 939 | ||
| 938 | static int | 940 | static int |
| 939 | pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, nfs4_stateid stateid, | 941 | pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid, |
| 940 | enum pnfs_iomode iomode, bool sync) | 942 | enum pnfs_iomode iomode, bool sync) |
| 941 | { | 943 | { |
| 942 | struct inode *ino = lo->plh_inode; | 944 | struct inode *ino = lo->plh_inode; |
| @@ -953,7 +955,7 @@ pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, nfs4_stateid stateid, | |||
| 953 | goto out; | 955 | goto out; |
| 954 | } | 956 | } |
| 955 | 957 | ||
| 956 | lrp->args.stateid = stateid; | 958 | nfs4_stateid_copy(&lrp->args.stateid, stateid); |
| 957 | lrp->args.layout_type = NFS_SERVER(ino)->pnfs_curr_ld->id; | 959 | lrp->args.layout_type = NFS_SERVER(ino)->pnfs_curr_ld->id; |
| 958 | lrp->args.inode = ino; | 960 | lrp->args.inode = ino; |
| 959 | lrp->args.range.iomode = iomode; | 961 | lrp->args.range.iomode = iomode; |
| @@ -996,7 +998,7 @@ _pnfs_return_layout(struct inode *ino) | |||
| 996 | dprintk("NFS: %s no layout to return\n", __func__); | 998 | dprintk("NFS: %s no layout to return\n", __func__); |
| 997 | goto out; | 999 | goto out; |
| 998 | } | 1000 | } |
| 999 | stateid = nfsi->layout->plh_stateid; | 1001 | nfs4_stateid_copy(&stateid, &nfsi->layout->plh_stateid); |
| 1000 | /* Reference matched in nfs4_layoutreturn_release */ | 1002 | /* Reference matched in nfs4_layoutreturn_release */ |
| 1001 | pnfs_get_layout_hdr(lo); | 1003 | pnfs_get_layout_hdr(lo); |
| 1002 | empty = list_empty(&lo->plh_segs); | 1004 | empty = list_empty(&lo->plh_segs); |
| @@ -1024,7 +1026,7 @@ _pnfs_return_layout(struct inode *ino) | |||
| 1024 | spin_unlock(&ino->i_lock); | 1026 | spin_unlock(&ino->i_lock); |
| 1025 | pnfs_free_lseg_list(&tmp_list); | 1027 | pnfs_free_lseg_list(&tmp_list); |
| 1026 | if (send) | 1028 | if (send) |
| 1027 | status = pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true); | 1029 | status = pnfs_send_layoutreturn(lo, &stateid, IOMODE_ANY, true); |
| 1028 | out_put_layout_hdr: | 1030 | out_put_layout_hdr: |
| 1029 | pnfs_put_layout_hdr(lo); | 1031 | pnfs_put_layout_hdr(lo); |
| 1030 | out: | 1032 | out: |
| @@ -1087,7 +1089,7 @@ bool pnfs_roc(struct inode *ino) | |||
| 1087 | goto out_noroc; | 1089 | goto out_noroc; |
| 1088 | } | 1090 | } |
| 1089 | 1091 | ||
| 1090 | stateid = lo->plh_stateid; | 1092 | nfs4_stateid_copy(&stateid, &lo->plh_stateid); |
| 1091 | /* always send layoutreturn if being marked so */ | 1093 | /* always send layoutreturn if being marked so */ |
| 1092 | if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, | 1094 | if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, |
| 1093 | &lo->plh_flags)) | 1095 | &lo->plh_flags)) |
| @@ -1114,7 +1116,7 @@ out_noroc: | |||
| 1114 | pnfs_free_lseg_list(&tmp_list); | 1116 | pnfs_free_lseg_list(&tmp_list); |
| 1115 | pnfs_layoutcommit_inode(ino, true); | 1117 | pnfs_layoutcommit_inode(ino, true); |
| 1116 | if (layoutreturn) | 1118 | if (layoutreturn) |
| 1117 | pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true); | 1119 | pnfs_send_layoutreturn(lo, &stateid, IOMODE_ANY, true); |
| 1118 | return roc; | 1120 | return roc; |
| 1119 | } | 1121 | } |
| 1120 | 1122 | ||
| @@ -1139,6 +1141,7 @@ void pnfs_roc_set_barrier(struct inode *ino, u32 barrier) | |||
| 1139 | 1141 | ||
| 1140 | spin_lock(&ino->i_lock); | 1142 | spin_lock(&ino->i_lock); |
| 1141 | lo = NFS_I(ino)->layout; | 1143 | lo = NFS_I(ino)->layout; |
| 1144 | pnfs_mark_layout_returned_if_empty(lo); | ||
| 1142 | if (pnfs_seqid_is_newer(barrier, lo->plh_barrier)) | 1145 | if (pnfs_seqid_is_newer(barrier, lo->plh_barrier)) |
| 1143 | lo->plh_barrier = barrier; | 1146 | lo->plh_barrier = barrier; |
| 1144 | spin_unlock(&ino->i_lock); | 1147 | spin_unlock(&ino->i_lock); |
| @@ -1734,16 +1737,29 @@ out_forget_reply: | |||
| 1734 | } | 1737 | } |
| 1735 | 1738 | ||
| 1736 | static void | 1739 | static void |
| 1740 | pnfs_set_plh_return_iomode(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode) | ||
| 1741 | { | ||
| 1742 | if (lo->plh_return_iomode == iomode) | ||
| 1743 | return; | ||
| 1744 | if (lo->plh_return_iomode != 0) | ||
| 1745 | iomode = IOMODE_ANY; | ||
| 1746 | lo->plh_return_iomode = iomode; | ||
| 1747 | } | ||
| 1748 | |||
| 1749 | int | ||
| 1737 | pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, | 1750 | pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, |
| 1738 | struct list_head *tmp_list, | 1751 | struct list_head *tmp_list, |
| 1739 | struct pnfs_layout_range *return_range) | 1752 | const struct pnfs_layout_range *return_range) |
| 1740 | { | 1753 | { |
| 1741 | struct pnfs_layout_segment *lseg, *next; | 1754 | struct pnfs_layout_segment *lseg, *next; |
| 1755 | int remaining = 0; | ||
| 1742 | 1756 | ||
| 1743 | dprintk("%s:Begin lo %p\n", __func__, lo); | 1757 | dprintk("%s:Begin lo %p\n", __func__, lo); |
| 1744 | 1758 | ||
| 1745 | if (list_empty(&lo->plh_segs)) | 1759 | if (list_empty(&lo->plh_segs)) |
| 1746 | return; | 1760 | return 0; |
| 1761 | |||
| 1762 | assert_spin_locked(&lo->plh_inode->i_lock); | ||
| 1747 | 1763 | ||
| 1748 | list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) | 1764 | list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) |
| 1749 | if (should_free_lseg(&lseg->pls_range, return_range)) { | 1765 | if (should_free_lseg(&lseg->pls_range, return_range)) { |
| @@ -1753,10 +1769,13 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, | |||
| 1753 | lseg->pls_range.offset, | 1769 | lseg->pls_range.offset, |
| 1754 | lseg->pls_range.length); | 1770 | lseg->pls_range.length); |
| 1755 | set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags); | 1771 | set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags); |
| 1756 | mark_lseg_invalid(lseg, tmp_list); | 1772 | pnfs_set_plh_return_iomode(lo, return_range->iomode); |
| 1773 | if (!mark_lseg_invalid(lseg, tmp_list)) | ||
| 1774 | remaining++; | ||
| 1757 | set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, | 1775 | set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, |
| 1758 | &lo->plh_flags); | 1776 | &lo->plh_flags); |
| 1759 | } | 1777 | } |
| 1778 | return remaining; | ||
| 1760 | } | 1779 | } |
| 1761 | 1780 | ||
| 1762 | void pnfs_error_mark_layout_for_return(struct inode *inode, | 1781 | void pnfs_error_mark_layout_for_return(struct inode *inode, |
| @@ -1769,19 +1788,28 @@ void pnfs_error_mark_layout_for_return(struct inode *inode, | |||
| 1769 | .length = NFS4_MAX_UINT64, | 1788 | .length = NFS4_MAX_UINT64, |
| 1770 | }; | 1789 | }; |
| 1771 | LIST_HEAD(free_me); | 1790 | LIST_HEAD(free_me); |
| 1791 | bool return_now = false; | ||
| 1772 | 1792 | ||
| 1773 | spin_lock(&inode->i_lock); | 1793 | spin_lock(&inode->i_lock); |
| 1774 | if (lo->plh_return_iomode == 0) | 1794 | pnfs_set_plh_return_iomode(lo, range.iomode); |
| 1775 | lo->plh_return_iomode = range.iomode; | ||
| 1776 | else if (lo->plh_return_iomode != range.iomode) | ||
| 1777 | lo->plh_return_iomode = IOMODE_ANY; | ||
| 1778 | /* | 1795 | /* |
| 1779 | * mark all matching lsegs so that we are sure to have no live | 1796 | * mark all matching lsegs so that we are sure to have no live |
| 1780 | * segments at hand when sending layoutreturn. See pnfs_put_lseg() | 1797 | * segments at hand when sending layoutreturn. See pnfs_put_lseg() |
| 1781 | * for how it works. | 1798 | * for how it works. |
| 1782 | */ | 1799 | */ |
| 1783 | pnfs_mark_matching_lsegs_return(lo, &free_me, &range); | 1800 | if (!pnfs_mark_matching_lsegs_return(lo, &free_me, &range)) { |
| 1784 | spin_unlock(&inode->i_lock); | 1801 | nfs4_stateid stateid; |
| 1802 | enum pnfs_iomode iomode = lo->plh_return_iomode; | ||
| 1803 | |||
| 1804 | nfs4_stateid_copy(&stateid, &lo->plh_stateid); | ||
| 1805 | return_now = pnfs_prepare_layoutreturn(lo); | ||
| 1806 | spin_unlock(&inode->i_lock); | ||
| 1807 | if (return_now) | ||
| 1808 | pnfs_send_layoutreturn(lo, &stateid, iomode, false); | ||
| 1809 | } else { | ||
| 1810 | spin_unlock(&inode->i_lock); | ||
| 1811 | nfs_commit_inode(inode, 0); | ||
| 1812 | } | ||
| 1785 | pnfs_free_lseg_list(&free_me); | 1813 | pnfs_free_lseg_list(&free_me); |
| 1786 | } | 1814 | } |
| 1787 | EXPORT_SYMBOL_GPL(pnfs_error_mark_layout_for_return); | 1815 | EXPORT_SYMBOL_GPL(pnfs_error_mark_layout_for_return); |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 6916ff4e86f9..9f4e2a47f4aa 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
| @@ -260,11 +260,14 @@ void pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, | |||
| 260 | bool update_barrier); | 260 | bool update_barrier); |
| 261 | int pnfs_choose_layoutget_stateid(nfs4_stateid *dst, | 261 | int pnfs_choose_layoutget_stateid(nfs4_stateid *dst, |
| 262 | struct pnfs_layout_hdr *lo, | 262 | struct pnfs_layout_hdr *lo, |
| 263 | struct pnfs_layout_range *range, | 263 | const struct pnfs_layout_range *range, |
| 264 | struct nfs4_state *open_state); | 264 | struct nfs4_state *open_state); |
| 265 | int pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, | 265 | int pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, |
| 266 | struct list_head *tmp_list, | 266 | struct list_head *tmp_list, |
| 267 | struct pnfs_layout_range *recall_range); | 267 | const struct pnfs_layout_range *recall_range); |
| 268 | int pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, | ||
| 269 | struct list_head *tmp_list, | ||
| 270 | const struct pnfs_layout_range *recall_range); | ||
| 268 | bool pnfs_roc(struct inode *ino); | 271 | bool pnfs_roc(struct inode *ino); |
| 269 | void pnfs_roc_release(struct inode *ino); | 272 | void pnfs_roc_release(struct inode *ino); |
| 270 | void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); | 273 | void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); |
| @@ -388,6 +391,12 @@ pnfs_get_lseg(struct pnfs_layout_segment *lseg) | |||
| 388 | return lseg; | 391 | return lseg; |
| 389 | } | 392 | } |
| 390 | 393 | ||
| 394 | static inline bool | ||
| 395 | pnfs_is_valid_lseg(struct pnfs_layout_segment *lseg) | ||
| 396 | { | ||
| 397 | return test_bit(NFS_LSEG_VALID, &lseg->pls_flags) != 0; | ||
| 398 | } | ||
| 399 | |||
| 391 | /* Return true if a layout driver is being used for this mountpoint */ | 400 | /* Return true if a layout driver is being used for this mountpoint */ |
| 392 | static inline int pnfs_enabled_sb(struct nfs_server *nfss) | 401 | static inline int pnfs_enabled_sb(struct nfs_server *nfss) |
| 393 | { | 402 | { |
| @@ -535,6 +544,26 @@ pnfs_calc_offset_length(u64 offset, u64 end) | |||
| 535 | return 1 + end - offset; | 544 | return 1 + end - offset; |
| 536 | } | 545 | } |
| 537 | 546 | ||
| 547 | /** | ||
| 548 | * pnfs_mark_layout_returned_if_empty - marks the layout as returned | ||
| 549 | * @lo: layout header | ||
| 550 | * | ||
| 551 | * Note: Caller must hold inode->i_lock | ||
| 552 | */ | ||
| 553 | static inline void | ||
| 554 | pnfs_mark_layout_returned_if_empty(struct pnfs_layout_hdr *lo) | ||
| 555 | { | ||
| 556 | if (list_empty(&lo->plh_segs)) | ||
| 557 | set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); | ||
| 558 | } | ||
| 559 | |||
| 560 | static inline void | ||
| 561 | pnfs_copy_range(struct pnfs_layout_range *dst, | ||
| 562 | const struct pnfs_layout_range *src) | ||
| 563 | { | ||
| 564 | memcpy(dst, src, sizeof(*dst)); | ||
| 565 | } | ||
| 566 | |||
| 538 | extern unsigned int layoutstats_timer; | 567 | extern unsigned int layoutstats_timer; |
| 539 | 568 | ||
| 540 | #ifdef NFS_DEBUG | 569 | #ifdef NFS_DEBUG |
diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c index 24655b807d44..81ac6480f9e7 100644 --- a/fs/nfs/pnfs_nfs.c +++ b/fs/nfs/pnfs_nfs.c | |||
| @@ -266,17 +266,14 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages, | |||
| 266 | } else { | 266 | } else { |
| 267 | nfs_retry_commit(mds_pages, NULL, cinfo, 0); | 267 | nfs_retry_commit(mds_pages, NULL, cinfo, 0); |
| 268 | pnfs_generic_retry_commit(cinfo, 0); | 268 | pnfs_generic_retry_commit(cinfo, 0); |
| 269 | cinfo->completion_ops->error_cleanup(NFS_I(inode)); | ||
| 270 | return -ENOMEM; | 269 | return -ENOMEM; |
| 271 | } | 270 | } |
| 272 | } | 271 | } |
| 273 | 272 | ||
| 274 | nreq += pnfs_generic_alloc_ds_commits(cinfo, &list); | 273 | nreq += pnfs_generic_alloc_ds_commits(cinfo, &list); |
| 275 | 274 | ||
| 276 | if (nreq == 0) { | 275 | if (nreq == 0) |
| 277 | cinfo->completion_ops->error_cleanup(NFS_I(inode)); | ||
| 278 | goto out; | 276 | goto out; |
| 279 | } | ||
| 280 | 277 | ||
| 281 | atomic_add(nreq, &cinfo->mds->rpcs_out); | 278 | atomic_add(nreq, &cinfo->mds->rpcs_out); |
| 282 | 279 | ||
| @@ -871,6 +868,11 @@ pnfs_layout_mark_request_commit(struct nfs_page *req, | |||
| 871 | buckets = cinfo->ds->buckets; | 868 | buckets = cinfo->ds->buckets; |
| 872 | list = &buckets[ds_commit_idx].written; | 869 | list = &buckets[ds_commit_idx].written; |
| 873 | if (list_empty(list)) { | 870 | if (list_empty(list)) { |
| 871 | if (!pnfs_is_valid_lseg(lseg)) { | ||
| 872 | spin_unlock(cinfo->lock); | ||
| 873 | cinfo->completion_ops->resched_write(cinfo, req); | ||
| 874 | return; | ||
| 875 | } | ||
| 874 | /* Non-empty buckets hold a reference on the lseg. That ref | 876 | /* Non-empty buckets hold a reference on the lseg. That ref |
| 875 | * is normally transferred to the COMMIT call and released | 877 | * is normally transferred to the COMMIT call and released |
| 876 | * there. It could also be released if the last req is pulled | 878 | * there. It could also be released if the last req is pulled |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 4d254232d728..94828b3f8c95 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -21,6 +21,8 @@ | |||
| 21 | #include <linux/nfs_page.h> | 21 | #include <linux/nfs_page.h> |
| 22 | #include <linux/backing-dev.h> | 22 | #include <linux/backing-dev.h> |
| 23 | #include <linux/export.h> | 23 | #include <linux/export.h> |
| 24 | #include <linux/freezer.h> | ||
| 25 | #include <linux/wait.h> | ||
| 24 | 26 | ||
| 25 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
| 26 | 28 | ||
| @@ -1155,7 +1157,8 @@ int nfs_flush_incompatible(struct file *file, struct page *page) | |||
| 1155 | if (req == NULL) | 1157 | if (req == NULL) |
| 1156 | return 0; | 1158 | return 0; |
| 1157 | l_ctx = req->wb_lock_context; | 1159 | l_ctx = req->wb_lock_context; |
| 1158 | do_flush = req->wb_page != page || req->wb_context != ctx; | 1160 | do_flush = req->wb_page != page || |
| 1161 | !nfs_match_open_context(req->wb_context, ctx); | ||
| 1159 | /* for now, flush if more than 1 request in page_group */ | 1162 | /* for now, flush if more than 1 request in page_group */ |
| 1160 | do_flush |= req->wb_this_page != req; | 1163 | do_flush |= req->wb_this_page != req; |
| 1161 | if (l_ctx && flctx && | 1164 | if (l_ctx && flctx && |
| @@ -1353,9 +1356,15 @@ static void nfs_async_write_error(struct list_head *head) | |||
| 1353 | } | 1356 | } |
| 1354 | } | 1357 | } |
| 1355 | 1358 | ||
| 1359 | static void nfs_async_write_reschedule_io(struct nfs_pgio_header *hdr) | ||
| 1360 | { | ||
| 1361 | nfs_async_write_error(&hdr->pages); | ||
| 1362 | } | ||
| 1363 | |||
| 1356 | static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops = { | 1364 | static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops = { |
| 1357 | .error_cleanup = nfs_async_write_error, | 1365 | .error_cleanup = nfs_async_write_error, |
| 1358 | .completion = nfs_write_completion, | 1366 | .completion = nfs_write_completion, |
| 1367 | .reschedule_io = nfs_async_write_reschedule_io, | ||
| 1359 | }; | 1368 | }; |
| 1360 | 1369 | ||
| 1361 | void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | 1370 | void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
| @@ -1556,27 +1565,29 @@ static void nfs_writeback_result(struct rpc_task *task, | |||
| 1556 | } | 1565 | } |
| 1557 | } | 1566 | } |
| 1558 | 1567 | ||
| 1568 | static int nfs_wait_atomic_killable(atomic_t *key) | ||
| 1569 | { | ||
| 1570 | if (fatal_signal_pending(current)) | ||
| 1571 | return -ERESTARTSYS; | ||
| 1572 | freezable_schedule_unsafe(); | ||
| 1573 | return 0; | ||
| 1574 | } | ||
| 1559 | 1575 | ||
| 1560 | static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) | 1576 | static int wait_on_commit(struct nfs_mds_commit_info *cinfo) |
| 1561 | { | 1577 | { |
| 1562 | int ret; | 1578 | return wait_on_atomic_t(&cinfo->rpcs_out, |
| 1579 | nfs_wait_atomic_killable, TASK_KILLABLE); | ||
| 1580 | } | ||
| 1563 | 1581 | ||
| 1564 | if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags)) | 1582 | static void nfs_commit_begin(struct nfs_mds_commit_info *cinfo) |
| 1565 | return 1; | 1583 | { |
| 1566 | if (!may_wait) | 1584 | atomic_inc(&cinfo->rpcs_out); |
| 1567 | return 0; | ||
| 1568 | ret = out_of_line_wait_on_bit_lock(&nfsi->flags, | ||
| 1569 | NFS_INO_COMMIT, | ||
| 1570 | nfs_wait_bit_killable, | ||
| 1571 | TASK_KILLABLE); | ||
| 1572 | return (ret < 0) ? ret : 1; | ||
| 1573 | } | 1585 | } |
| 1574 | 1586 | ||
| 1575 | static void nfs_commit_clear_lock(struct nfs_inode *nfsi) | 1587 | static void nfs_commit_end(struct nfs_mds_commit_info *cinfo) |
| 1576 | { | 1588 | { |
| 1577 | clear_bit(NFS_INO_COMMIT, &nfsi->flags); | 1589 | if (atomic_dec_and_test(&cinfo->rpcs_out)) |
| 1578 | smp_mb__after_atomic(); | 1590 | wake_up_atomic_t(&cinfo->rpcs_out); |
| 1579 | wake_up_bit(&nfsi->flags, NFS_INO_COMMIT); | ||
| 1580 | } | 1591 | } |
| 1581 | 1592 | ||
| 1582 | void nfs_commitdata_release(struct nfs_commit_data *data) | 1593 | void nfs_commitdata_release(struct nfs_commit_data *data) |
| @@ -1693,6 +1704,13 @@ void nfs_retry_commit(struct list_head *page_list, | |||
| 1693 | } | 1704 | } |
| 1694 | EXPORT_SYMBOL_GPL(nfs_retry_commit); | 1705 | EXPORT_SYMBOL_GPL(nfs_retry_commit); |
| 1695 | 1706 | ||
| 1707 | static void | ||
| 1708 | nfs_commit_resched_write(struct nfs_commit_info *cinfo, | ||
| 1709 | struct nfs_page *req) | ||
| 1710 | { | ||
| 1711 | __set_page_dirty_nobuffers(req->wb_page); | ||
| 1712 | } | ||
| 1713 | |||
| 1696 | /* | 1714 | /* |
| 1697 | * Commit dirty pages | 1715 | * Commit dirty pages |
| 1698 | */ | 1716 | */ |
| @@ -1714,7 +1732,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how, | |||
| 1714 | data->mds_ops, how, 0); | 1732 | data->mds_ops, how, 0); |
| 1715 | out_bad: | 1733 | out_bad: |
| 1716 | nfs_retry_commit(head, NULL, cinfo, 0); | 1734 | nfs_retry_commit(head, NULL, cinfo, 0); |
| 1717 | cinfo->completion_ops->error_cleanup(NFS_I(inode)); | ||
| 1718 | return -ENOMEM; | 1735 | return -ENOMEM; |
| 1719 | } | 1736 | } |
| 1720 | 1737 | ||
| @@ -1776,8 +1793,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) | |||
| 1776 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | 1793 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
| 1777 | 1794 | ||
| 1778 | nfs_init_cinfo(&cinfo, data->inode, data->dreq); | 1795 | nfs_init_cinfo(&cinfo, data->inode, data->dreq); |
| 1779 | if (atomic_dec_and_test(&cinfo.mds->rpcs_out)) | 1796 | nfs_commit_end(cinfo.mds); |
| 1780 | nfs_commit_clear_lock(NFS_I(data->inode)); | ||
| 1781 | } | 1797 | } |
| 1782 | 1798 | ||
| 1783 | static void nfs_commit_release(void *calldata) | 1799 | static void nfs_commit_release(void *calldata) |
| @@ -1796,7 +1812,7 @@ static const struct rpc_call_ops nfs_commit_ops = { | |||
| 1796 | 1812 | ||
| 1797 | static const struct nfs_commit_completion_ops nfs_commit_completion_ops = { | 1813 | static const struct nfs_commit_completion_ops nfs_commit_completion_ops = { |
| 1798 | .completion = nfs_commit_release_pages, | 1814 | .completion = nfs_commit_release_pages, |
| 1799 | .error_cleanup = nfs_commit_clear_lock, | 1815 | .resched_write = nfs_commit_resched_write, |
| 1800 | }; | 1816 | }; |
| 1801 | 1817 | ||
| 1802 | int nfs_generic_commit_list(struct inode *inode, struct list_head *head, | 1818 | int nfs_generic_commit_list(struct inode *inode, struct list_head *head, |
| @@ -1815,30 +1831,25 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
| 1815 | LIST_HEAD(head); | 1831 | LIST_HEAD(head); |
| 1816 | struct nfs_commit_info cinfo; | 1832 | struct nfs_commit_info cinfo; |
| 1817 | int may_wait = how & FLUSH_SYNC; | 1833 | int may_wait = how & FLUSH_SYNC; |
| 1834 | int error = 0; | ||
| 1818 | int res; | 1835 | int res; |
| 1819 | 1836 | ||
| 1820 | res = nfs_commit_set_lock(NFS_I(inode), may_wait); | ||
| 1821 | if (res <= 0) | ||
| 1822 | goto out_mark_dirty; | ||
| 1823 | nfs_init_cinfo_from_inode(&cinfo, inode); | 1837 | nfs_init_cinfo_from_inode(&cinfo, inode); |
| 1838 | nfs_commit_begin(cinfo.mds); | ||
| 1824 | res = nfs_scan_commit(inode, &head, &cinfo); | 1839 | res = nfs_scan_commit(inode, &head, &cinfo); |
| 1825 | if (res) { | 1840 | if (res) |
| 1826 | int error; | ||
| 1827 | |||
| 1828 | error = nfs_generic_commit_list(inode, &head, how, &cinfo); | 1841 | error = nfs_generic_commit_list(inode, &head, how, &cinfo); |
| 1829 | if (error < 0) | 1842 | nfs_commit_end(cinfo.mds); |
| 1830 | return error; | 1843 | if (error < 0) |
| 1831 | if (!may_wait) | 1844 | goto out_error; |
| 1832 | goto out_mark_dirty; | 1845 | if (!may_wait) |
| 1833 | error = wait_on_bit_action(&NFS_I(inode)->flags, | 1846 | goto out_mark_dirty; |
| 1834 | NFS_INO_COMMIT, | 1847 | error = wait_on_commit(cinfo.mds); |
| 1835 | nfs_wait_bit_killable, | 1848 | if (error < 0) |
| 1836 | TASK_KILLABLE); | 1849 | return error; |
| 1837 | if (error < 0) | ||
| 1838 | return error; | ||
| 1839 | } else | ||
| 1840 | nfs_commit_clear_lock(NFS_I(inode)); | ||
| 1841 | return res; | 1850 | return res; |
| 1851 | out_error: | ||
| 1852 | res = error; | ||
| 1842 | /* Note: If we exit without ensuring that the commit is complete, | 1853 | /* Note: If we exit without ensuring that the commit is complete, |
| 1843 | * we must mark the inode as dirty. Otherwise, future calls to | 1854 | * we must mark the inode as dirty. Otherwise, future calls to |
| 1844 | * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure | 1855 | * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure |
| @@ -1848,6 +1859,7 @@ out_mark_dirty: | |||
| 1848 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | 1859 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
| 1849 | return res; | 1860 | return res; |
| 1850 | } | 1861 | } |
| 1862 | EXPORT_SYMBOL_GPL(nfs_commit_inode); | ||
| 1851 | 1863 | ||
| 1852 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) | 1864 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) |
| 1853 | { | 1865 | { |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index b88fc46cfbb8..9eee972863a7 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
| @@ -216,7 +216,6 @@ struct nfs_inode { | |||
| 216 | #define NFS_INO_FLUSHING (4) /* inode is flushing out data */ | 216 | #define NFS_INO_FLUSHING (4) /* inode is flushing out data */ |
| 217 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ | 217 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ |
| 218 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ | 218 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ |
| 219 | #define NFS_INO_COMMIT (7) /* inode is committing unstable writes */ | ||
| 220 | #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ | 219 | #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ |
| 221 | #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ | 220 | #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ |
| 222 | #define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */ | 221 | #define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */ |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 7b30ac0c7def..791098a08a87 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
| @@ -1421,11 +1421,12 @@ struct nfs_mds_commit_info { | |||
| 1421 | struct list_head list; | 1421 | struct list_head list; |
| 1422 | }; | 1422 | }; |
| 1423 | 1423 | ||
| 1424 | struct nfs_commit_info; | ||
| 1424 | struct nfs_commit_data; | 1425 | struct nfs_commit_data; |
| 1425 | struct nfs_inode; | 1426 | struct nfs_inode; |
| 1426 | struct nfs_commit_completion_ops { | 1427 | struct nfs_commit_completion_ops { |
| 1427 | void (*error_cleanup) (struct nfs_inode *nfsi); | ||
| 1428 | void (*completion) (struct nfs_commit_data *data); | 1428 | void (*completion) (struct nfs_commit_data *data); |
| 1429 | void (*resched_write) (struct nfs_commit_info *, struct nfs_page *); | ||
| 1429 | }; | 1430 | }; |
| 1430 | 1431 | ||
| 1431 | struct nfs_commit_info { | 1432 | struct nfs_commit_info { |
| @@ -1462,6 +1463,7 @@ struct nfs_pgio_completion_ops { | |||
| 1462 | void (*error_cleanup)(struct list_head *head); | 1463 | void (*error_cleanup)(struct list_head *head); |
| 1463 | void (*init_hdr)(struct nfs_pgio_header *hdr); | 1464 | void (*init_hdr)(struct nfs_pgio_header *hdr); |
| 1464 | void (*completion)(struct nfs_pgio_header *hdr); | 1465 | void (*completion)(struct nfs_pgio_header *hdr); |
| 1466 | void (*reschedule_io)(struct nfs_pgio_header *hdr); | ||
| 1465 | }; | 1467 | }; |
| 1466 | 1468 | ||
| 1467 | struct nfs_unlinkdata { | 1469 | struct nfs_unlinkdata { |
