diff options
author | Weston Andros Adamson <dros@primarydata.com> | 2014-05-15 11:56:54 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-05-29 11:11:48 -0400 |
commit | 5002c58639d41b93e800c8a4b7eca49c40d57822 (patch) | |
tree | b9d9981b3396f4f7a5f518f905d8a1199e087509 /fs/nfs/direct.c | |
parent | 7f714720fac03383d687dbe39494cc96b845bd46 (diff) |
pnfs: support multiple verfs per direct req
Support direct requests that span multiple pnfs data servers by
comparing nfs_pgio_header->verf to a cached verf in pnfs_commit_bucket.
Continue to use dreq->verf if the MDS is used / non-pNFS.
Signed-off-by: Weston Andros Adamson <dros@primarydata.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r-- | fs/nfs/direct.c | 102 |
1 files changed, 97 insertions, 5 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 2c0e08f4cf71..4ad7bc388679 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -108,6 +108,97 @@ static inline int put_dreq(struct nfs_direct_req *dreq) | |||
108 | return atomic_dec_and_test(&dreq->io_count); | 108 | return atomic_dec_and_test(&dreq->io_count); |
109 | } | 109 | } |
110 | 110 | ||
111 | /* | ||
112 | * nfs_direct_select_verf - select the right verifier | ||
113 | * @dreq - direct request possibly spanning multiple servers | ||
114 | * @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 | ||
116 | * | ||
117 | * returns the correct verifier to use given the role of the server | ||
118 | */ | ||
119 | static struct nfs_writeverf * | ||
120 | nfs_direct_select_verf(struct nfs_direct_req *dreq, | ||
121 | struct nfs_client *ds_clp, | ||
122 | int ds_idx) | ||
123 | { | ||
124 | struct nfs_writeverf *verfp = &dreq->verf; | ||
125 | |||
126 | #ifdef CONFIG_NFS_V4_1 | ||
127 | if (ds_clp) { | ||
128 | /* pNFS is in use, use the DS verf */ | ||
129 | if (ds_idx >= 0 && ds_idx < dreq->ds_cinfo.nbuckets) | ||
130 | verfp = &dreq->ds_cinfo.buckets[ds_idx].direct_verf; | ||
131 | else | ||
132 | WARN_ON_ONCE(1); | ||
133 | } | ||
134 | #endif | ||
135 | return verfp; | ||
136 | } | ||
137 | |||
138 | |||
139 | /* | ||
140 | * nfs_direct_set_hdr_verf - set the write/commit verifier | ||
141 | * @dreq - direct request possibly spanning multiple servers | ||
142 | * @hdr - pageio header to validate against previously seen verfs | ||
143 | * | ||
144 | * Set the server's (MDS or DS) "seen" verifier | ||
145 | */ | ||
146 | static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq, | ||
147 | struct nfs_pgio_header *hdr) | ||
148 | { | ||
149 | struct nfs_writeverf *verfp; | ||
150 | |||
151 | verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp, | ||
152 | hdr->data->ds_idx); | ||
153 | WARN_ON_ONCE(verfp->committed >= 0); | ||
154 | memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); | ||
155 | WARN_ON_ONCE(verfp->committed < 0); | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * nfs_direct_cmp_hdr_verf - compare verifier for pgio header | ||
160 | * @dreq - direct request possibly spanning multiple servers | ||
161 | * @hdr - pageio header to validate against previously seen verf | ||
162 | * | ||
163 | * set the server's "seen" verf if not initialized. | ||
164 | * returns result of comparison between @hdr->verf and the "seen" | ||
165 | * verf of the server used by @hdr (DS or MDS) | ||
166 | */ | ||
167 | static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq, | ||
168 | struct nfs_pgio_header *hdr) | ||
169 | { | ||
170 | struct nfs_writeverf *verfp; | ||
171 | |||
172 | verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp, | ||
173 | hdr->data->ds_idx); | ||
174 | if (verfp->committed < 0) { | ||
175 | nfs_direct_set_hdr_verf(dreq, hdr); | ||
176 | return 0; | ||
177 | } | ||
178 | return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); | ||
179 | } | ||
180 | |||
181 | #if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4) | ||
182 | /* | ||
183 | * nfs_direct_cmp_commit_data_verf - compare verifier for commit data | ||
184 | * @dreq - direct request possibly spanning multiple servers | ||
185 | * @data - commit data to validate against previously seen verf | ||
186 | * | ||
187 | * returns result of comparison between @data->verf and the verf of | ||
188 | * the server used by @data (DS or MDS) | ||
189 | */ | ||
190 | static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, | ||
191 | struct nfs_commit_data *data) | ||
192 | { | ||
193 | struct nfs_writeverf *verfp; | ||
194 | |||
195 | verfp = nfs_direct_select_verf(dreq, data->ds_clp, | ||
196 | data->ds_commit_index); | ||
197 | WARN_ON_ONCE(verfp->committed < 0); | ||
198 | return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf)); | ||
199 | } | ||
200 | #endif | ||
201 | |||
111 | /** | 202 | /** |
112 | * nfs_direct_IO - NFS address space operation for direct I/O | 203 | * nfs_direct_IO - NFS address space operation for direct I/O |
113 | * @rw: direction (read or write) | 204 | * @rw: direction (read or write) |
@@ -168,6 +259,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void) | |||
168 | kref_get(&dreq->kref); | 259 | kref_get(&dreq->kref); |
169 | init_completion(&dreq->completion); | 260 | init_completion(&dreq->completion); |
170 | INIT_LIST_HEAD(&dreq->mds_cinfo.list); | 261 | INIT_LIST_HEAD(&dreq->mds_cinfo.list); |
262 | dreq->verf.committed = NFS_INVALID_STABLE_HOW; /* not set yet */ | ||
171 | INIT_WORK(&dreq->work, nfs_direct_write_schedule_work); | 263 | INIT_WORK(&dreq->work, nfs_direct_write_schedule_work); |
172 | spin_lock_init(&dreq->lock); | 264 | spin_lock_init(&dreq->lock); |
173 | 265 | ||
@@ -602,7 +694,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data) | |||
602 | dprintk("NFS: %5u commit failed with error %d.\n", | 694 | dprintk("NFS: %5u commit failed with error %d.\n", |
603 | data->task.tk_pid, status); | 695 | data->task.tk_pid, status); |
604 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 696 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
605 | } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { | 697 | } else if (nfs_direct_cmp_commit_data_verf(dreq, data)) { |
606 | dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid); | 698 | dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid); |
607 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 699 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
608 | } | 700 | } |
@@ -811,13 +903,13 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) | |||
811 | if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) | 903 | if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) |
812 | bit = NFS_IOHDR_NEED_RESCHED; | 904 | bit = NFS_IOHDR_NEED_RESCHED; |
813 | else if (dreq->flags == 0) { | 905 | else if (dreq->flags == 0) { |
814 | memcpy(&dreq->verf, &hdr->verf, | 906 | nfs_direct_set_hdr_verf(dreq, hdr); |
815 | sizeof(dreq->verf)); | ||
816 | bit = NFS_IOHDR_NEED_COMMIT; | 907 | bit = NFS_IOHDR_NEED_COMMIT; |
817 | dreq->flags = NFS_ODIRECT_DO_COMMIT; | 908 | dreq->flags = NFS_ODIRECT_DO_COMMIT; |
818 | } else if (dreq->flags == NFS_ODIRECT_DO_COMMIT) { | 909 | } else if (dreq->flags == NFS_ODIRECT_DO_COMMIT) { |
819 | if (memcmp(&dreq->verf, &hdr->verf, sizeof(dreq->verf))) { | 910 | if (nfs_direct_set_or_cmp_hdr_verf(dreq, hdr)) { |
820 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 911 | dreq->flags = |
912 | NFS_ODIRECT_RESCHED_WRITES; | ||
821 | bit = NFS_IOHDR_NEED_RESCHED; | 913 | bit = NFS_IOHDR_NEED_RESCHED; |
822 | } else | 914 | } else |
823 | bit = NFS_IOHDR_NEED_COMMIT; | 915 | bit = NFS_IOHDR_NEED_COMMIT; |