aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/bmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/gfs2/bmap.c')
-rw-r--r--fs/gfs2/bmap.c199
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
39typedef 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
44struct strip_mine { 40struct 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
272static 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
687static 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
735out:
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
753static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, 714static 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:
887out_rlist: 842out_rlist:
888 gfs2_rlist_free(&rlist); 843 gfs2_rlist_free(&rlist);
889out: 844out:
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
864static 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 }
914out:
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 }