]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/gfs2/bmap.c
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
[karo-tx-linux.git] / fs / gfs2 / bmap.c
index 7878c473ae6206b3d3211707868de05b63c2a0c4..41d494d7970918644f338411d2fc523c89a641e1 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
+#include <linux/blkdev.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
 
@@ -36,11 +37,6 @@ struct metapath {
        __u16 mp_list[GFS2_MAX_META_HEIGHT];
 };
 
-typedef int (*block_call_t) (struct gfs2_inode *ip, struct buffer_head *dibh,
-                            struct buffer_head *bh, __be64 *top,
-                            __be64 *bottom, unsigned int height,
-                            void *data);
-
 struct strip_mine {
        int sm_first;
        unsigned int sm_height;
@@ -273,6 +269,30 @@ static inline __be64 *metapointer(unsigned int height, const struct metapath *mp
        return ((__be64 *)(bh->b_data + head_size)) + mp->mp_list[height];
 }
 
+static void gfs2_metapath_ra(struct gfs2_glock *gl,
+                            const struct buffer_head *bh, const __be64 *pos)
+{
+       struct buffer_head *rabh;
+       const __be64 *endp = (const __be64 *)(bh->b_data + bh->b_size);
+       const __be64 *t;
+
+       for (t = pos; t < endp; t++) {
+               if (!*t)
+                       continue;
+
+               rabh = gfs2_getbuf(gl, be64_to_cpu(*t), CREATE);
+               if (trylock_buffer(rabh)) {
+                       if (!buffer_uptodate(rabh)) {
+                               rabh->b_end_io = end_buffer_read_sync;
+                               submit_bh(READA | REQ_META, rabh);
+                               continue;
+                       }
+                       unlock_buffer(rabh);
+               }
+               brelse(rabh);
+       }
+}
+
 /**
  * lookup_metapath - Walk the metadata tree to a specific point
  * @ip: The inode
@@ -432,12 +452,14 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
 {
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
+       struct super_block *sb = sdp->sd_vfs;
        struct buffer_head *dibh = mp->mp_bh[0];
        u64 bn, dblock = 0;
        unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0;
        unsigned dblks = 0;
        unsigned ptrs_per_blk;
        const unsigned end_of_metadata = height - 1;
+       int ret;
        int eob = 0;
        enum alloc_state state;
        __be64 *ptr;
@@ -540,6 +562,15 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
                        dblock = bn;
                        while (n-- > 0)
                                *ptr++ = cpu_to_be64(bn++);
+                       if (buffer_zeronew(bh_map)) {
+                               ret = sb_issue_zeroout(sb, dblock, dblks,
+                                                      GFP_NOFS);
+                               if (ret) {
+                                       fs_err(sdp,
+                                              "Failed to zero data buffers\n");
+                                       clear_buffer_zeronew(bh_map);
+                               }
+                       }
                        break;
                }
        } while ((state != ALLOC_DATA) || !dblock);
@@ -667,76 +698,6 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
        return ret;
 }
 
-/**
- * recursive_scan - recursively scan through the end of a file
- * @ip: the inode
- * @dibh: the dinode buffer
- * @mp: the path through the metadata to the point to start
- * @height: the height the recursion is at
- * @block: the indirect block to look at
- * @first: 1 if this is the first block
- * @bc: the call to make for each piece of metadata
- * @data: data opaque to this function to pass to @bc
- *
- * When this is first called @height and @block should be zero and
- * @first should be 1.
- *
- * Returns: errno
- */
-
-static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
-                         struct metapath *mp, unsigned int height,
-                         u64 block, int first, block_call_t bc,
-                         void *data)
-{
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct buffer_head *bh = NULL;
-       __be64 *top, *bottom;
-       u64 bn;
-       int error;
-       int mh_size = sizeof(struct gfs2_meta_header);
-
-       if (!height) {
-               error = gfs2_meta_inode_buffer(ip, &bh);
-               if (error)
-                       return error;
-               dibh = bh;
-
-               top = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0];
-               bottom = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs;
-       } else {
-               error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh);
-               if (error)
-                       return error;
-
-               top = (__be64 *)(bh->b_data + mh_size) +
-                                 (first ? mp->mp_list[height] : 0);
-
-               bottom = (__be64 *)(bh->b_data + mh_size) + sdp->sd_inptrs;
-       }
-
-       error = bc(ip, dibh, bh, top, bottom, height, data);
-       if (error)
-               goto out;
-
-       if (height < ip->i_height - 1)
-               for (; top < bottom; top++, first = 0) {
-                       if (!*top)
-                               continue;
-
-                       bn = be64_to_cpu(*top);
-
-                       error = recursive_scan(ip, dibh, mp, height + 1, bn,
-                                              first, bc, data);
-                       if (error)
-                               break;
-               }
-
-out:
-       brelse(bh);
-       return error;
-}
-
 /**
  * do_strip - Look for a layer a particular layer of the file and strip it off
  * @ip: the inode
@@ -752,9 +713,8 @@ out:
 
 static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
                    struct buffer_head *bh, __be64 *top, __be64 *bottom,
-                   unsigned int height, void *data)
+                   unsigned int height, struct strip_mine *sm)
 {
-       struct strip_mine *sm = data;
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_rgrp_list rlist;
        u64 bn, bstart;
@@ -783,11 +743,6 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
        else if (ip->i_depth)
                revokes = sdp->sd_inptrs;
 
-       if (ip != GFS2_I(sdp->sd_rindex))
-               error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh);
-       else if (!sdp->sd_rgrps)
-               error = gfs2_ri_update(ip);
-
        if (error)
                return error;
 
@@ -805,7 +760,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
                        blen++;
                else {
                        if (bstart)
-                               gfs2_rlist_add(sdp, &rlist, bstart);
+                               gfs2_rlist_add(ip, &rlist, bstart);
 
                        bstart = bn;
                        blen = 1;
@@ -813,7 +768,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
        }
 
        if (bstart)
-               gfs2_rlist_add(sdp, &rlist, bstart);
+               gfs2_rlist_add(ip, &rlist, bstart);
        else
                goto out; /* Nothing to do */
 
