Merge tag 'gfs2-4.11.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2...
[sfrench/cifs-2.6.git] / fs / gfs2 / bmap.c
index fc5da4cbe88c1c67a8c5ffcb512ee7edf877bb6c..01b97c012c6e9635540eaf2126cd5358726c1082 100644 (file)
@@ -720,6 +720,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_rgrp_list rlist;
+       struct gfs2_trans *tr;
        u64 bn, bstart;
        u32 blen, btotal;
        __be64 *p;
@@ -728,6 +729,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
        unsigned int revokes = 0;
        int x;
        int error;
+       int jblocks_rqsted;
 
        error = gfs2_rindex_update(sdp);
        if (error)
@@ -791,12 +793,17 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
        if (gfs2_rs_active(&ip->i_res)) /* needs to be done with the rgrp glock held */
                gfs2_rs_deltree(&ip->i_res);
 
-       error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE +
-                                RES_INDIRECT + RES_STATFS + RES_QUOTA,
-                                revokes);
+restart:
+       jblocks_rqsted = rg_blocks + RES_DINODE +
+               RES_INDIRECT + RES_STATFS + RES_QUOTA +
+               gfs2_struct2blk(sdp, revokes, sizeof(u64));
+       if (jblocks_rqsted > atomic_read(&sdp->sd_log_thresh2))
+               jblocks_rqsted = atomic_read(&sdp->sd_log_thresh2);
+       error = gfs2_trans_begin(sdp, jblocks_rqsted, revokes);
        if (error)
                goto out_rg_gunlock;
 
+       tr = current->journal_info;
        down_write(&ip->i_rw_mutex);
 
        gfs2_trans_add_meta(ip->i_gl, dibh);
@@ -810,6 +817,16 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
                if (!*p)
                        continue;
 
+               /* check for max reasonable journal transaction blocks */
+               if (tr->tr_num_buf_new + RES_STATFS +
+                   RES_QUOTA >= atomic_read(&sdp->sd_log_thresh2)) {
+                       if (rg_blocks >= tr->tr_num_buf_new)
+                               rg_blocks -= tr->tr_num_buf_new;
+                       else
+                               rg_blocks = 0;
+                       break;
+               }
+
                bn = be64_to_cpu(*p);
 
                if (bstart + blen == bn)
@@ -827,6 +844,9 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
                *p = 0;
                gfs2_add_inode_blocks(&ip->i_inode, -1);
        }
+       if (p == bottom)
+               rg_blocks = 0;
+
        if (bstart) {
                __gfs2_free_blocks(ip, bstart, blen, metadata);
                btotal += blen;
@@ -844,6 +864,9 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
 
        gfs2_trans_end(sdp);
 
+       if (rg_blocks)
+               goto restart;
+
 out_rg_gunlock:
        gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
 out_rlist: