diff options
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r-- | fs/nfs/direct.c | 112 |
1 files changed, 95 insertions, 17 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 294692ff83b1..7077521acdf4 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -66,6 +66,10 @@ static struct kmem_cache *nfs_direct_cachep; | |||
66 | /* | 66 | /* |
67 | * This represents a set of asynchronous requests that we're waiting on | 67 | * This represents a set of asynchronous requests that we're waiting on |
68 | */ | 68 | */ |
69 | struct nfs_direct_mirror { | ||
70 | ssize_t count; | ||
71 | }; | ||
72 | |||
69 | struct nfs_direct_req { | 73 | struct nfs_direct_req { |
70 | struct kref kref; /* release manager */ | 74 | struct kref kref; /* release manager */ |
71 | 75 | ||
@@ -78,8 +82,13 @@ struct nfs_direct_req { | |||
78 | /* completion state */ | 82 | /* completion state */ |
79 | atomic_t io_count; /* i/os we're waiting for */ | 83 | atomic_t io_count; /* i/os we're waiting for */ |
80 | spinlock_t lock; /* protect completion state */ | 84 | spinlock_t lock; /* protect completion state */ |
85 | |||
86 | struct nfs_direct_mirror mirrors[NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX]; | ||
87 | int mirror_count; | ||
88 | |||
81 | ssize_t count, /* bytes actually processed */ | 89 | ssize_t count, /* bytes actually processed */ |
82 | bytes_left, /* bytes left to be sent */ | 90 | bytes_left, /* bytes left to be sent */ |
91 | io_start, /* start of IO */ | ||
83 | error; /* any reported error */ | 92 | error; /* any reported error */ |
84 | struct completion completion; /* wait for i/o completion */ | 93 | struct completion completion; /* wait for i/o completion */ |
85 | 94 | ||
@@ -108,26 +117,56 @@ static inline int put_dreq(struct nfs_direct_req *dreq) | |||
108 | return atomic_dec_and_test(&dreq->io_count); | 117 | return atomic_dec_and_test(&dreq->io_count); |
109 | } | 118 | } |
110 | 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 | ||
127 | nfs_direct_good_bytes(struct nfs_direct_req *dreq, struct nfs_pgio_header *hdr) | ||
128 | { | ||
129 | int i; | ||
130 | ssize_t count; | ||
131 | |||
132 | WARN_ON_ONCE(hdr->pgio_mirror_idx >= dreq->mirror_count); | ||
133 | |||
134 | count = dreq->mirrors[hdr->pgio_mirror_idx].count; | ||
135 | if (count + dreq->io_start < hdr->io_start + hdr->good_bytes) { | ||
136 | count = hdr->io_start + hdr->good_bytes - dreq->io_start; | ||
137 | dreq->mirrors[hdr->pgio_mirror_idx].count = count; | ||
138 | } | ||
139 | |||
140 | /* update the dreq->count by finding the minimum agreed count from all | ||
141 | * mirrors */ | ||
142 | count = dreq->mirrors[0].count; | ||
143 | |||
144 | for (i = 1; i < dreq->mirror_count; i++) | ||
145 | count = min(count, dreq->mirrors[i].count); | ||
146 | |||
147 | dreq->count = count; | ||
148 | } | ||
149 | |||
111 | /* | 150 | /* |
112 | * nfs_direct_select_verf - select the right verifier | 151 | * nfs_direct_select_verf - select the right verifier |
113 | * @dreq - direct request possibly spanning multiple servers | 152 | * @dreq - direct request possibly spanning multiple servers |
114 | * @ds_clp - nfs_client of data server or NULL if MDS / non-pnfs | 153 | * @ds_clp - nfs_client of data server or NULL if MDS / non-pnfs |
115 | * @ds_idx - index of data server in data server list, only valid if ds_clp set | 154 | * @commit_idx - commit bucket index for the DS |
116 | * | 155 | * |
117 | * returns the correct verifier to use given the role of the server | 156 | * returns the correct verifier to use given the role of the server |
118 | */ | 157 | */ |
119 | static struct nfs_writeverf * | 158 | static struct nfs_writeverf * |
120 | nfs_direct_select_verf(struct nfs_direct_req *dreq, | 159 | nfs_direct_select_verf(struct nfs_direct_req *dreq, |
121 | struct nfs_client *ds_clp, | 160 | struct nfs_client *ds_clp, |
122 | int ds_idx) | 161 | int commit_idx) |
123 | { | 162 | { |
124 | struct nfs_writeverf *verfp = &dreq->verf; | 163 | struct nfs_writeverf *verfp = &dreq->verf; |
125 | 164 | ||
126 | #ifdef CONFIG_NFS_V4_1 | 165 | #ifdef CONFIG_NFS_V4_1 |
127 | if (ds_clp) { | 166 | if (ds_clp) { |
128 | /* pNFS is in use, use the DS verf */ | 167 | /* pNFS is in use, use the DS verf */ |
129 | if (ds_idx >= 0 && ds_idx < dreq->ds_cinfo.nbuckets) | 168 | if (commit_idx >= 0 && commit_idx < dreq->ds_cinfo.nbuckets) |
130 | verfp = &dreq->ds_cinfo.buckets[ds_idx].direct_verf; | 169 | verfp = &dreq->ds_cinfo.buckets[commit_idx].direct_verf; |
131 | else | 170 | else |
132 | WARN_ON_ONCE(1); | 171 | WARN_ON_ONCE(1); |
133 | } | 172 | } |
@@ -148,8 +187,7 @@ static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq, | |||
148 | { | 187 | { |
149 | struct nfs_writeverf *verfp; | 188 | struct nfs_writeverf *verfp; |
150 | 189 | ||
151 | verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, | 190 | verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, hdr->ds_commit_idx); |
152 | hdr->ds_idx); | ||
153 | WARN_ON_ONCE(verfp->committed >= 0); | 191 | WARN_ON_ONCE(verfp->committed >= 0); |
154 | memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); | 192 | memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); |
155 | WARN_ON_ONCE(verfp->committed < 0); | 193 | WARN_ON_ONCE(verfp->committed < 0); |
@@ -169,8 +207,7 @@ static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq, | |||
169 | { | 207 | { |
170 | struct nfs_writeverf *verfp; | 208 | struct nfs_writeverf *verfp; |
171 | 209 | ||
172 | verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, | 210 | verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, hdr->ds_commit_idx); |
173 | hdr->ds_idx); | ||
174 | if (verfp->committed < 0) { | 211 | if (verfp->committed < 0) { |
175 | nfs_direct_set_hdr_verf(dreq, hdr); | 212 | nfs_direct_set_hdr_verf(dreq, hdr); |
176 | return 0; | 213 | return 0; |
@@ -193,7 +230,11 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, | |||
193 | 230 | ||
194 | verfp = nfs_direct_select_verf(dreq, data->ds_clp, | 231 | verfp = nfs_direct_select_verf(dreq, data->ds_clp, |
195 | data->ds_commit_index); | 232 | data->ds_commit_index); |
196 | WARN_ON_ONCE(verfp->committed < 0); | 233 | |
234 | /* verifier not set so always fail */ | ||
235 | if (verfp->committed < 0) | ||
236 | return 1; | ||
237 | |||
197 | return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf)); | 238 | return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf)); |
198 | } | 239 | } |
199 | 240 | ||
@@ -249,6 +290,18 @@ void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, | |||
249 | cinfo->completion_ops = &nfs_direct_commit_completion_ops; | 290 | cinfo->completion_ops = &nfs_direct_commit_completion_ops; |
250 | } | 291 | } |
251 | 292 | ||
293 | static inline void nfs_direct_setup_mirroring(struct nfs_direct_req *dreq, | ||
294 | struct nfs_pageio_descriptor *pgio, | ||
295 | struct nfs_page *req) | ||
296 | { | ||
297 | int mirror_count = 1; | ||
298 | |||
299 | if (pgio->pg_ops->pg_get_mirror_count) | ||
300 | mirror_count = pgio->pg_ops->pg_get_mirror_count(pgio, req); | ||
301 | |||
302 | dreq->mirror_count = mirror_count; | ||
303 | } | ||
304 | |||
252 | static inline struct nfs_direct_req *nfs_direct_req_alloc(void) | 305 | static inline struct nfs_direct_req *nfs_direct_req_alloc(void) |
253 | { | 306 | { |
254 | struct nfs_direct_req *dreq; | 307 | struct nfs_direct_req *dreq; |
@@ -263,6 +316,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void) | |||
263 | INIT_LIST_HEAD(&dreq->mds_cinfo.list); | 316 | INIT_LIST_HEAD(&dreq->mds_cinfo.list); |
264 | dreq->verf.committed = NFS_INVALID_STABLE_HOW; /* not set yet */ | 317 | dreq->verf.committed = NFS_INVALID_STABLE_HOW; /* not set yet */ |
265 | INIT_WORK(&dreq->work, nfs_direct_write_schedule_work); | 318 | INIT_WORK(&dreq->work, nfs_direct_write_schedule_work); |
319 | dreq->mirror_count = 1; | ||
266 | spin_lock_init(&dreq->lock); | 320 | spin_lock_init(&dreq->lock); |
267 | 321 | ||
268 | return dreq; | 322 | return dreq; |
@@ -369,7 +423,8 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr) | |||
369 | if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && (hdr->good_bytes == 0)) | 423 | if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && (hdr->good_bytes == 0)) |
370 | dreq->error = hdr->error; | 424 | dreq->error = hdr->error; |
371 | else | 425 | else |
372 | dreq->count += hdr->good_bytes; | 426 | nfs_direct_good_bytes(dreq, hdr); |
427 | |||
373 | spin_unlock(&dreq->lock); | 428 | spin_unlock(&dreq->lock); |
374 | 429 | ||
375 | while (!list_empty(&hdr->pages)) { | 430 | while (!list_empty(&hdr->pages)) { |
@@ -547,6 +602,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter, | |||
547 | 602 | ||
548 | dreq->inode = inode; | 603 | dreq->inode = inode; |
549 | dreq->bytes_left = count; | 604 | dreq->bytes_left = count; |
605 | dreq->io_start = pos; | ||
550 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); | 606 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); |
551 | l_ctx = nfs_get_lock_context(dreq->ctx); | 607 | l_ctx = nfs_get_lock_context(dreq->ctx); |
552 | if (IS_ERR(l_ctx)) { | 608 | if (IS_ERR(l_ctx)) { |
@@ -579,6 +635,20 @@ out: | |||
579 | return result; | 635 | return result; |
580 | } | 636 | } |
581 | 637 | ||
638 | static void | ||
639 | nfs_direct_write_scan_commit_list(struct inode *inode, | ||
640 | struct list_head *list, | ||
641 | struct nfs_commit_info *cinfo) | ||
642 | { | ||
643 | spin_lock(cinfo->lock); | ||
644 | #ifdef CONFIG_NFS_V4_1 | ||
645 | if (cinfo->ds != NULL && cinfo->ds->nwritten != 0) | ||
646 | NFS_SERVER(inode)->pnfs_curr_ld->recover_commit_reqs(list, cinfo); | ||
647 | #endif | ||
648 | nfs_scan_commit_list(&cinfo->mds->list, list, cinfo, 0); | ||
649 | spin_unlock(cinfo->lock); | ||
650 | } | ||
651 | |||
582 | static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | 652 | static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) |
583 | { | 653 | { |
584 | struct nfs_pageio_descriptor desc; | 654 | struct nfs_pageio_descriptor desc; |
@@ -586,20 +656,23 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
586 | LIST_HEAD(reqs); | 656 | LIST_HEAD(reqs); |
587 | struct nfs_commit_info cinfo; | 657 | struct nfs_commit_info cinfo; |
588 | LIST_HEAD(failed); | 658 | LIST_HEAD(failed); |
659 | int i; | ||
589 | 660 | ||
590 | nfs_init_cinfo_from_dreq(&cinfo, dreq); | 661 | nfs_init_cinfo_from_dreq(&cinfo, dreq); |
591 | pnfs_recover_commit_reqs(dreq->inode, &reqs, &cinfo); | 662 | nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo); |
592 | spin_lock(cinfo.lock); | ||
593 | nfs_scan_commit_list(&cinfo.mds->list, &reqs, &cinfo, 0); | ||
594 | spin_unlock(cinfo.lock); | ||
595 | 663 | ||
596 | dreq->count = 0; | 664 | dreq->count = 0; |
665 | for (i = 0; i < dreq->mirror_count; i++) | ||
666 | dreq->mirrors[i].count = 0; | ||
597 | get_dreq(dreq); | 667 | get_dreq(dreq); |
598 | 668 | ||
599 | nfs_pageio_init_write(&desc, dreq->inode, FLUSH_STABLE, false, | 669 | nfs_pageio_init_write(&desc, dreq->inode, FLUSH_STABLE, false, |
600 | &nfs_direct_write_completion_ops); | 670 | &nfs_direct_write_completion_ops); |
601 | desc.pg_dreq = dreq; | 671 | desc.pg_dreq = dreq; |
602 | 672 | ||
673 | req = nfs_list_entry(reqs.next); | ||
674 | nfs_direct_setup_mirroring(dreq, &desc, req); | ||
675 | |||
603 | list_for_each_entry_safe(req, tmp, &reqs, wb_list) { | 676 | list_for_each_entry_safe(req, tmp, &reqs, wb_list) { |
604 | if (!nfs_pageio_add_request(&desc, req)) { | 677 | if (!nfs_pageio_add_request(&desc, req)) { |
605 | nfs_list_remove_request(req); | 678 | nfs_list_remove_request(req); |
@@ -646,7 +719,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) | |||
646 | nfs_list_remove_request(req); | 719 | nfs_list_remove_request(req); |
647 | if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) { | 720 | if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) { |
648 | /* Note the rewrite will go through mds */ | 721 | /* Note the rewrite will go through mds */ |
649 | nfs_mark_request_commit(req, NULL, &cinfo); | 722 | nfs_mark_request_commit(req, NULL, &cinfo, 0); |
650 | } else | 723 | } else |
651 | nfs_release_request(req); | 724 | nfs_release_request(req); |
652 | nfs_unlock_and_release_request(req); | 725 | nfs_unlock_and_release_request(req); |
@@ -721,7 +794,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) | |||
721 | dreq->error = hdr->error; | 794 | dreq->error = hdr->error; |
722 | } | 795 | } |
723 | if (dreq->error == 0) { | 796 | if (dreq->error == 0) { |
724 | dreq->count += hdr->good_bytes; | 797 | nfs_direct_good_bytes(dreq, hdr); |
725 | if (nfs_write_need_commit(hdr)) { | 798 | if (nfs_write_need_commit(hdr)) { |
726 | if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) | 799 | if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) |
727 | request_commit = true; | 800 | request_commit = true; |
@@ -745,7 +818,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) | |||
745 | nfs_list_remove_request(req); | 818 | nfs_list_remove_request(req); |
746 | if (request_commit) { | 819 | if (request_commit) { |
747 | kref_get(&req->wb_kref); | 820 | kref_get(&req->wb_kref); |
748 | nfs_mark_request_commit(req, hdr->lseg, &cinfo); | 821 | nfs_mark_request_commit(req, hdr->lseg, &cinfo, |
822 | hdr->ds_commit_idx); | ||
749 | } | 823 | } |
750 | nfs_unlock_and_release_request(req); | 824 | nfs_unlock_and_release_request(req); |
751 | } | 825 | } |
@@ -826,6 +900,9 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, | |||
826 | result = PTR_ERR(req); | 900 | result = PTR_ERR(req); |
827 | break; | 901 | break; |
828 | } | 902 | } |
903 | |||
904 | nfs_direct_setup_mirroring(dreq, &desc, req); | ||
905 | |||
829 | nfs_lock_request(req); | 906 | nfs_lock_request(req); |
830 | req->wb_index = pos >> PAGE_SHIFT; | 907 | req->wb_index = pos >> PAGE_SHIFT; |
831 | req->wb_offset = pos & ~PAGE_MASK; | 908 | req->wb_offset = pos & ~PAGE_MASK; |
@@ -934,6 +1011,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter, | |||
934 | 1011 | ||
935 | dreq->inode = inode; | 1012 | dreq->inode = inode; |
936 | dreq->bytes_left = count; | 1013 | dreq->bytes_left = count; |
1014 | dreq->io_start = pos; | ||
937 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); | 1015 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); |
938 | l_ctx = nfs_get_lock_context(dreq->ctx); | 1016 | l_ctx = nfs_get_lock_context(dreq->ctx); |
939 | if (IS_ERR(l_ctx)) { | 1017 | if (IS_ERR(l_ctx)) { |