gfs2: Generalize truncate code
authorAndreas Gruenbacher <agruenba@redhat.com>
Mon, 11 Dec 2017 11:49:55 +0000 (12:49 +0100)
committerAndreas Gruenbacher <agruenba@redhat.com>
Thu, 18 Jan 2018 20:15:37 +0000 (21:15 +0100)
Pull the code for computing the range of metapointers to iterate out of
gfs2_metapath_ra (for readahead), sweep_bh_for_rgrps (for deallocating
metapointers within a block), and trunc_dealloc (for walking the
metadata tree).

In sweep_bh_for_rgrps, move the code for looking up the resource group
descriptor of the current resource group out of the inner loop.  The
metatype check moves to trunc_dealloc.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
fs/gfs2/bmap.c

index c4a297e875129f970d0a9179a403fa4390e5074b..8fd42ae026dd64b03be4b6d51d8538936fcd7f80 100644 (file)
@@ -279,15 +279,11 @@ static inline __be64 *metapointer(unsigned int height, const struct metapath *mp
        return p + mp->mp_list[height];
 }
 
-static void gfs2_metapath_ra(struct gfs2_glock *gl, struct metapath *mp,
-                            unsigned int height)
+static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end)
 {
-       struct buffer_head *bh = mp->mp_bh[height];
-       const __be64 *pos = metapointer(height, mp);
-       const __be64 *endp = (const __be64 *)(bh->b_data + bh->b_size);
        const __be64 *t;
 
-       for (t = pos; t < endp; t++) {
+       for (t = start; t < end; t++) {
                struct buffer_head *rabh;
 
                if (!*t)
@@ -1077,10 +1073,11 @@ out:
  * sweep_bh_for_rgrps - find an rgrp in a meta buffer and free blocks therein
  * @ip: inode
  * @rg_gh: holder of resource group glock
- * @mp: current metapath fully populated with buffers
+ * @bh: buffer head to sweep
+ * @start: starting point in bh
+ * @end: end point in bh
+ * @meta: true if bh points to metadata (rather than data)
  * @btotal: place to keep count of total blocks freed
- * @hgt: height we're processing
- * @keep_start: preserve the first meta pointer
  *
  * We sweep a metadata buffer (provided by the metapath) for blocks we need to
  * free, and free them all. However, we do it one rgrp at a time. If this
@@ -1095,47 +1092,46 @@ out:
  *          *btotal has the total number of blocks freed
  */
 static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
-                             const struct metapath *mp, u32 *btotal, int hgt,
-                             bool keep_start)
+                             struct buffer_head *bh, __be64 *start, __be64 *end,
+                             bool meta, u32 *btotal)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_rgrpd *rgd;
        struct gfs2_trans *tr;
-       struct buffer_head *bh = mp->mp_bh[hgt];
-       __be64 *top, *bottom, *p;
+       __be64 *p;
        int blks_outside_rgrp;
        u64 bn, bstart, isize_blks;
        s64 blen; /* needs to be s64 or gfs2_add_inode_blocks breaks */
-       int meta = ((hgt != ip->i_height - 1) ? 1 : 0);
        int ret = 0;
        bool buf_in_tr = false; /* buffer was added to transaction */
 
-       if (gfs2_metatype_check(sdp, bh,
-                               (hgt ? GFS2_METATYPE_IN : GFS2_METATYPE_DI)))
-               return -EIO;
-
 more_rgrps:
+       rgd = NULL;
+       if (gfs2_holder_initialized(rd_gh)) {
+               rgd = gfs2_glock2rgrp(rd_gh->gh_gl);
+               gfs2_assert_withdraw(sdp,
+                            gfs2_glock_is_locked_by_me(rd_gh->gh_gl));
+       }
        blks_outside_rgrp = 0;
        bstart = 0;
        blen = 0;
-       top = metapointer(hgt, mp); /* first ptr from metapath */
-       /* If we're keeping some data at the truncation point, we've got to
-          preserve the metadata tree by adding 1 to the starting metapath. */
-       if (keep_start)
-               top++;
-
-       bottom = (__be64 *)(bh->b_data + bh->b_size);
 
-       for (p = top; p < bottom; p++) {
+       for (p = start; p < end; p++) {
                if (!*p)
                        continue;
                bn = be64_to_cpu(*p);
-               if (gfs2_holder_initialized(rd_gh)) {
-                       rgd = gfs2_glock2rgrp(rd_gh->gh_gl);
-                       gfs2_assert_withdraw(sdp,
-                                    gfs2_glock_is_locked_by_me(rd_gh->gh_gl));
+
+               if (rgd) {
+                       if (!rgrp_contains_block(rgd, bn)) {
+                               blks_outside_rgrp++;
+                               continue;
+                       }
                } else {
                        rgd = gfs2_blk2rgrpd(sdp, bn, true);
+                       if (unlikely(!rgd)) {
+                               ret = -EIO;
+                               goto out;
+                       }
                        ret = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
                                                 0, rd_gh);
                        if (ret)
@@ -1147,11 +1143,6 @@ more_rgrps:
                                gfs2_rs_deltree(&ip->i_res);
                }
 
-               if (!rgrp_contains_block(rgd, bn)) {
-                       blks_outside_rgrp++;
-                       continue;
-               }
-
                /* The size of our transactions will be unknown until we
                   actually process all the metadata blocks that relate to
                   the rgrp. So we estimate. We know it can't be more than
@@ -1170,7 +1161,7 @@ more_rgrps:
                                jblocks_rqsted += isize_blks;
                        revokes = jblocks_rqsted;
                        if (meta)
-                               revokes += hptrs(sdp, hgt);
+                               revokes += end - start;
                        else if (ip->i_depth)
                                revokes += sdp->sd_inptrs;
                        ret = gfs2_trans_begin(sdp, jblocks_rqsted, revokes);
@@ -1228,7 +1219,11 @@ out_unlock:
                                            outside the rgrp we just processed,
                                            do it all over again. */
                if (current->journal_info) {
-                       struct buffer_head *dibh = mp->mp_bh[0];
+                       struct buffer_head *dibh;
+
+                       ret = gfs2_meta_inode_buffer(ip, &dibh);
+                       if (ret)
+                               goto out;
 
                        /* Every transaction boundary, we rewrite the dinode
                           to keep its di_blocks current in case of failure. */
@@ -1236,6 +1231,7 @@ out_unlock:
                                current_time(&ip->i_inode);
                        gfs2_trans_add_meta(ip->i_gl, dibh);
                        gfs2_dinode_out(ip, dibh->b_data);
+                       brelse(dibh);
                        up_write(&ip->i_rw_mutex);
                        gfs2_trans_end(sdp);
                }
@@ -1295,6 +1291,23 @@ static bool mp_eq_to_hgt(struct metapath *mp, __u16 *list, unsigned int h)
        return true;
 }
 
+static inline void
+metapointer_range(struct metapath *mp, int height,
+                 __u16 *start_list, unsigned int start_aligned,
+                 __be64 **start, __be64 **end)
+{
+       struct buffer_head *bh = mp->mp_bh[height];
+       __be64 *first;
+
+       first = metaptr1(height, mp);
+       *start = first;
+       if (mp_eq_to_hgt(mp, start_list, height)) {
+               bool keep_start = height < start_aligned;
+               *start = first + start_list[height] + keep_start;
+       }
+       *end = (__be64 *)(bh->b_data + bh->b_size);
+}
+
 /**
  * trunc_dealloc - truncate a file down to a desired size
  * @ip: inode to truncate
@@ -1321,7 +1334,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
        int ret, state;
        int mp_h; /* metapath buffers are read in to this height */
        u64 prev_bnr = 0;
-       bool keep_start; /* need to preserve the first meta pointer? */
+       __be64 *start, *end;
 
        memset(&mp, 0, sizeof(mp));
        find_metapath(sdp, lblock, &mp, ip->i_height);
@@ -1352,8 +1365,11 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
                goto out_metapath;
 
        /* issue read-ahead on metadata */
-       for (mp_h = 0; mp_h < mp.mp_aheight - 1; mp_h++)
-               gfs2_metapath_ra(ip->i_gl, &mp, mp_h);
+       for (mp_h = 0; mp_h < mp.mp_aheight - 1; mp_h++) {
+               metapointer_range(&mp, mp_h, start_list, start_aligned,
+                                 &start, &end);
+               gfs2_metapath_ra(ip->i_gl, start, end);
+       }
 
        if (mp.mp_aheight == ip->i_height)
                state = DEALLOC_MP_FULL; /* We have a complete metapath */
@@ -1388,11 +1404,20 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
                        }
                        prev_bnr = bh->b_blocknr;
 
-                       keep_start = mp_h < start_aligned &&
-                                    mp_eq_to_hgt(&mp, start_list, mp_h);
+                       if (gfs2_metatype_check(sdp, bh,
+                                               (mp_h ? GFS2_METATYPE_IN :
+                                                       GFS2_METATYPE_DI))) {
+                               ret = -EIO;
+                               goto out;
+                       }
+
+                       metapointer_range(&mp, mp_h, start_list, start_aligned,
+                                         &start, &end);
+                       ret = sweep_bh_for_rgrps(ip, &rd_gh, mp.mp_bh[mp_h],
+                                                start, end,
+                                                mp_h != ip->i_height - 1,
+                                                &btotal);
 
-                       ret = sweep_bh_for_rgrps(ip, &rd_gh, &mp, &btotal,
-                                                mp_h, keep_start);
                        /* If we hit an error or just swept dinode buffer,
                           just exit. */
                        if (ret || !mp_h) {
@@ -1446,9 +1471,12 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
 
                        /* issue read-ahead on metadata */
                        if (mp.mp_aheight > 1) {
-                               for (; ret > 1; ret--)
-                                       gfs2_metapath_ra(ip->i_gl, &mp,
-                                               mp.mp_aheight - ret);
+                               for (; ret > 1; ret--) {
+                                       metapointer_range(&mp, mp.mp_aheight - ret,
+                                                         start_list, start_aligned,
+                                                         &start, &end);
+                                       gfs2_metapath_ra(ip->i_gl, start, end);
+                               }
                        }
 
                        /* If buffers found for the entire strip height */