aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2014-09-10 20:37:24 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-09-12 13:33:49 -0400
commit9cc475411779d635619c2d414da0769e3cbf796b (patch)
tree794f67ee82aa15c021ddcc29e05043791d47afcd /fs/nfs
parent34dc93c2fc04da0d01acf8a1660b4ab276208af7 (diff)
pnfs/blocklayout: move extent processing to blocklayout.c
This isn't device(id) related, so move it into the main file. Simple move for now, the next commit will clean it up a bit. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/blocklayout/blocklayout.c186
-rw-r--r--fs/nfs/blocklayout/blocklayout.h2
-rw-r--r--fs/nfs/blocklayout/blocklayoutdev.c186
3 files changed, 186 insertions, 188 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
index cf10a6e291e4..61a858cd54fe 100644
--- a/fs/nfs/blocklayout/blocklayout.c
+++ b/fs/nfs/blocklayout/blocklayout.c
@@ -446,6 +446,192 @@ static void bl_free_lseg(struct pnfs_layout_segment *lseg)
446 kfree(lseg); 446 kfree(lseg);
447} 447}
448 448
449/* Tracks info needed to ensure extents in layout obey constraints of spec */
450struct layout_verification {
451 u32 mode; /* R or RW */
452 u64 start; /* Expected start of next non-COW extent */
453 u64 inval; /* Start of INVAL coverage */
454 u64 cowread; /* End of COW read coverage */
455};
456
457/* Verify the extent meets the layout requirements of the pnfs-block draft,
458 * section 2.3.1.
459 */
460static int verify_extent(struct pnfs_block_extent *be,
461 struct layout_verification *lv)
462{
463 if (lv->mode == IOMODE_READ) {
464 if (be->be_state == PNFS_BLOCK_READWRITE_DATA ||
465 be->be_state == PNFS_BLOCK_INVALID_DATA)
466 return -EIO;
467 if (be->be_f_offset != lv->start)
468 return -EIO;
469 lv->start += be->be_length;
470 return 0;
471 }
472 /* lv->mode == IOMODE_RW */
473 if (be->be_state == PNFS_BLOCK_READWRITE_DATA) {
474 if (be->be_f_offset != lv->start)
475 return -EIO;
476 if (lv->cowread > lv->start)
477 return -EIO;
478 lv->start += be->be_length;
479 lv->inval = lv->start;
480 return 0;
481 } else if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
482 if (be->be_f_offset != lv->start)
483 return -EIO;
484 lv->start += be->be_length;
485 return 0;
486 } else if (be->be_state == PNFS_BLOCK_READ_DATA) {
487 if (be->be_f_offset > lv->start)
488 return -EIO;
489 if (be->be_f_offset < lv->inval)
490 return -EIO;
491 if (be->be_f_offset < lv->cowread)
492 return -EIO;
493 /* It looks like you might want to min this with lv->start,
494 * but you really don't.
495 */
496 lv->inval = lv->inval + be->be_length;
497 lv->cowread = be->be_f_offset + be->be_length;
498 return 0;
499 } else
500 return -EIO;
501}
502
503static int decode_sector_number(__be32 **rp, sector_t *sp)
504{
505 uint64_t s;
506
507 *rp = xdr_decode_hyper(*rp, &s);
508 if (s & 0x1ff) {
509 printk(KERN_WARNING "NFS: %s: sector not aligned\n", __func__);
510 return -1;
511 }
512 *sp = s >> SECTOR_SHIFT;
513 return 0;
514}
515
516/* XDR decode pnfs_block_layout4 structure */
517static int
518nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo,
519 struct nfs4_layoutget_res *lgr, gfp_t gfp_flags)
520{
521 struct pnfs_block_layout *bl = BLK_LO2EXT(lo);
522 int i, status = -EIO;
523 uint32_t count;
524 struct pnfs_block_extent *be = NULL, *save;
525 struct xdr_stream stream;
526 struct xdr_buf buf;
527 struct page *scratch;
528 __be32 *p;
529 struct layout_verification lv = {
530 .mode = lgr->range.iomode,
531 .start = lgr->range.offset >> SECTOR_SHIFT,
532 .inval = lgr->range.offset >> SECTOR_SHIFT,
533 .cowread = lgr->range.offset >> SECTOR_SHIFT,
534 };
535 LIST_HEAD(extents);
536
537 dprintk("---> %s\n", __func__);
538
539 scratch = alloc_page(gfp_flags);
540 if (!scratch)
541 return -ENOMEM;
542
543 xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len);
544 xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
545
546 p = xdr_inline_decode(&stream, 4);
547 if (unlikely(!p))
548 goto out_err;
549
550 count = be32_to_cpup(p++);
551
552 dprintk("%s enter, number of extents %i\n", __func__, count);
553 p = xdr_inline_decode(&stream, (28 + NFS4_DEVICEID4_SIZE) * count);
554 if (unlikely(!p))
555 goto out_err;
556
557 /* Decode individual extents, putting them in temporary
558 * staging area until whole layout is decoded to make error
559 * recovery easier.
560 */
561 for (i = 0; i < count; i++) {
562 struct nfs4_deviceid id;
563
564 be = kzalloc(sizeof(struct pnfs_block_extent), GFP_NOFS);
565 if (!be) {
566 status = -ENOMEM;
567 goto out_err;
568 }
569 memcpy(&id, p, NFS4_DEVICEID4_SIZE);
570 p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
571
572 be->be_device =
573 nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &id,
574 lo->plh_lc_cred, gfp_flags);
575 if (!be->be_device)
576 goto out_err;
577
578 /* The next three values are read in as bytes,
579 * but stored as 512-byte sector lengths
580 */
581 if (decode_sector_number(&p, &be->be_f_offset) < 0)
582 goto out_err;
583 if (decode_sector_number(&p, &be->be_length) < 0)
584 goto out_err;
585 if (decode_sector_number(&p, &be->be_v_offset) < 0)
586 goto out_err;
587 be->be_state = be32_to_cpup(p++);
588 if (verify_extent(be, &lv)) {
589 dprintk("%s verify failed\n", __func__);
590 goto out_err;
591 }
592 list_add_tail(&be->be_list, &extents);
593 }
594 if (lgr->range.offset + lgr->range.length !=
595 lv.start << SECTOR_SHIFT) {
596 dprintk("%s Final length mismatch\n", __func__);
597 be = NULL;
598 goto out_err;
599 }
600 if (lv.start < lv.cowread) {
601 dprintk("%s Final uncovered COW extent\n", __func__);
602 be = NULL;
603 goto out_err;
604 }
605 /* Extents decoded properly, now try to merge them in to
606 * existing layout extents.
607 */
608 list_for_each_entry_safe(be, save, &extents, be_list) {
609 list_del(&be->be_list);
610
611 status = ext_tree_insert(bl, be);
612 if (status)
613 goto out_free_list;
614 }
615 status = 0;
616 out:
617 __free_page(scratch);
618 dprintk("%s returns %i\n", __func__, status);
619 return status;
620
621 out_err:
622 nfs4_put_deviceid_node(be->be_device);
623 kfree(be);
624 out_free_list:
625 while (!list_empty(&extents)) {
626 be = list_first_entry(&extents, struct pnfs_block_extent,
627 be_list);
628 list_del(&be->be_list);
629 nfs4_put_deviceid_node(be->be_device);
630 kfree(be);
631 }
632 goto out;
633}
634
449/* We pretty much ignore lseg, and store all data layout wide, so we 635/* We pretty much ignore lseg, and store all data layout wide, so we
450 * can correctly merge. 636 * can correctly merge.
451 */ 637 */
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h
index 9757f3eabdd2..00c11eb9d765 100644
--- a/fs/nfs/blocklayout/blocklayout.h
+++ b/fs/nfs/blocklayout/blocklayout.h
@@ -113,8 +113,6 @@ struct bl_msg_hdr {
113/* blocklayoutdev.c */ 113/* blocklayoutdev.c */
114ssize_t bl_pipe_downcall(struct file *, const char __user *, size_t); 114ssize_t bl_pipe_downcall(struct file *, const char __user *, size_t);
115void bl_pipe_destroy_msg(struct rpc_pipe_msg *); 115void bl_pipe_destroy_msg(struct rpc_pipe_msg *);
116int nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo,
117 struct nfs4_layoutget_res *lgr, gfp_t gfp_flags);
118 116
119struct nfs4_deviceid_node *bl_alloc_deviceid_node(struct nfs_server *server, 117struct nfs4_deviceid_node *bl_alloc_deviceid_node(struct nfs_server *server,
120 struct pnfs_device *pdev, gfp_t gfp_mask); 118 struct pnfs_device *pdev, gfp_t gfp_mask);
diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c
index d6527d20c508..2b54e2940288 100644
--- a/fs/nfs/blocklayout/blocklayoutdev.c
+++ b/fs/nfs/blocklayout/blocklayoutdev.c
@@ -40,19 +40,6 @@
40 40
41#define NFSDBG_FACILITY NFSDBG_PNFS_LD 41#define NFSDBG_FACILITY NFSDBG_PNFS_LD
42 42
43static int decode_sector_number(__be32 **rp, sector_t *sp)
44{
45 uint64_t s;
46
47 *rp = xdr_decode_hyper(*rp, &s);
48 if (s & 0x1ff) {
49 printk(KERN_WARNING "NFS: %s: sector not aligned\n", __func__);
50 return -1;
51 }
52 *sp = s >> SECTOR_SHIFT;
53 return 0;
54}
55
56ssize_t bl_pipe_downcall(struct file *filp, const char __user *src, 43ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
57 size_t mlen) 44 size_t mlen)
58{ 45{
@@ -183,176 +170,3 @@ bl_free_deviceid_node(struct nfs4_deviceid_node *d)
183 170
184 kfree(dev); 171 kfree(dev);
185} 172}
186
187/* Tracks info needed to ensure extents in layout obey constraints of spec */
188struct layout_verification {
189 u32 mode; /* R or RW */
190 u64 start; /* Expected start of next non-COW extent */
191 u64 inval; /* Start of INVAL coverage */
192 u64 cowread; /* End of COW read coverage */
193};
194
195/* Verify the extent meets the layout requirements of the pnfs-block draft,
196 * section 2.3.1.
197 */
198static int verify_extent(struct pnfs_block_extent *be,
199 struct layout_verification *lv)
200{
201 if (lv->mode == IOMODE_READ) {
202 if (be->be_state == PNFS_BLOCK_READWRITE_DATA ||
203 be->be_state == PNFS_BLOCK_INVALID_DATA)
204 return -EIO;
205 if (be->be_f_offset != lv->start)
206 return -EIO;
207 lv->start += be->be_length;
208 return 0;
209 }
210 /* lv->mode == IOMODE_RW */
211 if (be->be_state == PNFS_BLOCK_READWRITE_DATA) {
212 if (be->be_f_offset != lv->start)
213 return -EIO;
214 if (lv->cowread > lv->start)
215 return -EIO;
216 lv->start += be->be_length;
217 lv->inval = lv->start;
218 return 0;
219 } else if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
220 if (be->be_f_offset != lv->start)
221 return -EIO;
222 lv->start += be->be_length;
223 return 0;
224 } else if (be->be_state == PNFS_BLOCK_READ_DATA) {
225 if (be->be_f_offset > lv->start)
226 return -EIO;
227 if (be->be_f_offset < lv->inval)
228 return -EIO;
229 if (be->be_f_offset < lv->cowread)
230 return -EIO;
231 /* It looks like you might want to min this with lv->start,
232 * but you really don't.
233 */
234 lv->inval = lv->inval + be->be_length;
235 lv->cowread = be->be_f_offset + be->be_length;
236 return 0;
237 } else
238 return -EIO;
239}
240
241/* XDR decode pnfs_block_layout4 structure */
242int
243nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo,
244 struct nfs4_layoutget_res *lgr, gfp_t gfp_flags)
245{
246 struct pnfs_block_layout *bl = BLK_LO2EXT(lo);
247 int i, status = -EIO;
248 uint32_t count;
249 struct pnfs_block_extent *be = NULL, *save;
250 struct xdr_stream stream;
251 struct xdr_buf buf;
252 struct page *scratch;
253 __be32 *p;
254 struct layout_verification lv = {
255 .mode = lgr->range.iomode,
256 .start = lgr->range.offset >> SECTOR_SHIFT,
257 .inval = lgr->range.offset >> SECTOR_SHIFT,
258 .cowread = lgr->range.offset >> SECTOR_SHIFT,
259 };
260 LIST_HEAD(extents);
261
262 dprintk("---> %s\n", __func__);
263
264 scratch = alloc_page(gfp_flags);
265 if (!scratch)
266 return -ENOMEM;
267
268 xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len);
269 xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
270
271 p = xdr_inline_decode(&stream, 4);
272 if (unlikely(!p))
273 goto out_err;
274
275 count = be32_to_cpup(p++);
276
277 dprintk("%s enter, number of extents %i\n", __func__, count);
278 p = xdr_inline_decode(&stream, (28 + NFS4_DEVICEID4_SIZE) * count);
279 if (unlikely(!p))
280 goto out_err;
281
282 /* Decode individual extents, putting them in temporary
283 * staging area until whole layout is decoded to make error
284 * recovery easier.
285 */
286 for (i = 0; i < count; i++) {
287 struct nfs4_deviceid id;
288
289 be = kzalloc(sizeof(struct pnfs_block_extent), GFP_NOFS);
290 if (!be) {
291 status = -ENOMEM;
292 goto out_err;
293 }
294 memcpy(&id, p, NFS4_DEVICEID4_SIZE);
295 p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
296
297 be->be_device =
298 nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &id,
299 lo->plh_lc_cred, gfp_flags);
300 if (!be->be_device)
301 goto out_err;
302
303 /* The next three values are read in as bytes,
304 * but stored as 512-byte sector lengths
305 */
306 if (decode_sector_number(&p, &be->be_f_offset) < 0)
307 goto out_err;
308 if (decode_sector_number(&p, &be->be_length) < 0)
309 goto out_err;
310 if (decode_sector_number(&p, &be->be_v_offset) < 0)
311 goto out_err;
312 be->be_state = be32_to_cpup(p++);
313 if (verify_extent(be, &lv)) {
314 dprintk("%s verify failed\n", __func__);
315 goto out_err;
316 }
317 list_add_tail(&be->be_list, &extents);
318 }
319 if (lgr->range.offset + lgr->range.length !=
320 lv.start << SECTOR_SHIFT) {
321 dprintk("%s Final length mismatch\n", __func__);
322 be = NULL;
323 goto out_err;
324 }
325 if (lv.start < lv.cowread) {
326 dprintk("%s Final uncovered COW extent\n", __func__);
327 be = NULL;
328 goto out_err;
329 }
330 /* Extents decoded properly, now try to merge them in to
331 * existing layout extents.
332 */
333 list_for_each_entry_safe(be, save, &extents, be_list) {
334 list_del(&be->be_list);
335
336 status = ext_tree_insert(bl, be);
337 if (status)
338 goto out_free_list;
339 }
340 status = 0;
341 out:
342 __free_page(scratch);
343 dprintk("%s returns %i\n", __func__, status);
344 return status;
345
346 out_err:
347 nfs4_put_deviceid_node(be->be_device);
348 kfree(be);
349 out_free_list:
350 while (!list_empty(&extents)) {
351 be = list_first_entry(&extents, struct pnfs_block_extent,
352 be_list);
353 list_del(&be->be_list);
354 nfs4_put_deviceid_node(be->be_device);
355 kfree(be);
356 }
357 goto out;
358}