diff options
Diffstat (limited to 'fs/gfs2/bmap.c')
| -rw-r--r-- | fs/gfs2/bmap.c | 199 |
1 files changed, 112 insertions, 87 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 7878c473ae62..41d494d79709 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/spinlock.h> | 10 | #include <linux/spinlock.h> |
| 11 | #include <linux/completion.h> | 11 | #include <linux/completion.h> |
| 12 | #include <linux/buffer_head.h> | 12 | #include <linux/buffer_head.h> |
| 13 | #include <linux/blkdev.h> | ||
| 13 | #include <linux/gfs2_ondisk.h> | 14 | #include <linux/gfs2_ondisk.h> |
| 14 | #include <linux/crc32.h> | 15 | #include <linux/crc32.h> |
| 15 | 16 | ||
| @@ -36,11 +37,6 @@ struct metapath { | |||
| 36 | __u16 mp_list[GFS2_MAX_META_HEIGHT]; | 37 | __u16 mp_list[GFS2_MAX_META_HEIGHT]; |
| 37 | }; | 38 | }; |
| 38 | 39 | ||
| 39 | typedef int (*block_call_t) (struct gfs2_inode *ip, struct buffer_head *dibh, | ||
| 40 | struct buffer_head *bh, __be64 *top, | ||
| 41 | __be64 *bottom, unsigned int height, | ||
| 42 | void *data); | ||
| 43 | |||
| 44 | struct strip_mine { | 40 | struct strip_mine { |
| 45 | int sm_first; | 41 | int sm_first; |
| 46 | unsigned int sm_height; | 42 | unsigned int sm_height; |
| @@ -273,6 +269,30 @@ static inline __be64 *metapointer(unsigned int height, const struct metapath *mp | |||
| 273 | return ((__be64 *)(bh->b_data + head_size)) + mp->mp_list[height]; | 269 | return ((__be64 *)(bh->b_data + head_size)) + mp->mp_list[height]; |
| 274 | } | 270 | } |
| 275 | 271 | ||
| 272 | static void gfs2_metapath_ra(struct gfs2_glock *gl, | ||
| 273 | const struct buffer_head *bh, const __be64 *pos) | ||
| 274 | { | ||
| 275 | struct buffer_head *rabh; | ||
| 276 | const __be64 *endp = (const __be64 *)(bh->b_data + bh->b_size); | ||
| 277 | const __be64 *t; | ||
| 278 | |||
| 279 | for (t = pos; t < endp; t++) { | ||
| 280 | if (!*t) | ||
| 281 | continue; | ||
| 282 | |||
| 283 | rabh = gfs2_getbuf(gl, be64_to_cpu(*t), CREATE); | ||
| 284 | if (trylock_buffer(rabh)) { | ||
| 285 | if (!buffer_uptodate(rabh)) { | ||
| 286 | rabh->b_end_io = end_buffer_read_sync; | ||
| 287 | submit_bh(READA | REQ_META, rabh); | ||
| 288 | continue; | ||
| 289 | } | ||
| 290 | unlock_buffer(rabh); | ||
| 291 | } | ||
| 292 | brelse(rabh); | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 276 | /** | 296 | /** |
| 277 | * lookup_metapath - Walk the metadata tree to a specific point | 297 | * lookup_metapath - Walk the metadata tree to a specific point |
| 278 | * @ip: The inode | 298 | * @ip: The inode |
| @@ -432,12 +452,14 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock, | |||
| 432 | { | 452 | { |
| 433 | struct gfs2_inode *ip = GFS2_I(inode); | 453 | struct gfs2_inode *ip = GFS2_I(inode); |
| 434 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 454 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
| 455 | struct super_block *sb = sdp->sd_vfs; | ||
| 435 | struct buffer_head *dibh = mp->mp_bh[0]; | 456 | struct buffer_head *dibh = mp->mp_bh[0]; |
| 436 | u64 bn, dblock = 0; | 457 | u64 bn, dblock = 0; |
| 437 | unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0; | 458 | unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0; |
| 438 | unsigned dblks = 0; | 459 | unsigned dblks = 0; |
| 439 | unsigned ptrs_per_blk; | 460 | unsigned ptrs_per_blk; |
| 440 | const unsigned end_of_metadata = height - 1; | 461 | const unsigned end_of_metadata = height - 1; |
| 462 | int ret; | ||
| 441 | int eob = 0; | 463 | int eob = 0; |
| 442 | enum alloc_state state; | 464 | enum alloc_state state; |
| 443 | __be64 *ptr; | 465 | __be64 *ptr; |
| @@ -540,6 +562,15 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock, | |||
| 540 | dblock = bn; | 562 | dblock = bn; |
| 541 | while (n-- > 0) | 563 | while (n-- > 0) |
| 542 | *ptr++ = cpu_to_be64(bn++); | 564 | *ptr++ = cpu_to_be64(bn++); |
| 565 | if (buffer_zeronew(bh_map)) { | ||
| 566 | ret = sb_issue_zeroout(sb, dblock, dblks, | ||
| 567 | GFP_NOFS); | ||
| 568 | if (ret) { | ||
| 569 | fs_err(sdp, | ||
| 570 | "Failed to zero data buffers\n"); | ||
| 571 | clear_buffer_zeronew(bh_map); | ||
| 572 | } | ||
| 573 | } | ||
| 543 | break; | 574 | break; |
| 544 | } | 575 | } |
| 545 | } while ((state != ALLOC_DATA) || !dblock); | 576 | } while ((state != ALLOC_DATA) || !dblock); |
| @@ -668,76 +699,6 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi | |||
| 668 | } | 699 | } |
| 669 | 700 | ||
| 670 | /** | 701 | /** |
| 671 | * recursive_scan - recursively scan through the end of a file | ||
| 672 | * @ip: the inode | ||
| 673 | * @dibh: the dinode buffer | ||
| 674 | * @mp: the path through the metadata to the point to start | ||
| 675 | * @height: the height the recursion is at | ||
| 676 | * @block: the indirect block to look at | ||
| 677 | * @first: 1 if this is the first block | ||
| 678 | * @bc: the call to make for each piece of metadata | ||
| 679 | * @data: data opaque to this function to pass to @bc | ||
| 680 | * | ||
| 681 | * When this is first called @height and @block should be zero and | ||
| 682 | * @first should be 1. | ||
| 683 | * | ||
| 684 | * Returns: errno | ||
| 685 | */ | ||
| 686 | |||
| 687 | static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, | ||
| 688 | struct metapath *mp, unsigned int height, | ||
| 689 | u64 block, int first, block_call_t bc, | ||
| 690 | void *data) | ||
| 691 | { | ||
| 692 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
| 693 | struct buffer_head *bh = NULL; | ||
| 694 | __be64 *top, *bottom; | ||
| 695 | u64 bn; | ||
| 696 | int error; | ||
| 697 | int mh_size = sizeof(struct gfs2_meta_header); | ||
| 698 | |||
| 699 | if (!height) { | ||
| 700 | error = gfs2_meta_inode_buffer(ip, &bh); | ||
| 701 | if (error) | ||
| 702 | return error; | ||
| 703 | dibh = bh; | ||
| 704 | |||
| 705 | top = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0]; | ||
| 706 | bottom = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs; | ||
| 707 | } else { | ||
| 708 | error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh); | ||
| 709 | if (error) | ||
| 710 | return error; | ||
| 711 | |||
| 712 | top = (__be64 *)(bh->b_data + mh_size) + | ||
| 713 | (first ? mp->mp_list[height] : 0); | ||
| 714 | |||
| 715 | bottom = (__be64 *)(bh->b_data + mh_size) + sdp->sd_inptrs; | ||
| 716 | } | ||
| 717 | |||
| 718 | error = bc(ip, dibh, bh, top, bottom, height, data); | ||
| 719 | if (error) | ||
| 720 | goto out; | ||
| 721 | |||
| 722 | if (height < ip->i_height - 1) | ||
| 723 | for (; top < bottom; top++, first = 0) { | ||
| 724 | if (!*top) | ||
| 725 | continue; | ||
| 726 | |||
| 727 | bn = be64_to_cpu(*top); | ||
| 728 | |||
| 729 | error = recursive_scan(ip, dibh, mp, height + 1, bn, | ||
| 730 | first, bc, data); | ||
| 731 | if (error) | ||
| 732 | break; | ||
| 733 | } | ||
| 734 | |||
| 735 | out: | ||
| 736 | brelse(bh); | ||
| 737 | return error; | ||
| 738 | } | ||
| 739 | |||
| 740 | /** | ||
| 741 | * do_strip - Look for a layer a particular layer of the file and strip it off | 702 | * do_strip - Look for a layer a particular layer of the file and strip it off |
| 742 | * @ip: the inode | 703 | * @ip: the inode |
| 743 | * @dibh: the dinode buffer | 704 | * @dibh: the dinode buffer |
| @@ -752,9 +713,8 @@ out: | |||
| 752 | 713 | ||
| 753 | static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | 714 | static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, |
| 754 | struct buffer_head *bh, __be64 *top, __be64 *bottom, | 715 | struct buffer_head *bh, __be64 *top, __be64 *bottom, |
| 755 | unsigned int height, void *data) | 716 | unsigned int height, struct strip_mine *sm) |
| 756 | { | 717 | { |
| 757 | struct strip_mine *sm = data; | ||
| 758 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 718 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
| 759 | struct gfs2_rgrp_list rlist; | 719 | struct gfs2_rgrp_list rlist; |
| 760 | u64 bn, bstart; | 720 | u64 bn, bstart; |
| @@ -783,11 +743,6 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
| 783 | else if (ip->i_depth) | 743 | else if (ip->i_depth) |
| 784 | revokes = sdp->sd_inptrs; | 744 | revokes = sdp->sd_inptrs; |
| 785 | 745 | ||
| 786 | if (ip != GFS2_I(sdp->sd_rindex)) | ||
| 787 | error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh); | ||
| 788 | else if (!sdp->sd_rgrps) | ||
| 789 | error = gfs2_ri_update(ip); | ||
| 790 | |||
| 791 | if (error) | 746 | if (error) |
| 792 | return error; | 747 | return error; |
| 793 | 748 | ||
| @@ -805,7 +760,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
| 805 | blen++; | 760 | blen++; |
| 806 | else { | 761 | else { |
| 807 | if (bstart) | 762 | if (bstart) |
| 808 | gfs2_rlist_add(sdp, &rlist, bstart); | 763 | gfs2_rlist_add(ip, &rlist, bstart); |
| 809 | 764 | ||
| 810 | bstart = bn; | 765 | bstart = bn; |
| 811 | blen = 1; | 766 | blen = 1; |
| @@ -813,7 +768,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
| 813 | } | 768 | } |
| 814 | 769 | ||
| 815 | if (bstart) | 770 | if (bstart) |
| 816 | gfs2_rlist_add(sdp, &rlist, bstart); | 771 | gfs2_rlist_add(ip, &rlist, bstart); |
| 817 | else | 772 | else |
| 818 | goto out; /* Nothing to do */ | 773 | goto out; /* Nothing to do */ |
| 819 | 774 | ||
| @@ -887,12 +842,82 @@ out_rg_gunlock: | |||
| 887 | out_rlist: | 842 | out_rlist: |
| 888 | gfs2_rlist_free(&rlist); | 843 | gfs2_rlist_free(&rlist); |
| 889 | out: | 844 | out: |
| 890 | if (ip != GFS2_I(sdp->sd_rindex)) | ||
| 891 | gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh); | ||
| 892 | return error; | 845 | return error; |
| 893 | } | 846 | } |
| 894 | 847 | ||
| 895 | /** | 848 | /** |
| 849 | * recursive_scan - recursively scan through the end of a file | ||
| 850 | * @ip: the inode | ||
| 851 | * @dibh: the dinode buffer | ||
| 852 | * @mp: the path through the metadata to the point to start | ||
| 853 | * @height: the height the recursion is at | ||
| 854 | * @block: the indirect block to look at | ||
| 855 | * @first: 1 if this is the first block | ||
| 856 | * @sm: data opaque to this function to pass to @bc | ||
| 857 | * | ||
| 858 | * When this is first called @height and @block should be zero and | ||
| 859 | * @first should be 1. | ||
| 860 | * | ||
| 861 | * Returns: errno | ||
| 862 | */ | ||
| 863 | |||
| 864 | static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, | ||
| 865 | struct metapath *mp, unsigned int height, | ||
| 866 | u64 block, int first, struct strip_mine *sm) | ||
| 867 | { | ||
| 868 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
| 869 | struct buffer_head *bh = NULL; | ||
| 870 | __be64 *top, *bottom; | ||
| 871 | u64 bn; | ||
| 872 | int error; | ||
| 873 | int mh_size = sizeof(struct gfs2_meta_header); | ||
| 874 | |||
| 875 | if (!height) { | ||
| 876 | error = gfs2_meta_inode_buffer(ip, &bh); | ||
| 877 | if (error) | ||
| 878 | return error; | ||
| 879 | dibh = bh; | ||
| 880 | |||
| 881 | top = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0]; | ||
| 882 | bottom = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs; | ||
| 883 | } else { | ||
| 884 | error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh); | ||
| 885 | if (error) | ||
| 886 | return error; | ||
| 887 | |||
| 888 | top = (__be64 *)(bh->b_data + mh_size) + | ||
| 889 | (first ? mp->mp_list[height] : 0); | ||
| 890 | |||
| 891 | bottom = (__be64 *)(bh->b_data + mh_size) + sdp->sd_inptrs; | ||
| 892 | } | ||
| 893 | |||
| 894 | error = do_strip(ip, dibh, bh, top, bottom, height, sm); | ||
| 895 | if (error) | ||
| 896 | goto out; | ||
| 897 | |||
| 898 | if (height < ip->i_height - 1) { | ||
| 899 | |||
| 900 | gfs2_metapath_ra(ip->i_gl, bh, top); | ||
| 901 | |||
| 902 | for (; top < bottom; top++, first = 0) { | ||
| 903 | if (!*top) | ||
| 904 | continue; | ||
| 905 | |||
| 906 | bn = be64_to_cpu(*top); | ||
| 907 | |||
| 908 | error = recursive_scan(ip, dibh, mp, height + 1, bn, | ||
| 909 | first, sm); | ||
| 910 | if (error) | ||
| 911 | break; | ||
| 912 | } | ||
| 913 | } | ||
| 914 | out: | ||
| 915 | brelse(bh); | ||
| 916 | return error; | ||
| 917 | } | ||
| 918 | |||
| 919 | |||
| 920 | /** | ||
| 896 | * gfs2_block_truncate_page - Deal with zeroing out data for truncate | 921 | * gfs2_block_truncate_page - Deal with zeroing out data for truncate |
| 897 | * | 922 | * |
| 898 | * This is partly borrowed from ext3. | 923 | * This is partly borrowed from ext3. |
| @@ -1031,7 +1056,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size) | |||
| 1031 | sm.sm_first = !!size; | 1056 | sm.sm_first = !!size; |
| 1032 | sm.sm_height = height; | 1057 | sm.sm_height = height; |
| 1033 | 1058 | ||
| 1034 | error = recursive_scan(ip, NULL, &mp, 0, 0, 1, do_strip, &sm); | 1059 | error = recursive_scan(ip, NULL, &mp, 0, 0, 1, &sm); |
| 1035 | if (error) | 1060 | if (error) |
| 1036 | break; | 1061 | break; |
| 1037 | } | 1062 | } |
