GFS2: reserve more blocks for transactions
authorBenjamin Marzinski <bmarzins@redhat.com>
Mon, 27 Sep 2010 21:00:04 +0000 (16:00 -0500)
committerSteven Whitehouse <swhiteho@redhat.com>
Tue, 28 Sep 2010 08:44:24 +0000 (09:44 +0100)
Some of the functions in GFS2 were not reserving space in the transaction for
the resource group header and the resource groups bitblocks that get added
when you do allocation. GFS2 now makes sure to reserve space for the
resource group header and either all the bitblocks in the resource group, or
one for each block that it may allocate, whichever is smaller using the new
gfs2_rg_blocks() inline function.

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
fs/gfs2/aops.c
fs/gfs2/bmap.c
fs/gfs2/file.c
fs/gfs2/ops_inode.c
fs/gfs2/quota.c
fs/gfs2/trans.h
fs/gfs2/xattr.c

index 180ef8a6de6b86a5a63aa83eec2036ec79a1b8b5..1bf178831ae8c508da41035ea587e8ed6d060f18 100644 (file)
@@ -663,6 +663,8 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
                rblocks += RES_STATFS + RES_QUOTA;
        if (&ip->i_inode == sdp->sd_rindex)
                rblocks += 2 * RES_STATFS;
+       if (alloc_required)
+               rblocks += gfs2_rg_blocks(al);
 
        error = gfs2_trans_begin(sdp, rblocks,
                                 PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
index 04513e997df6275f98b36cd6c238520a5a33bdb5..5476c066d4ee336733445eda2f804561179ecb41 100644 (file)
@@ -1151,7 +1151,7 @@ static int do_grow(struct inode *inode, u64 size)
                        goto do_grow_qunlock;
        }
 
-       error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
+       error = gfs2_trans_begin(sdp, RES_DINODE + RES_STATFS + RES_RG_BIT, 0);
        if (error)
                goto do_grow_release;
 
index daadcd2e755f2ee2712e58ac830d6c226a35d5a0..237ee6a940df23ab0720ed99252657611d0be7ec 100644 (file)
@@ -382,8 +382,10 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        rblocks = RES_DINODE + ind_blocks;
        if (gfs2_is_jdata(ip))
                rblocks += data_blocks ? data_blocks : 1;
-       if (ind_blocks || data_blocks)
+       if (ind_blocks || data_blocks) {
                rblocks += RES_STATFS + RES_QUOTA;
+               rblocks += gfs2_rg_blocks(al);
+       }
        ret = gfs2_trans_begin(sdp, rblocks, 0);
        if (ret)
                goto out_trans_fail;
index 98a94cfc2bb289a936ee1222eaaebdf34af76200..fba00171d915252c9f9433d26a29d24059a241fb 100644 (file)
@@ -219,7 +219,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
                        goto out_gunlock_q;
 
                error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
-                                        al->al_rgd->rd_length +
+                                        gfs2_rg_blocks(al) +
                                         2 * RES_DINODE + RES_STATFS +
                                         RES_QUOTA, 0);
                if (error)
@@ -884,7 +884,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
                        goto out_gunlock_q;
 
                error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
-                                        al->al_rgd->rd_length +
+                                        gfs2_rg_blocks(al) +
                                         4 * RES_DINODE + 4 * RES_LEAF +
                                         RES_STATFS + RES_QUOTA + 4, 0);
                if (error)
@@ -1481,7 +1481,7 @@ retry:
                al->al_requested = data_blocks + ind_blocks;
 
                rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA +
-                         RES_RG_HDR + ip->i_alloc->al_rgd->rd_length;
+                         RES_RG_HDR + gfs2_rg_blocks(al);
                if (gfs2_is_jdata(ip))
                        rblocks += data_blocks ? data_blocks : 1;
 
index 9bc6dd9a54430509a33352a5d1655600f3464b6e..58a9b9998b42d0d9603c7a49ffc746ab4a22ef87 100644 (file)
@@ -815,7 +815,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
                goto out_alloc;
 
        if (nalloc)
-               blocks += al->al_rgd->rd_length + nalloc * ind_blocks + RES_STATFS;
+               blocks += gfs2_rg_blocks(al) + nalloc * ind_blocks + RES_STATFS;
 
        error = gfs2_trans_begin(sdp, blocks, 0);
        if (error)
@@ -1586,6 +1586,7 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
                error = gfs2_inplace_reserve(ip);
                if (error)
                        goto out_alloc;
+               blocks += gfs2_rg_blocks(al);
        }
 
        error = gfs2_trans_begin(sdp, blocks + RES_DINODE + 1, 0);
index b849eb7ad37d9ce52146ffabaa84d321dd94ace1..fb56b783e028c8ce61b0b663e67e2df14e408b07 100644 (file)
@@ -26,6 +26,14 @@ struct gfs2_glock;
 #define RES_STATFS     1
 #define RES_QUOTA      2
 
+/* reserve either the number of blocks to be allocated plus the rg header
+ * block, or all of the blocks in the rg, whichever is smaller */
+static inline unsigned int gfs2_rg_blocks(const struct gfs2_alloc *al)
+{
+       return (al->al_requested < al->al_rgd->rd_length)?
+              al->al_requested + 1 : al->al_rgd->rd_length;
+}
+
 int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
                     unsigned int revokes);
 
index 776af6eb4bcb1b193ecf5ef858ac09cb0535b95f..30b58f07c8a6b219fc964efe101ce5f861397885 100644 (file)
@@ -734,7 +734,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
                goto out_gunlock_q;
 
        error = gfs2_trans_begin(GFS2_SB(&ip->i_inode),
-                                blks + al->al_rgd->rd_length +
+                                blks + gfs2_rg_blocks(al) +
                                 RES_DINODE + RES_STATFS + RES_QUOTA, 0);
        if (error)
                goto out_ipres;