diff options
-rw-r--r-- | fs/gfs2/bmap.c | 149 |
1 files changed, 71 insertions, 78 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index e60296137707..9d3a0c26df28 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -36,11 +36,6 @@ struct metapath { | |||
36 | __u16 mp_list[GFS2_MAX_META_HEIGHT]; | 36 | __u16 mp_list[GFS2_MAX_META_HEIGHT]; |
37 | }; | 37 | }; |
38 | 38 | ||
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 { | 39 | struct strip_mine { |
45 | int sm_first; | 40 | int sm_first; |
46 | unsigned int sm_height; | 41 | unsigned int sm_height; |
@@ -668,76 +663,6 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi | |||
668 | } | 663 | } |
669 | 664 | ||
670 | /** | 665 | /** |
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 | 666 | * do_strip - Look for a layer a particular layer of the file and strip it off |
742 | * @ip: the inode | 667 | * @ip: the inode |
743 | * @dibh: the dinode buffer | 668 | * @dibh: the dinode buffer |
@@ -752,9 +677,8 @@ out: | |||
752 | 677 | ||
753 | static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | 678 | static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, |
754 | struct buffer_head *bh, __be64 *top, __be64 *bottom, | 679 | struct buffer_head *bh, __be64 *top, __be64 *bottom, |
755 | unsigned int height, void *data) | 680 | unsigned int height, struct strip_mine *sm) |
756 | { | 681 | { |
757 | struct strip_mine *sm = data; | ||
758 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 682 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
759 | struct gfs2_rgrp_list rlist; | 683 | struct gfs2_rgrp_list rlist; |
760 | u64 bn, bstart; | 684 | u64 bn, bstart; |
@@ -886,6 +810,75 @@ out: | |||
886 | } | 810 | } |
887 | 811 | ||
888 | /** | 812 | /** |
813 | * recursive_scan - recursively scan through the end of a file | ||
814 | * @ip: the inode | ||
815 | * @dibh: the dinode buffer | ||
816 | * @mp: the path through the metadata to the point to start | ||
817 | * @height: the height the recursion is at | ||
818 | * @block: the indirect block to look at | ||
819 | * @first: 1 if this is the first block | ||
820 | * @sm: data opaque to this function to pass to @bc | ||
821 | * | ||
822 | * When this is first called @height and @block should be zero and | ||
823 | * @first should be 1. | ||
824 | * | ||
825 | * Returns: errno | ||
826 | */ | ||
827 | |||
828 | static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, | ||
829 | struct metapath *mp, unsigned int height, | ||
830 | u64 block, int first, struct strip_mine *sm) | ||
831 | { | ||
832 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
833 | struct buffer_head *bh = NULL; | ||
834 | __be64 *top, *bottom; | ||
835 | u64 bn; | ||
836 | int error; | ||
837 | int mh_size = sizeof(struct gfs2_meta_header); | ||
838 | |||
839 | if (!height) { | ||
840 | error = gfs2_meta_inode_buffer(ip, &bh); | ||
841 | if (error) | ||
842 | return error; | ||
843 | dibh = bh; | ||
844 | |||
845 | top = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0]; | ||
846 | bottom = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs; | ||
847 | } else { | ||
848 | error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh); | ||
849 | if (error) | ||
850 | return error; | ||
851 | |||
852 | top = (__be64 *)(bh->b_data + mh_size) + | ||
853 | (first ? mp->mp_list[height] : 0); | ||
854 | |||
855 | bottom = (__be64 *)(bh->b_data + mh_size) + sdp->sd_inptrs; | ||
856 | } | ||
857 | |||
858 | error = do_strip(ip, dibh, bh, top, bottom, height, sm); | ||
859 | if (error) | ||
860 | goto out; | ||
861 | |||
862 | if (height < ip->i_height - 1) | ||
863 | for (; top < bottom; top++, first = 0) { | ||
864 | if (!*top) | ||
865 | continue; | ||
866 | |||
867 | bn = be64_to_cpu(*top); | ||
868 | |||
869 | error = recursive_scan(ip, dibh, mp, height + 1, bn, | ||
870 | first, sm); | ||
871 | if (error) | ||
872 | break; | ||
873 | } | ||
874 | |||
875 | out: | ||
876 | brelse(bh); | ||
877 | return error; | ||
878 | } | ||
879 | |||
880 | |||
881 | /** | ||
889 | * gfs2_block_truncate_page - Deal with zeroing out data for truncate | 882 | * gfs2_block_truncate_page - Deal with zeroing out data for truncate |
890 | * | 883 | * |
891 | * This is partly borrowed from ext3. | 884 | * This is partly borrowed from ext3. |
@@ -1024,7 +1017,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size) | |||
1024 | sm.sm_first = !!size; | 1017 | sm.sm_first = !!size; |
1025 | sm.sm_height = height; | 1018 | sm.sm_height = height; |
1026 | 1019 | ||
1027 | error = recursive_scan(ip, NULL, &mp, 0, 0, 1, do_strip, &sm); | 1020 | error = recursive_scan(ip, NULL, &mp, 0, 0, 1, &sm); |
1028 | if (error) | 1021 | if (error) |
1029 | break; | 1022 | break; |
1030 | } | 1023 | } |