diff options
Diffstat (limited to 'fs/gfs2/bmap.c')
| -rw-r--r-- | fs/gfs2/bmap.c | 205 |
1 files changed, 119 insertions, 86 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 5226c3bfbcf7..a7b586e02693 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
| @@ -572,22 +572,6 @@ static int gfs2_hole_size(struct inode *inode, sector_t lblock, u64 len, | |||
| 572 | return ret; | 572 | return ret; |
| 573 | } | 573 | } |
| 574 | 574 | ||
| 575 | static inline void bmap_lock(struct gfs2_inode *ip, int create) | ||
| 576 | { | ||
| 577 | if (create) | ||
| 578 | down_write(&ip->i_rw_mutex); | ||
| 579 | else | ||
| 580 | down_read(&ip->i_rw_mutex); | ||
| 581 | } | ||
| 582 | |||
| 583 | static inline void bmap_unlock(struct gfs2_inode *ip, int create) | ||
| 584 | { | ||
| 585 | if (create) | ||
| 586 | up_write(&ip->i_rw_mutex); | ||
| 587 | else | ||
| 588 | up_read(&ip->i_rw_mutex); | ||
| 589 | } | ||
| 590 | |||
| 591 | static inline __be64 *gfs2_indirect_init(struct metapath *mp, | 575 | static inline __be64 *gfs2_indirect_init(struct metapath *mp, |
| 592 | struct gfs2_glock *gl, unsigned int i, | 576 | struct gfs2_glock *gl, unsigned int i, |
| 593 | unsigned offset, u64 bn) | 577 | unsigned offset, u64 bn) |
| @@ -614,15 +598,11 @@ enum alloc_state { | |||
| 614 | }; | 598 | }; |
| 615 | 599 | ||
| 616 | /** | 600 | /** |
| 617 | * gfs2_bmap_alloc - Build a metadata tree of the requested height | 601 | * gfs2_iomap_alloc - Build a metadata tree of the requested height |
| 618 | * @inode: The GFS2 inode | 602 | * @inode: The GFS2 inode |
| 619 | * @lblock: The logical starting block of the extent | 603 | * @iomap: The iomap structure |
| 620 | * @bh_map: This is used to return the mapping details | 604 | * @flags: iomap flags |
| 621 | * @zero_new: True if newly allocated blocks should be zeroed | ||
| 622 | * @mp: The metapath, with proper height information calculated | 605 | * @mp: The metapath, with proper height information calculated |
| 623 | * @maxlen: The max number of data blocks to alloc | ||
| 624 | * @dblock: Pointer to return the resulting new block | ||
| 625 | * @dblks: Pointer to return the number of blocks allocated | ||
| 626 | * | 606 | * |
| 627 | * In this routine we may have to alloc: | 607 | * In this routine we may have to alloc: |
| 628 | * i) Indirect blocks to grow the metadata tree height | 608 | * i) Indirect blocks to grow the metadata tree height |
| @@ -635,6 +615,13 @@ enum alloc_state { | |||
| 635 | * blocks are available, there will only be one request per bmap call) | 615 | * blocks are available, there will only be one request per bmap call) |
| 636 | * and uses the state machine to initialise the blocks in order. | 616 | * and uses the state machine to initialise the blocks in order. |
| 637 | * | 617 | * |
| 618 | * Right now, this function will allocate at most one indirect block | ||
| 619 | * worth of data -- with a default block size of 4K, that's slightly | ||
| 620 | * less than 2M. If this limitation is ever removed to allow huge | ||
| 621 | * allocations, we would probably still want to limit the iomap size we | ||
| 622 | * return to avoid stalling other tasks during huge writes; the next | ||
| 623 | * iomap iteration would then find the blocks already allocated. | ||
| 624 | * | ||
| 638 | * Returns: errno on error | 625 | * Returns: errno on error |
| 639 | */ | 626 | */ |
| 640 | 627 | ||
| @@ -649,6 +636,7 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, | |||
| 649 | unsigned dblks = 0; | 636 | unsigned dblks = 0; |
| 650 | unsigned ptrs_per_blk; | 637 | unsigned ptrs_per_blk; |
| 651 | const unsigned end_of_metadata = mp->mp_fheight - 1; | 638 | const unsigned end_of_metadata = mp->mp_fheight - 1; |
| 639 | int ret; | ||
| 652 | enum alloc_state state; | 640 | enum alloc_state state; |
| 653 | __be64 *ptr; | 641 | __be64 *ptr; |
| 654 | __be64 zero_bn = 0; | 642 | __be64 zero_bn = 0; |
| @@ -659,6 +647,8 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, | |||
| 659 | 647 | ||
| 660 | gfs2_trans_add_meta(ip->i_gl, dibh); | 648 | gfs2_trans_add_meta(ip->i_gl, dibh); |
| 661 | 649 | ||
| 650 | down_write(&ip->i_rw_mutex); | ||
| 651 | |||
| 662 | if (mp->mp_fheight == mp->mp_aheight) { | 652 | if (mp->mp_fheight == mp->mp_aheight) { |
| 663 | struct buffer_head *bh; | 653 | struct buffer_head *bh; |
| 664 | int eob; | 654 | int eob; |
| @@ -694,11 +684,10 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, | |||
| 694 | blks = dblks + iblks; | 684 | blks = dblks + iblks; |
| 695 | i = mp->mp_aheight; | 685 | i = mp->mp_aheight; |
| 696 | do { | 686 | do { |
| 697 | int error; | ||
| 698 | n = blks - alloced; | 687 | n = blks - alloced; |
| 699 | error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL); | 688 | ret = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL); |
| 700 | if (error) | 689 | if (ret) |
| 701 | return error; | 690 | goto out; |
| 702 | alloced += n; | 691 | alloced += n; |
| 703 | if (state != ALLOC_DATA || gfs2_is_jdata(ip)) | 692 | if (state != ALLOC_DATA || gfs2_is_jdata(ip)) |
| 704 | gfs2_trans_add_unrevoke(sdp, bn, n); | 693 | gfs2_trans_add_unrevoke(sdp, bn, n); |
| @@ -754,7 +743,7 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, | |||
| 754 | dblks = n; | 743 | dblks = n; |
| 755 | ptr = metapointer(end_of_metadata, mp); | 744 | ptr = metapointer(end_of_metadata, mp); |
| 756 | iomap->addr = bn << inode->i_blkbits; | 745 | iomap->addr = bn << inode->i_blkbits; |
| 757 | iomap->flags |= IOMAP_F_NEW; | 746 | iomap->flags |= IOMAP_F_MERGED | IOMAP_F_NEW; |
| 758 | while (n-- > 0) | 747 | while (n-- > 0) |
| 759 | *ptr++ = cpu_to_be64(bn++); | 748 | *ptr++ = cpu_to_be64(bn++); |
| 760 | break; | 749 | break; |
| @@ -764,8 +753,10 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, | |||
| 764 | iomap->length = (u64)dblks << inode->i_blkbits; | 753 | iomap->length = (u64)dblks << inode->i_blkbits; |
| 765 | ip->i_height = mp->mp_fheight; | 754 | ip->i_height = mp->mp_fheight; |
| 766 | gfs2_add_inode_blocks(&ip->i_inode, alloced); | 755 | gfs2_add_inode_blocks(&ip->i_inode, alloced); |
| 767 | gfs2_dinode_out(ip, mp->mp_bh[0]->b_data); | 756 | gfs2_dinode_out(ip, dibh->b_data); |
| 768 | return 0; | 757 | out: |
| 758 | up_write(&ip->i_rw_mutex); | ||
| 759 | return ret; | ||
| 769 | } | 760 | } |
| 770 | 761 | ||
| 771 | static void gfs2_stuffed_iomap(struct inode *inode, struct iomap *iomap) | 762 | static void gfs2_stuffed_iomap(struct inode *inode, struct iomap *iomap) |
| @@ -781,110 +772,130 @@ static void gfs2_stuffed_iomap(struct inode *inode, struct iomap *iomap) | |||
| 781 | } | 772 | } |
| 782 | 773 | ||
| 783 | /** | 774 | /** |
| 784 | * gfs2_iomap_begin - Map blocks from an inode to disk blocks | 775 | * gfs2_iomap_get - Map blocks from an inode to disk blocks |
| 785 | * @inode: The inode | 776 | * @inode: The inode |
| 786 | * @pos: Starting position in bytes | 777 | * @pos: Starting position in bytes |
| 787 | * @length: Length to map, in bytes | 778 | * @length: Length to map, in bytes |
| 788 | * @flags: iomap flags | 779 | * @flags: iomap flags |
| 789 | * @iomap: The iomap structure | 780 | * @iomap: The iomap structure |
| 781 | * @mp: The metapath | ||
| 790 | * | 782 | * |
| 791 | * Returns: errno | 783 | * Returns: errno |
| 792 | */ | 784 | */ |
| 793 | int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, | 785 | static int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, |
| 794 | unsigned flags, struct iomap *iomap) | 786 | unsigned flags, struct iomap *iomap, |
| 787 | struct metapath *mp) | ||
| 795 | { | 788 | { |
| 796 | struct gfs2_inode *ip = GFS2_I(inode); | 789 | struct gfs2_inode *ip = GFS2_I(inode); |
| 797 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 790 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
| 798 | struct metapath mp = { .mp_aheight = 1, }; | ||
| 799 | __be64 *ptr; | 791 | __be64 *ptr; |
| 800 | sector_t lblock; | 792 | sector_t lblock; |
| 801 | sector_t lend; | 793 | sector_t lblock_stop; |
| 802 | int ret = 0; | 794 | int ret; |
| 803 | int eob; | 795 | int eob; |
| 804 | unsigned int len; | 796 | u64 len; |
| 805 | struct buffer_head *bh; | 797 | struct buffer_head *bh; |
| 806 | u8 height; | 798 | u8 height; |
| 807 | 799 | ||
| 808 | trace_gfs2_iomap_start(ip, pos, length, flags); | 800 | if (!length) |
| 809 | if (!length) { | 801 | return -EINVAL; |
| 810 | ret = -EINVAL; | ||
| 811 | goto out; | ||
| 812 | } | ||
| 813 | 802 | ||
| 814 | if (gfs2_is_stuffed(ip)) { | 803 | if (gfs2_is_stuffed(ip)) { |
| 815 | if (flags & IOMAP_REPORT) { | 804 | if (flags & IOMAP_REPORT) { |
| 805 | if (pos >= i_size_read(inode)) | ||
| 806 | return -ENOENT; | ||
| 816 | gfs2_stuffed_iomap(inode, iomap); | 807 | gfs2_stuffed_iomap(inode, iomap); |
| 817 | if (pos >= iomap->length) | 808 | return 0; |
| 818 | ret = -ENOENT; | ||
| 819 | goto out; | ||
| 820 | } | 809 | } |
| 821 | BUG_ON(!(flags & IOMAP_WRITE)); | 810 | BUG_ON(!(flags & IOMAP_WRITE)); |
| 822 | } | 811 | } |
| 823 | |||
| 824 | lblock = pos >> inode->i_blkbits; | 812 | lblock = pos >> inode->i_blkbits; |
| 825 | lend = (pos + length + sdp->sd_sb.sb_bsize - 1) >> inode->i_blkbits; | ||
| 826 | len = lend - lblock; | ||
| 827 | |||
| 828 | iomap->offset = lblock << inode->i_blkbits; | 813 | iomap->offset = lblock << inode->i_blkbits; |
| 829 | iomap->addr = IOMAP_NULL_ADDR; | 814 | lblock_stop = (pos + length - 1) >> inode->i_blkbits; |
| 830 | iomap->type = IOMAP_HOLE; | 815 | len = lblock_stop - lblock + 1; |
| 831 | iomap->length = (u64)(lend - lblock) << inode->i_blkbits; | 816 | |
| 832 | iomap->flags = IOMAP_F_MERGED; | 817 | down_read(&ip->i_rw_mutex); |
| 833 | bmap_lock(ip, flags & IOMAP_WRITE); | ||
| 834 | 818 | ||
| 835 | ret = gfs2_meta_inode_buffer(ip, &mp.mp_bh[0]); | 819 | ret = gfs2_meta_inode_buffer(ip, &mp->mp_bh[0]); |
| 836 | if (ret) | 820 | if (ret) |
| 837 | goto out_release; | 821 | goto unlock; |
| 838 | 822 | ||
| 839 | height = ip->i_height; | 823 | height = ip->i_height; |
| 840 | while ((lblock + 1) * sdp->sd_sb.sb_bsize > sdp->sd_heightsize[height]) | 824 | while ((lblock + 1) * sdp->sd_sb.sb_bsize > sdp->sd_heightsize[height]) |
| 841 | height++; | 825 | height++; |
| 842 | find_metapath(sdp, lblock, &mp, height); | 826 | find_metapath(sdp, lblock, mp, height); |
| 843 | if (height > ip->i_height || gfs2_is_stuffed(ip)) | 827 | if (height > ip->i_height || gfs2_is_stuffed(ip)) |
| 844 | goto do_alloc; | 828 | goto do_alloc; |
| 845 | 829 | ||
| 846 | ret = lookup_metapath(ip, &mp); | 830 | ret = lookup_metapath(ip, mp); |
| 847 | if (ret) | 831 | if (ret) |
| 848 | goto out_release; | 832 | goto unlock; |
| 849 | 833 | ||
| 850 | if (mp.mp_aheight != ip->i_height) | 834 | if (mp->mp_aheight != ip->i_height) |
| 851 | goto do_alloc; | 835 | goto do_alloc; |
| 852 | 836 | ||
| 853 | ptr = metapointer(ip->i_height - 1, &mp); | 837 | ptr = metapointer(ip->i_height - 1, mp); |
| 854 | if (*ptr == 0) | 838 | if (*ptr == 0) |
| 855 | goto do_alloc; | 839 | goto do_alloc; |
| 856 | 840 | ||
| 857 | iomap->type = IOMAP_MAPPED; | 841 | bh = mp->mp_bh[ip->i_height - 1]; |
| 858 | iomap->addr = be64_to_cpu(*ptr) << inode->i_blkbits; | 842 | len = gfs2_extent_length(bh->b_data, bh->b_size, ptr, len, &eob); |
| 859 | 843 | ||
| 860 | bh = mp.mp_bh[ip->i_height - 1]; | 844 | iomap->addr = be64_to_cpu(*ptr) << inode->i_blkbits; |
| 861 | len = gfs2_extent_length(bh->b_data, bh->b_size, ptr, lend - lblock, &eob); | 845 | iomap->length = len << inode->i_blkbits; |
| 846 | iomap->type = IOMAP_MAPPED; | ||
| 847 | iomap->flags = IOMAP_F_MERGED; | ||
| 862 | if (eob) | 848 | if (eob) |
| 863 | iomap->flags |= IOMAP_F_BOUNDARY; | 849 | iomap->flags |= IOMAP_F_BOUNDARY; |
| 864 | iomap->length = (u64)len << inode->i_blkbits; | ||
| 865 | 850 | ||
| 866 | out_release: | ||
| 867 | release_metapath(&mp); | ||
| 868 | bmap_unlock(ip, flags & IOMAP_WRITE); | ||
| 869 | out: | 851 | out: |
| 870 | trace_gfs2_iomap_end(ip, iomap, ret); | 852 | iomap->bdev = inode->i_sb->s_bdev; |
| 853 | unlock: | ||
| 854 | up_read(&ip->i_rw_mutex); | ||
| 871 | return ret; | 855 | return ret; |
| 872 | 856 | ||
| 873 | do_alloc: | 857 | do_alloc: |
| 874 | if (flags & IOMAP_WRITE) { | 858 | iomap->addr = IOMAP_NULL_ADDR; |
| 875 | ret = gfs2_iomap_alloc(inode, iomap, flags, &mp); | 859 | iomap->length = len << inode->i_blkbits; |
| 876 | } else if (flags & IOMAP_REPORT) { | 860 | iomap->type = IOMAP_HOLE; |
| 861 | iomap->flags = 0; | ||
| 862 | if (flags & IOMAP_REPORT) { | ||
| 877 | loff_t size = i_size_read(inode); | 863 | loff_t size = i_size_read(inode); |
| 878 | if (pos >= size) | 864 | if (pos >= size) |
| 879 | ret = -ENOENT; | 865 | ret = -ENOENT; |
| 880 | else if (height <= ip->i_height) | 866 | else if (height == ip->i_height) |
| 881 | ret = gfs2_hole_size(inode, lblock, len, &mp, iomap); | 867 | ret = gfs2_hole_size(inode, lblock, len, mp, iomap); |
| 882 | else | 868 | else |
| 883 | iomap->length = size - pos; | 869 | iomap->length = size - pos; |
| 884 | } | 870 | } |
| 885 | goto out_release; | 871 | goto out; |
| 886 | } | 872 | } |
| 887 | 873 | ||
| 874 | static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length, | ||
| 875 | unsigned flags, struct iomap *iomap) | ||
| 876 | { | ||
| 877 | struct gfs2_inode *ip = GFS2_I(inode); | ||
| 878 | struct metapath mp = { .mp_aheight = 1, }; | ||
| 879 | int ret; | ||
| 880 | |||
| 881 | trace_gfs2_iomap_start(ip, pos, length, flags); | ||
| 882 | if (flags & IOMAP_WRITE) { | ||
| 883 | ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp); | ||
| 884 | if (!ret && iomap->type == IOMAP_HOLE) | ||
| 885 | ret = gfs2_iomap_alloc(inode, iomap, flags, &mp); | ||
| 886 | release_metapath(&mp); | ||
| 887 | } else { | ||
| 888 | ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp); | ||
| 889 | release_metapath(&mp); | ||
| 890 | } | ||
| 891 | trace_gfs2_iomap_end(ip, iomap, ret); | ||
| 892 | return ret; | ||
| 893 | } | ||
| 894 | |||
| 895 | const struct iomap_ops gfs2_iomap_ops = { | ||
| 896 | .iomap_begin = gfs2_iomap_begin, | ||
| 897 | }; | ||
| 898 | |||
| 888 | /** | 899 | /** |
| 889 | * gfs2_block_map - Map one or more blocks of an inode to a disk block | 900 | * gfs2_block_map - Map one or more blocks of an inode to a disk block |
| 890 | * @inode: The inode | 901 | * @inode: The inode |
| @@ -910,25 +921,34 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, | |||
| 910 | struct buffer_head *bh_map, int create) | 921 | struct buffer_head *bh_map, int create) |
| 911 | { | 922 | { |
| 912 | struct gfs2_inode *ip = GFS2_I(inode); | 923 | struct gfs2_inode *ip = GFS2_I(inode); |
| 913 | struct iomap iomap; | 924 | loff_t pos = (loff_t)lblock << inode->i_blkbits; |
| 914 | int ret, flags = 0; | 925 | loff_t length = bh_map->b_size; |
| 926 | struct metapath mp = { .mp_aheight = 1, }; | ||
| 927 | struct iomap iomap = { }; | ||
| 928 | int ret; | ||
| 915 | 929 | ||
| 916 | clear_buffer_mapped(bh_map); | 930 | clear_buffer_mapped(bh_map); |
| 917 | clear_buffer_new(bh_map); | 931 | clear_buffer_new(bh_map); |
| 918 | clear_buffer_boundary(bh_map); | 932 | clear_buffer_boundary(bh_map); |
| 919 | trace_gfs2_bmap(ip, bh_map, lblock, create, 1); | 933 | trace_gfs2_bmap(ip, bh_map, lblock, create, 1); |
| 920 | 934 | ||
| 921 | if (create) | 935 | if (create) { |
| 922 | flags |= IOMAP_WRITE; | 936 | ret = gfs2_iomap_get(inode, pos, length, IOMAP_WRITE, &iomap, &mp); |
| 923 | ret = gfs2_iomap_begin(inode, (loff_t)lblock << inode->i_blkbits, | 937 | if (!ret && iomap.type == IOMAP_HOLE) |
| 924 | bh_map->b_size, flags, &iomap); | 938 | ret = gfs2_iomap_alloc(inode, &iomap, IOMAP_WRITE, &mp); |
| 925 | if (ret) { | 939 | release_metapath(&mp); |
| 926 | if (!create && ret == -ENOENT) { | 940 | } else { |
| 927 | /* Return unmapped buffer beyond the end of file. */ | 941 | ret = gfs2_iomap_get(inode, pos, length, 0, &iomap, &mp); |
| 942 | release_metapath(&mp); | ||
| 943 | |||
| 944 | /* Return unmapped buffer beyond the end of file. */ | ||
| 945 | if (ret == -ENOENT) { | ||
| 928 | ret = 0; | 946 | ret = 0; |
| 947 | goto out; | ||
| 929 | } | 948 | } |
| 930 | goto out; | ||
| 931 | } | 949 | } |
| 950 | if (ret) | ||
| 951 | goto out; | ||
| 932 | 952 | ||
| 933 | if (iomap.length > bh_map->b_size) { | 953 | if (iomap.length > bh_map->b_size) { |
| 934 | iomap.length = bh_map->b_size; | 954 | iomap.length = bh_map->b_size; |
| @@ -1143,6 +1163,19 @@ out: | |||
| 1143 | return error; | 1163 | return error; |
| 1144 | } | 1164 | } |
| 1145 | 1165 | ||
| 1166 | int gfs2_iomap_get_alloc(struct inode *inode, loff_t pos, loff_t length, | ||
| 1167 | struct iomap *iomap) | ||
| 1168 | { | ||
| 1169 | struct metapath mp = { .mp_aheight = 1, }; | ||
| 1170 | int ret; | ||
| 1171 | |||
| 1172 | ret = gfs2_iomap_get(inode, pos, length, IOMAP_WRITE, iomap, &mp); | ||
| 1173 | if (!ret && iomap->type == IOMAP_HOLE) | ||
| 1174 | ret = gfs2_iomap_alloc(inode, iomap, IOMAP_WRITE, &mp); | ||
| 1175 | release_metapath(&mp); | ||
| 1176 | return ret; | ||
| 1177 | } | ||
| 1178 | |||
| 1146 | /** | 1179 | /** |
| 1147 | * sweep_bh_for_rgrps - find an rgrp in a meta buffer and free blocks therein | 1180 | * sweep_bh_for_rgrps - find an rgrp in a meta buffer and free blocks therein |
| 1148 | * @ip: inode | 1181 | * @ip: inode |
