diff options
author | Christoph Hellwig <hch@lst.de> | 2014-09-10 20:37:25 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-09-12 13:33:49 -0400 |
commit | ca0fe1dfa5acac6ec4ef5820d2eb5460b02648d5 (patch) | |
tree | 31b397a0ef6f2d10a1b0d36a87c01355b6ddb445 /fs/nfs | |
parent | 9cc475411779d635619c2d414da0769e3cbf796b (diff) |
pnfs/blocklayout: refactor extent processing
Factor out a helper for all per-extent work, and merge the now trivial
functions for lseg allocation and parsing.
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.c | 207 |
1 files changed, 105 insertions, 102 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 61a858cd54fe..76ec017a6f0a 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
@@ -513,144 +513,147 @@ static int decode_sector_number(__be32 **rp, sector_t *sp) | |||
513 | return 0; | 513 | return 0; |
514 | } | 514 | } |
515 | 515 | ||
516 | /* XDR decode pnfs_block_layout4 structure */ | ||
517 | static int | 516 | static int |
518 | nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo, | 517 | bl_alloc_extent(struct xdr_stream *xdr, struct pnfs_layout_hdr *lo, |
519 | struct nfs4_layoutget_res *lgr, gfp_t gfp_flags) | 518 | struct layout_verification *lv, struct list_head *extents, |
519 | gfp_t gfp_mask) | ||
520 | { | 520 | { |
521 | struct pnfs_block_layout *bl = BLK_LO2EXT(lo); | 521 | struct pnfs_block_extent *be; |
522 | int i, status = -EIO; | 522 | struct nfs4_deviceid id; |
523 | uint32_t count; | 523 | int error; |
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; | 524 | __be32 *p; |
525 | |||
526 | p = xdr_inline_decode(xdr, 28 + NFS4_DEVICEID4_SIZE); | ||
527 | if (!p) | ||
528 | return -EIO; | ||
529 | |||
530 | be = kzalloc(sizeof(*be), GFP_NOFS); | ||
531 | if (!be) | ||
532 | return -ENOMEM; | ||
533 | |||
534 | memcpy(&id, p, NFS4_DEVICEID4_SIZE); | ||
535 | p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE); | ||
536 | |||
537 | error = -EIO; | ||
538 | be->be_device = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &id, | ||
539 | lo->plh_lc_cred, gfp_mask); | ||
540 | if (!be->be_device) | ||
541 | goto out_free_be; | ||
542 | |||
543 | /* | ||
544 | * The next three values are read in as bytes, but stored in the | ||
545 | * extent structure in 512-byte granularity. | ||
546 | */ | ||
547 | if (decode_sector_number(&p, &be->be_f_offset) < 0) | ||
548 | goto out_put_deviceid; | ||
549 | if (decode_sector_number(&p, &be->be_length) < 0) | ||
550 | goto out_put_deviceid; | ||
551 | if (decode_sector_number(&p, &be->be_v_offset) < 0) | ||
552 | goto out_put_deviceid; | ||
553 | be->be_state = be32_to_cpup(p++); | ||
554 | |||
555 | error = verify_extent(be, lv); | ||
556 | if (error) { | ||
557 | dprintk("%s: extent verification failed\n", __func__); | ||
558 | goto out_put_deviceid; | ||
559 | } | ||
560 | |||
561 | list_add_tail(&be->be_list, extents); | ||
562 | return 0; | ||
563 | |||
564 | out_put_deviceid: | ||
565 | nfs4_put_deviceid_node(be->be_device); | ||
566 | out_free_be: | ||
567 | kfree(be); | ||
568 | return error; | ||
569 | } | ||
570 | |||
571 | static struct pnfs_layout_segment * | ||
572 | bl_alloc_lseg(struct pnfs_layout_hdr *lo, struct nfs4_layoutget_res *lgr, | ||
573 | gfp_t gfp_mask) | ||
574 | { | ||
529 | struct layout_verification lv = { | 575 | struct layout_verification lv = { |
530 | .mode = lgr->range.iomode, | 576 | .mode = lgr->range.iomode, |
531 | .start = lgr->range.offset >> SECTOR_SHIFT, | 577 | .start = lgr->range.offset >> SECTOR_SHIFT, |
532 | .inval = lgr->range.offset >> SECTOR_SHIFT, | 578 | .inval = lgr->range.offset >> SECTOR_SHIFT, |
533 | .cowread = lgr->range.offset >> SECTOR_SHIFT, | 579 | .cowread = lgr->range.offset >> SECTOR_SHIFT, |
534 | }; | 580 | }; |
581 | struct pnfs_block_layout *bl = BLK_LO2EXT(lo); | ||
582 | struct pnfs_layout_segment *lseg; | ||
583 | struct xdr_buf buf; | ||
584 | struct xdr_stream xdr; | ||
585 | struct page *scratch; | ||
586 | int status, i; | ||
587 | uint32_t count; | ||
588 | __be32 *p; | ||
535 | LIST_HEAD(extents); | 589 | LIST_HEAD(extents); |
536 | 590 | ||
537 | dprintk("---> %s\n", __func__); | 591 | dprintk("---> %s\n", __func__); |
538 | 592 | ||
539 | scratch = alloc_page(gfp_flags); | 593 | lseg = kzalloc(sizeof(*lseg), gfp_mask); |
594 | if (!lseg) | ||
595 | return ERR_PTR(-ENOMEM); | ||
596 | |||
597 | status = -ENOMEM; | ||
598 | scratch = alloc_page(gfp_mask); | ||
540 | if (!scratch) | 599 | if (!scratch) |
541 | return -ENOMEM; | 600 | goto out; |
542 | 601 | ||
543 | xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len); | 602 | xdr_init_decode_pages(&xdr, &buf, |
544 | xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); | 603 | lgr->layoutp->pages, lgr->layoutp->len); |
604 | xdr_set_scratch_buffer(&xdr, page_address(scratch), PAGE_SIZE); | ||
545 | 605 | ||
546 | p = xdr_inline_decode(&stream, 4); | 606 | status = -EIO; |
607 | p = xdr_inline_decode(&xdr, 4); | ||
547 | if (unlikely(!p)) | 608 | if (unlikely(!p)) |
548 | goto out_err; | 609 | goto out_free_scratch; |
549 | 610 | ||
550 | count = be32_to_cpup(p++); | 611 | count = be32_to_cpup(p++); |
612 | dprintk("%s: number of extents %d\n", __func__, count); | ||
551 | 613 | ||
552 | dprintk("%s enter, number of extents %i\n", __func__, count); | 614 | /* |
553 | p = xdr_inline_decode(&stream, (28 + NFS4_DEVICEID4_SIZE) * count); | 615 | * Decode individual extents, putting them in temporary staging area |
554 | if (unlikely(!p)) | 616 | * until whole layout is decoded to make error recovery easier. |
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 | */ | 617 | */ |
561 | for (i = 0; i < count; i++) { | 618 | for (i = 0; i < count; i++) { |
562 | struct nfs4_deviceid id; | 619 | status = bl_alloc_extent(&xdr, lo, &lv, &extents, gfp_mask); |
563 | 620 | if (status) | |
564 | be = kzalloc(sizeof(struct pnfs_block_extent), GFP_NOFS); | 621 | goto process_extents; |
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 | } | 622 | } |
623 | |||
594 | if (lgr->range.offset + lgr->range.length != | 624 | if (lgr->range.offset + lgr->range.length != |
595 | lv.start << SECTOR_SHIFT) { | 625 | lv.start << SECTOR_SHIFT) { |
596 | dprintk("%s Final length mismatch\n", __func__); | 626 | dprintk("%s Final length mismatch\n", __func__); |
597 | be = NULL; | 627 | status = -EIO; |
598 | goto out_err; | 628 | goto process_extents; |
599 | } | 629 | } |
630 | |||
600 | if (lv.start < lv.cowread) { | 631 | if (lv.start < lv.cowread) { |
601 | dprintk("%s Final uncovered COW extent\n", __func__); | 632 | dprintk("%s Final uncovered COW extent\n", __func__); |
602 | be = NULL; | 633 | status = -EIO; |
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 | } | 634 | } |
615 | status = 0; | ||
616 | out: | ||
617 | __free_page(scratch); | ||
618 | dprintk("%s returns %i\n", __func__, status); | ||
619 | return status; | ||
620 | 635 | ||
621 | out_err: | 636 | process_extents: |
622 | nfs4_put_deviceid_node(be->be_device); | ||
623 | kfree(be); | ||
624 | out_free_list: | ||
625 | while (!list_empty(&extents)) { | 637 | while (!list_empty(&extents)) { |
626 | be = list_first_entry(&extents, struct pnfs_block_extent, | 638 | struct pnfs_block_extent *be = |
627 | be_list); | 639 | list_first_entry(&extents, struct pnfs_block_extent, |
640 | be_list); | ||
628 | list_del(&be->be_list); | 641 | list_del(&be->be_list); |
629 | nfs4_put_deviceid_node(be->be_device); | ||
630 | kfree(be); | ||
631 | } | ||
632 | goto out; | ||
633 | } | ||
634 | 642 | ||
635 | /* We pretty much ignore lseg, and store all data layout wide, so we | 643 | if (!status) |
636 | * can correctly merge. | 644 | status = ext_tree_insert(bl, be); |
637 | */ | ||
638 | static struct pnfs_layout_segment *bl_alloc_lseg(struct pnfs_layout_hdr *lo, | ||
639 | struct nfs4_layoutget_res *lgr, | ||
640 | gfp_t gfp_flags) | ||
641 | { | ||
642 | struct pnfs_layout_segment *lseg; | ||
643 | int status; | ||
644 | 645 | ||
645 | dprintk("%s enter\n", __func__); | 646 | if (status) { |
646 | lseg = kzalloc(sizeof(*lseg), gfp_flags); | 647 | nfs4_put_deviceid_node(be->be_device); |
647 | if (!lseg) | 648 | kfree(be); |
648 | return ERR_PTR(-ENOMEM); | 649 | } |
649 | status = nfs4_blk_process_layoutget(lo, lgr, gfp_flags); | 650 | } |
651 | |||
652 | out_free_scratch: | ||
653 | __free_page(scratch); | ||
654 | out: | ||
655 | dprintk("%s returns %d\n", __func__, status); | ||
650 | if (status) { | 656 | if (status) { |
651 | /* We don't want to call the full-blown bl_free_lseg, | ||
652 | * since on error extents were not touched. | ||
653 | */ | ||
654 | kfree(lseg); | 657 | kfree(lseg); |
655 | return ERR_PTR(status); | 658 | return ERR_PTR(status); |
656 | } | 659 | } |