diff options
Diffstat (limited to 'fs/nfs/nfs4filelayout.c')
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 361 |
1 files changed, 331 insertions, 30 deletions
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 23f930caf1e2..428558464817 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -40,32 +40,309 @@ MODULE_LICENSE("GPL"); | |||
40 | MODULE_AUTHOR("Dean Hildebrand <dhildebz@umich.edu>"); | 40 | MODULE_AUTHOR("Dean Hildebrand <dhildebz@umich.edu>"); |
41 | MODULE_DESCRIPTION("The NFSv4 file layout driver"); | 41 | MODULE_DESCRIPTION("The NFSv4 file layout driver"); |
42 | 42 | ||
43 | static int | 43 | #define FILELAYOUT_POLL_RETRY_MAX (15*HZ) |
44 | filelayout_set_layoutdriver(struct nfs_server *nfss) | 44 | |
45 | static loff_t | ||
46 | filelayout_get_dense_offset(struct nfs4_filelayout_segment *flseg, | ||
47 | loff_t offset) | ||
45 | { | 48 | { |
46 | int status = pnfs_alloc_init_deviceid_cache(nfss->nfs_client, | 49 | u32 stripe_width = flseg->stripe_unit * flseg->dsaddr->stripe_count; |
47 | nfs4_fl_free_deviceid_callback); | 50 | u64 tmp; |
48 | if (status) { | 51 | |
49 | printk(KERN_WARNING "%s: deviceid cache could not be " | 52 | offset -= flseg->pattern_offset; |
50 | "initialized\n", __func__); | 53 | tmp = offset; |
51 | return status; | 54 | do_div(tmp, stripe_width); |
55 | |||
56 | return tmp * flseg->stripe_unit + do_div(offset, flseg->stripe_unit); | ||
57 | } | ||
58 | |||
59 | /* This function is used by the layout driver to calculate the | ||
60 | * offset of the file on the dserver based on whether the | ||
61 | * layout type is STRIPE_DENSE or STRIPE_SPARSE | ||
62 | */ | ||
63 | static loff_t | ||
64 | filelayout_get_dserver_offset(struct pnfs_layout_segment *lseg, loff_t offset) | ||
65 | { | ||
66 | struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); | ||
67 | |||
68 | switch (flseg->stripe_type) { | ||
69 | case STRIPE_SPARSE: | ||
70 | return offset; | ||
71 | |||
72 | case STRIPE_DENSE: | ||
73 | return filelayout_get_dense_offset(flseg, offset); | ||
52 | } | 74 | } |
53 | dprintk("%s: deviceid cache has been initialized successfully\n", | 75 | |
54 | __func__); | 76 | BUG(); |
77 | } | ||
78 | |||
79 | /* For data server errors we don't recover from */ | ||
80 | static void | ||
81 | filelayout_set_lo_fail(struct pnfs_layout_segment *lseg) | ||
82 | { | ||
83 | if (lseg->pls_range.iomode == IOMODE_RW) { | ||
84 | dprintk("%s Setting layout IOMODE_RW fail bit\n", __func__); | ||
85 | set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); | ||
86 | } else { | ||
87 | dprintk("%s Setting layout IOMODE_READ fail bit\n", __func__); | ||
88 | set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | static int filelayout_async_handle_error(struct rpc_task *task, | ||
93 | struct nfs4_state *state, | ||
94 | struct nfs_client *clp, | ||
95 | int *reset) | ||
96 | { | ||
97 | if (task->tk_status >= 0) | ||
98 | return 0; | ||
99 | |||
100 | *reset = 0; | ||
101 | |||
102 | switch (task->tk_status) { | ||
103 | case -NFS4ERR_BADSESSION: | ||
104 | case -NFS4ERR_BADSLOT: | ||
105 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
106 | case -NFS4ERR_DEADSESSION: | ||
107 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
108 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
109 | case -NFS4ERR_SEQ_MISORDERED: | ||
110 | dprintk("%s ERROR %d, Reset session. Exchangeid " | ||
111 | "flags 0x%x\n", __func__, task->tk_status, | ||
112 | clp->cl_exchange_flags); | ||
113 | nfs4_schedule_session_recovery(clp->cl_session); | ||
114 | break; | ||
115 | case -NFS4ERR_DELAY: | ||
116 | case -NFS4ERR_GRACE: | ||
117 | case -EKEYEXPIRED: | ||
118 | rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX); | ||
119 | break; | ||
120 | default: | ||
121 | dprintk("%s DS error. Retry through MDS %d\n", __func__, | ||
122 | task->tk_status); | ||
123 | *reset = 1; | ||
124 | break; | ||
125 | } | ||
126 | task->tk_status = 0; | ||
127 | return -EAGAIN; | ||
128 | } | ||
129 | |||
130 | /* NFS_PROTO call done callback routines */ | ||
131 | |||
132 | static int filelayout_read_done_cb(struct rpc_task *task, | ||
133 | struct nfs_read_data *data) | ||
134 | { | ||
135 | struct nfs_client *clp = data->ds_clp; | ||
136 | int reset = 0; | ||
137 | |||
138 | dprintk("%s DS read\n", __func__); | ||
139 | |||
140 | if (filelayout_async_handle_error(task, data->args.context->state, | ||
141 | data->ds_clp, &reset) == -EAGAIN) { | ||
142 | dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n", | ||
143 | __func__, data->ds_clp, data->ds_clp->cl_session); | ||
144 | if (reset) { | ||
145 | filelayout_set_lo_fail(data->lseg); | ||
146 | nfs4_reset_read(task, data); | ||
147 | clp = NFS_SERVER(data->inode)->nfs_client; | ||
148 | } | ||
149 | nfs_restart_rpc(task, clp); | ||
150 | return -EAGAIN; | ||
151 | } | ||
152 | |||
55 | return 0; | 153 | return 0; |
56 | } | 154 | } |
57 | 155 | ||
58 | /* Clear out the layout by destroying its device list */ | 156 | /* |
59 | static int | 157 | * Call ops for the async read/write cases |
60 | filelayout_clear_layoutdriver(struct nfs_server *nfss) | 158 | * In the case of dense layouts, the offset needs to be reset to its |
159 | * original value. | ||
160 | */ | ||
161 | static void filelayout_read_prepare(struct rpc_task *task, void *data) | ||
61 | { | 162 | { |
62 | dprintk("--> %s\n", __func__); | 163 | struct nfs_read_data *rdata = (struct nfs_read_data *)data; |
164 | |||
165 | rdata->read_done_cb = filelayout_read_done_cb; | ||
166 | |||
167 | if (nfs41_setup_sequence(rdata->ds_clp->cl_session, | ||
168 | &rdata->args.seq_args, &rdata->res.seq_res, | ||
169 | 0, task)) | ||
170 | return; | ||
171 | |||
172 | rpc_call_start(task); | ||
173 | } | ||
174 | |||
175 | static void filelayout_read_call_done(struct rpc_task *task, void *data) | ||
176 | { | ||
177 | struct nfs_read_data *rdata = (struct nfs_read_data *)data; | ||
178 | |||
179 | dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status); | ||
180 | |||
181 | /* Note this may cause RPC to be resent */ | ||
182 | rdata->mds_ops->rpc_call_done(task, data); | ||
183 | } | ||
184 | |||
185 | static void filelayout_read_release(void *data) | ||
186 | { | ||
187 | struct nfs_read_data *rdata = (struct nfs_read_data *)data; | ||
188 | |||
189 | rdata->mds_ops->rpc_release(data); | ||
190 | } | ||
191 | |||
192 | static int filelayout_write_done_cb(struct rpc_task *task, | ||
193 | struct nfs_write_data *data) | ||
194 | { | ||
195 | int reset = 0; | ||
196 | |||
197 | if (filelayout_async_handle_error(task, data->args.context->state, | ||
198 | data->ds_clp, &reset) == -EAGAIN) { | ||
199 | struct nfs_client *clp; | ||
200 | |||
201 | dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n", | ||
202 | __func__, data->ds_clp, data->ds_clp->cl_session); | ||
203 | if (reset) { | ||
204 | filelayout_set_lo_fail(data->lseg); | ||
205 | nfs4_reset_write(task, data); | ||
206 | clp = NFS_SERVER(data->inode)->nfs_client; | ||
207 | } else | ||
208 | clp = data->ds_clp; | ||
209 | nfs_restart_rpc(task, clp); | ||
210 | return -EAGAIN; | ||
211 | } | ||
63 | 212 | ||
64 | if (nfss->nfs_client->cl_devid_cache) | ||
65 | pnfs_put_deviceid_cache(nfss->nfs_client); | ||
66 | return 0; | 213 | return 0; |
67 | } | 214 | } |
68 | 215 | ||
216 | static void filelayout_write_prepare(struct rpc_task *task, void *data) | ||
217 | { | ||
218 | struct nfs_write_data *wdata = (struct nfs_write_data *)data; | ||
219 | |||
220 | if (nfs41_setup_sequence(wdata->ds_clp->cl_session, | ||
221 | &wdata->args.seq_args, &wdata->res.seq_res, | ||
222 | 0, task)) | ||
223 | return; | ||
224 | |||
225 | rpc_call_start(task); | ||
226 | } | ||
227 | |||
228 | static void filelayout_write_call_done(struct rpc_task *task, void *data) | ||
229 | { | ||
230 | struct nfs_write_data *wdata = (struct nfs_write_data *)data; | ||
231 | |||
232 | /* Note this may cause RPC to be resent */ | ||
233 | wdata->mds_ops->rpc_call_done(task, data); | ||
234 | } | ||
235 | |||
236 | static void filelayout_write_release(void *data) | ||
237 | { | ||
238 | struct nfs_write_data *wdata = (struct nfs_write_data *)data; | ||
239 | |||
240 | wdata->mds_ops->rpc_release(data); | ||
241 | } | ||
242 | |||
243 | struct rpc_call_ops filelayout_read_call_ops = { | ||
244 | .rpc_call_prepare = filelayout_read_prepare, | ||
245 | .rpc_call_done = filelayout_read_call_done, | ||
246 | .rpc_release = filelayout_read_release, | ||
247 | }; | ||
248 | |||
249 | struct rpc_call_ops filelayout_write_call_ops = { | ||
250 | .rpc_call_prepare = filelayout_write_prepare, | ||
251 | .rpc_call_done = filelayout_write_call_done, | ||
252 | .rpc_release = filelayout_write_release, | ||
253 | }; | ||
254 | |||
255 | static enum pnfs_try_status | ||
256 | filelayout_read_pagelist(struct nfs_read_data *data) | ||
257 | { | ||
258 | struct pnfs_layout_segment *lseg = data->lseg; | ||
259 | struct nfs4_pnfs_ds *ds; | ||
260 | loff_t offset = data->args.offset; | ||
261 | u32 j, idx; | ||
262 | struct nfs_fh *fh; | ||
263 | int status; | ||
264 | |||
265 | dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n", | ||
266 | __func__, data->inode->i_ino, | ||
267 | data->args.pgbase, (size_t)data->args.count, offset); | ||
268 | |||
269 | /* Retrieve the correct rpc_client for the byte range */ | ||
270 | j = nfs4_fl_calc_j_index(lseg, offset); | ||
271 | idx = nfs4_fl_calc_ds_index(lseg, j); | ||
272 | ds = nfs4_fl_prepare_ds(lseg, idx); | ||
273 | if (!ds) { | ||
274 | /* Either layout fh index faulty, or ds connect failed */ | ||
275 | set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); | ||
276 | set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); | ||
277 | return PNFS_NOT_ATTEMPTED; | ||
278 | } | ||
279 | dprintk("%s USE DS:ip %x %hu\n", __func__, | ||
280 | ntohl(ds->ds_ip_addr), ntohs(ds->ds_port)); | ||
281 | |||
282 | /* No multipath support. Use first DS */ | ||
283 | data->ds_clp = ds->ds_clp; | ||
284 | fh = nfs4_fl_select_ds_fh(lseg, j); | ||
285 | if (fh) | ||
286 | data->args.fh = fh; | ||
287 | |||
288 | data->args.offset = filelayout_get_dserver_offset(lseg, offset); | ||
289 | data->mds_offset = offset; | ||
290 | |||
291 | /* Perform an asynchronous read to ds */ | ||
292 | status = nfs_initiate_read(data, ds->ds_clp->cl_rpcclient, | ||
293 | &filelayout_read_call_ops); | ||
294 | BUG_ON(status != 0); | ||
295 | return PNFS_ATTEMPTED; | ||
296 | } | ||
297 | |||
298 | /* Perform async writes. */ | ||
299 | static enum pnfs_try_status | ||
300 | filelayout_write_pagelist(struct nfs_write_data *data, int sync) | ||
301 | { | ||
302 | struct pnfs_layout_segment *lseg = data->lseg; | ||
303 | struct nfs4_pnfs_ds *ds; | ||
304 | loff_t offset = data->args.offset; | ||
305 | u32 j, idx; | ||
306 | struct nfs_fh *fh; | ||
307 | int status; | ||
308 | |||
309 | /* Retrieve the correct rpc_client for the byte range */ | ||
310 | j = nfs4_fl_calc_j_index(lseg, offset); | ||
311 | idx = nfs4_fl_calc_ds_index(lseg, j); | ||
312 | ds = nfs4_fl_prepare_ds(lseg, idx); | ||
313 | if (!ds) { | ||
314 | printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__); | ||
315 | set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); | ||
316 | set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); | ||
317 | return PNFS_NOT_ATTEMPTED; | ||
318 | } | ||
319 | dprintk("%s ino %lu sync %d req %Zu@%llu DS:%x:%hu\n", __func__, | ||
320 | data->inode->i_ino, sync, (size_t) data->args.count, offset, | ||
321 | ntohl(ds->ds_ip_addr), ntohs(ds->ds_port)); | ||
322 | |||
323 | /* We can't handle commit to ds yet */ | ||
324 | if (!FILELAYOUT_LSEG(lseg)->commit_through_mds) | ||
325 | data->args.stable = NFS_FILE_SYNC; | ||
326 | |||
327 | data->write_done_cb = filelayout_write_done_cb; | ||
328 | data->ds_clp = ds->ds_clp; | ||
329 | fh = nfs4_fl_select_ds_fh(lseg, j); | ||
330 | if (fh) | ||
331 | data->args.fh = fh; | ||
332 | /* | ||
333 | * Get the file offset on the dserver. Set the write offset to | ||
334 | * this offset and save the original offset. | ||
335 | */ | ||
336 | data->args.offset = filelayout_get_dserver_offset(lseg, offset); | ||
337 | data->mds_offset = offset; | ||
338 | |||
339 | /* Perform an asynchronous write */ | ||
340 | status = nfs_initiate_write(data, ds->ds_clp->cl_rpcclient, | ||
341 | &filelayout_write_call_ops, sync); | ||
342 | BUG_ON(status != 0); | ||
343 | return PNFS_ATTEMPTED; | ||
344 | } | ||
345 | |||
69 | /* | 346 | /* |
70 | * filelayout_check_layout() | 347 | * filelayout_check_layout() |
71 | * | 348 | * |
@@ -92,14 +369,14 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo, | |||
92 | goto out; | 369 | goto out; |
93 | } | 370 | } |
94 | 371 | ||
95 | if (fl->stripe_unit % PAGE_SIZE) { | 372 | if (!fl->stripe_unit || fl->stripe_unit % PAGE_SIZE) { |
96 | dprintk("%s Stripe unit (%u) not page aligned\n", | 373 | dprintk("%s Invalid stripe unit (%u)\n", |
97 | __func__, fl->stripe_unit); | 374 | __func__, fl->stripe_unit); |
98 | goto out; | 375 | goto out; |
99 | } | 376 | } |
100 | 377 | ||
101 | /* find and reference the deviceid */ | 378 | /* find and reference the deviceid */ |
102 | dsaddr = nfs4_fl_find_get_deviceid(nfss->nfs_client, id); | 379 | dsaddr = nfs4_fl_find_get_deviceid(id); |
103 | if (dsaddr == NULL) { | 380 | if (dsaddr == NULL) { |
104 | dsaddr = get_device_info(lo->plh_inode, id); | 381 | dsaddr = get_device_info(lo->plh_inode, id); |
105 | if (dsaddr == NULL) | 382 | if (dsaddr == NULL) |
@@ -134,7 +411,7 @@ out: | |||
134 | dprintk("--> %s returns %d\n", __func__, status); | 411 | dprintk("--> %s returns %d\n", __func__, status); |
135 | return status; | 412 | return status; |
136 | out_put: | 413 | out_put: |
137 | pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache, &dsaddr->deviceid); | 414 | nfs4_fl_put_deviceid(dsaddr); |
138 | goto out; | 415 | goto out; |
139 | } | 416 | } |
140 | 417 | ||
@@ -243,23 +520,47 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid, | |||
243 | static void | 520 | static void |
244 | filelayout_free_lseg(struct pnfs_layout_segment *lseg) | 521 | filelayout_free_lseg(struct pnfs_layout_segment *lseg) |
245 | { | 522 | { |
246 | struct nfs_server *nfss = NFS_SERVER(lseg->pls_layout->plh_inode); | ||
247 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); | 523 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); |
248 | 524 | ||
249 | dprintk("--> %s\n", __func__); | 525 | dprintk("--> %s\n", __func__); |
250 | pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache, | 526 | nfs4_fl_put_deviceid(fl->dsaddr); |
251 | &fl->dsaddr->deviceid); | ||
252 | _filelayout_free_lseg(fl); | 527 | _filelayout_free_lseg(fl); |
253 | } | 528 | } |
254 | 529 | ||
530 | /* | ||
531 | * filelayout_pg_test(). Called by nfs_can_coalesce_requests() | ||
532 | * | ||
533 | * return 1 : coalesce page | ||
534 | * return 0 : don't coalesce page | ||
535 | */ | ||
536 | int | ||
537 | filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, | ||
538 | struct nfs_page *req) | ||
539 | { | ||
540 | u64 p_stripe, r_stripe; | ||
541 | u32 stripe_unit; | ||
542 | |||
543 | if (!pgio->pg_lseg) | ||
544 | return 1; | ||
545 | p_stripe = (u64)prev->wb_index << PAGE_CACHE_SHIFT; | ||
546 | r_stripe = (u64)req->wb_index << PAGE_CACHE_SHIFT; | ||
547 | stripe_unit = FILELAYOUT_LSEG(pgio->pg_lseg)->stripe_unit; | ||
548 | |||
549 | do_div(p_stripe, stripe_unit); | ||
550 | do_div(r_stripe, stripe_unit); | ||
551 | |||
552 | return (p_stripe == r_stripe); | ||
553 | } | ||
554 | |||
255 | static struct pnfs_layoutdriver_type filelayout_type = { | 555 | static struct pnfs_layoutdriver_type filelayout_type = { |
256 | .id = LAYOUT_NFSV4_1_FILES, | 556 | .id = LAYOUT_NFSV4_1_FILES, |
257 | .name = "LAYOUT_NFSV4_1_FILES", | 557 | .name = "LAYOUT_NFSV4_1_FILES", |
258 | .owner = THIS_MODULE, | 558 | .owner = THIS_MODULE, |
259 | .set_layoutdriver = filelayout_set_layoutdriver, | 559 | .alloc_lseg = filelayout_alloc_lseg, |
260 | .clear_layoutdriver = filelayout_clear_layoutdriver, | 560 | .free_lseg = filelayout_free_lseg, |
261 | .alloc_lseg = filelayout_alloc_lseg, | 561 | .pg_test = filelayout_pg_test, |
262 | .free_lseg = filelayout_free_lseg, | 562 | .read_pagelist = filelayout_read_pagelist, |
563 | .write_pagelist = filelayout_write_pagelist, | ||
263 | }; | 564 | }; |
264 | 565 | ||
265 | static int __init nfs4filelayout_init(void) | 566 | static int __init nfs4filelayout_init(void) |