@@ -887,11 +842,81 @@ out_rg_gunlock:
 out_rlist:
        gfs2_rlist_free(&rlist);
 out:
-       if (ip != GFS2_I(sdp->sd_rindex))
-               gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh);
        return error;
 }
 
+/**
+ * recursive_scan - recursively scan through the end of a file
+ * @ip: the inode
+ * @dibh: the dinode buffer
+ * @mp: the path through the metadata to the point to start
+ * @height: the height the recursion is at
+ * @block: the indirect block to look at
+ * @first: 1 if this is the first block
+ * @sm: data opaque to this function to pass to @bc
+ *
+ * When this is first called @height and @block should be zero and
+ * @first should be 1.
+ *
+ * Returns: errno
+ */
+
+static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
+                         struct metapath *mp, unsigned int height,
+                         u64 block, int first, struct strip_mine *sm)
+{
+       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       struct buffer_head *bh = NULL;
+       __be64 *top, *bottom;
+       u64 bn;
+       int error;
+       int mh_size = sizeof(struct gfs2_meta_header);
+
+       if (!height) {
+               error = gfs2_meta_inode_buffer(ip, &bh);
+               if (error)
+                       return error;
+               dibh = bh;
+
+               top = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0];
+               bottom = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs;
+       } else {
+               error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh);
+               if (error)
+                       return error;
+
+               top = (__be64 *)(bh->b_data + mh_size) +
+                                 (first ? mp->mp_list[height] : 0);
+
+               bottom = (__be64 *)(bh->b_data + mh_size) + sdp->sd_inptrs;
+       }
+
+       error = do_strip(ip, dibh, bh, top, bottom, height, sm);
+       if (error)
+               goto out;
+
+       if (height < ip->i_height - 1) {
+
+               gfs2_metapath_ra(ip->i_gl, bh, top);
+
+               for (; top < bottom; top++, first = 0) {
+                       if (!*top)
+                               continue;
+
+                       bn = be64_to_cpu(*top);
+
+                       error = recursive_scan(ip, dibh, mp, height + 1, bn,
+                                              first, sm);
+                       if (error)
+                               break;
+               }
+       }
+out:
+       brelse(bh);
+       return error;
+}
+
+
 /**
  * gfs2_block_truncate_page - Deal with zeroing out data for truncate
  *
@@ -1031,7 +1056,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size)
                sm.sm_first = !!size;
                sm.sm_height = height;
 
-               error = recursive_scan(ip, NULL, &mp, 0, 0, 1, do_strip, &sm);
+               error = recursive_scan(ip, NULL, &mp, 0, 0, 1, &sm);
                if (error)
                        break;
        }