diff options
author | Weston Andros Adamson <dros@primarydata.com> | 2014-09-19 12:48:33 -0400 |
---|---|---|
committer | Tom Haynes <loghyr@primarydata.com> | 2015-02-03 14:06:46 -0500 |
commit | 0a00b77b331a0e4aac461d4e920677661256918a (patch) | |
tree | 5335af505ce38262b8d2c6bdaa7b925427aa5f42 /fs/nfs/direct.c | |
parent | a7d42ddb3099727f58366fa006f850a219cce6c8 (diff) |
nfs: mirroring support for direct io
The current mirroring code only notices short writes to the first
mirror. This patch keeps per-mirror byte counts and only considers
a byte to be written once all mirrors report so.
Signed-off-by: Weston Andros Adamson <dros@primarydata.com>
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r-- | fs/nfs/direct.c | 71 |
1 files changed, 57 insertions, 14 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 0178d4fe8ab7..651387bbfd9f 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,6 +82,10 @@ 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 */ |
83 | error; /* any reported error */ | 91 | error; /* any reported error */ |
@@ -108,6 +116,29 @@ static inline int put_dreq(struct nfs_direct_req *dreq) | |||
108 | return atomic_dec_and_test(&dreq->io_count); | 116 | return atomic_dec_and_test(&dreq->io_count); |
109 | } | 117 | } |
110 | 118 | ||
119 | static void | ||
120 | nfs_direct_good_bytes(struct nfs_direct_req *dreq, struct nfs_pgio_header *hdr) | ||
121 | { | ||
122 | int i; | ||
123 | ssize_t count; | ||
124 | |||
125 | WARN_ON_ONCE(hdr->pgio_mirror_idx >= dreq->mirror_count); | ||
126 | |||
127 | dreq->mirrors[hdr->pgio_mirror_idx].count += hdr->good_bytes; | ||
128 | |||
129 | if (hdr->pgio_mirror_idx == 0) | ||
130 | dreq->count += hdr->good_bytes; | ||
131 | |||
132 | /* update the dreq->count by finding the minimum agreed count from all | ||
133 | * mirrors */ | ||
134 | count = dreq->mirrors[0].count; | ||
135 | |||
136 | for (i = 1; i < dreq->mirror_count; i++) | ||
137 | count = min(count, dreq->mirrors[i].count); | ||
138 | |||
139 | dreq->count = count; | ||
140 | } | ||
141 | |||
111 | /* | 142 | /* |
112 | * nfs_direct_select_verf - select the right verifier | 143 | * nfs_direct_select_verf - select the right verifier |
113 | * @dreq - direct request possibly spanning multiple servers | 144 | * @dreq - direct request possibly spanning multiple servers |
@@ -241,6 +272,18 @@ void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, | |||
241 | cinfo->completion_ops = &nfs_direct_commit_completion_ops; | 272 | cinfo->completion_ops = &nfs_direct_commit_completion_ops; |
242 | } | 273 | } |
243 | 274 | ||
275 | static inline void nfs_direct_setup_mirroring(struct nfs_direct_req *dreq, | ||
276 | struct nfs_pageio_descriptor *pgio, | ||
277 | struct nfs_page *req) | ||
278 | { | ||
279 | int mirror_count = 1; | ||
280 | |||
281 | if (pgio->pg_ops->pg_get_mirror_count) | ||
282 | mirror_count = pgio->pg_ops->pg_get_mirror_count(pgio, req); | ||
283 | |||
284 | dreq->mirror_count = mirror_count; | ||
285 | } | ||
286 | |||
244 | static inline struct nfs_direct_req *nfs_direct_req_alloc(void) | 287 | static inline struct nfs_direct_req *nfs_direct_req_alloc(void) |
245 | { | 288 | { |
246 | struct nfs_direct_req *dreq; | 289 | struct nfs_direct_req *dreq; |
@@ -255,6 +298,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void) | |||
255 | INIT_LIST_HEAD(&dreq->mds_cinfo.list); | 298 | INIT_LIST_HEAD(&dreq->mds_cinfo.list); |
256 | dreq->verf.committed = NFS_INVALID_STABLE_HOW; /* not set yet */ | 299 | dreq->verf.committed = NFS_INVALID_STABLE_HOW; /* not set yet */ |
257 | INIT_WORK(&dreq->work, nfs_direct_write_schedule_work); | 300 | INIT_WORK(&dreq->work, nfs_direct_write_schedule_work); |
301 | dreq->mirror_count = 1; | ||
258 | spin_lock_init(&dreq->lock); | 302 | spin_lock_init(&dreq->lock); |
259 | 303 | ||
260 | return dreq; | 304 | return dreq; |
@@ -360,14 +404,9 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr) | |||
360 | spin_lock(&dreq->lock); | 404 | spin_lock(&dreq->lock); |
361 | if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && (hdr->good_bytes == 0)) | 405 | if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && (hdr->good_bytes == 0)) |
362 | dreq->error = hdr->error; | 406 | dreq->error = hdr->error; |
363 | else { | 407 | else |
364 | /* | 408 | nfs_direct_good_bytes(dreq, hdr); |
365 | * FIXME: right now this only accounts for bytes written | 409 | |
366 | * to the first mirror | ||
367 | */ | ||
368 | if (hdr->pgio_mirror_idx == 0) | ||
369 | dreq->count += hdr->good_bytes; | ||
370 | } | ||
371 | spin_unlock(&dreq->lock); | 410 | spin_unlock(&dreq->lock); |
372 | 411 | ||
373 | while (!list_empty(&hdr->pages)) { | 412 | while (!list_empty(&hdr->pages)) { |
@@ -598,17 +637,23 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
598 | LIST_HEAD(reqs); | 637 | LIST_HEAD(reqs); |
599 | struct nfs_commit_info cinfo; | 638 | struct nfs_commit_info cinfo; |
600 | LIST_HEAD(failed); | 639 | LIST_HEAD(failed); |
640 | int i; | ||
601 | 641 | ||
602 | nfs_init_cinfo_from_dreq(&cinfo, dreq); | 642 | nfs_init_cinfo_from_dreq(&cinfo, dreq); |
603 | nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo); | 643 | nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo); |
604 | 644 | ||
605 | dreq->count = 0; | 645 | dreq->count = 0; |
646 | for (i = 0; i < dreq->mirror_count; i++) | ||
647 | dreq->mirrors[i].count = 0; | ||
606 | get_dreq(dreq); | 648 | get_dreq(dreq); |
607 | 649 | ||
608 | nfs_pageio_init_write(&desc, dreq->inode, FLUSH_STABLE, false, | 650 | nfs_pageio_init_write(&desc, dreq->inode, FLUSH_STABLE, false, |
609 | &nfs_direct_write_completion_ops); | 651 | &nfs_direct_write_completion_ops); |
610 | desc.pg_dreq = dreq; | 652 | desc.pg_dreq = dreq; |
611 | 653 | ||
654 | req = nfs_list_entry(reqs.next); | ||
655 | nfs_direct_setup_mirroring(dreq, &desc, req); | ||
656 | |||
612 | list_for_each_entry_safe(req, tmp, &reqs, wb_list) { | 657 | list_for_each_entry_safe(req, tmp, &reqs, wb_list) { |
613 | if (!nfs_pageio_add_request(&desc, req)) { | 658 | if (!nfs_pageio_add_request(&desc, req)) { |
614 | nfs_list_remove_request(req); | 659 | nfs_list_remove_request(req); |
@@ -730,12 +775,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) | |||
730 | dreq->error = hdr->error; | 775 | dreq->error = hdr->error; |
731 | } | 776 | } |
732 | if (dreq->error == 0) { | 777 | if (dreq->error == 0) { |
733 | /* | 778 | nfs_direct_good_bytes(dreq, hdr); |
734 | * FIXME: right now this only accounts for bytes written | ||
735 | * to the first mirror | ||
736 | */ | ||
737 | if (hdr->pgio_mirror_idx == 0) | ||
738 | dreq->count += hdr->good_bytes; | ||
739 | if (nfs_write_need_commit(hdr)) { | 779 | if (nfs_write_need_commit(hdr)) { |
740 | if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) | 780 | if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) |
741 | request_commit = true; | 781 | request_commit = true; |
@@ -841,6 +881,9 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, | |||
841 | result = PTR_ERR(req); | 881 | result = PTR_ERR(req); |
842 | break; | 882 | break; |
843 | } | 883 | } |
884 | |||
885 | nfs_direct_setup_mirroring(dreq, &desc, req); | ||
886 | |||
844 | nfs_lock_request(req); | 887 | nfs_lock_request(req); |
845 | req->wb_index = pos >> PAGE_SHIFT; | 888 | req->wb_index = pos >> PAGE_SHIFT; |
846 | req->wb_offset = pos & ~PAGE_MASK; | 889 | req->wb_offset = pos & ~PAGE_MASK; |