aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2014-09-10 20:37:25 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-09-12 13:33:49 -0400
commitca0fe1dfa5acac6ec4ef5820d2eb5460b02648d5 (patch)
tree31b397a0ef6f2d10a1b0d36a87c01355b6ddb445 /fs/nfs
parent9cc475411779d635619c2d414da0769e3cbf796b (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.c207
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 */
517static int 516static int
518nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo, 517bl_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
564out_put_deviceid:
565 nfs4_put_deviceid_node(be->be_device);
566out_free_be:
567 kfree(be);
568 return error;
569}
570
571static struct pnfs_layout_segment *
572bl_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: 636process_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 */
638static 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
652out_free_scratch:
653 __free_page(scratch);
654out:
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 }