]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/gfs2/bmap.c
Merge branch 'x86-cleanups-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / fs / gfs2 / bmap.c
index 1fd3ae237bdde3faee7b67d68bfc50b496b6e976..a68e91bcef3ddf7d005665955ecff7909ccb171f 100644 (file)
@@ -991,6 +991,41 @@ unlock:
        return err;
 }
 
+/**
+ * gfs2_journaled_truncate - Wrapper for truncate_pagecache for jdata files
+ * @inode: The inode being truncated
+ * @oldsize: The original (larger) size
+ * @newsize: The new smaller size
+ *
+ * With jdata files, we have to journal a revoke for each block which is
+ * truncated. As a result, we need to split this into separate transactions
+ * if the number of pages being truncated gets too large.
+ */
+
+#define GFS2_JTRUNC_REVOKES 8192
+
+static int gfs2_journaled_truncate(struct inode *inode, u64 oldsize, u64 newsize)
+{
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+       u64 max_chunk = GFS2_JTRUNC_REVOKES * sdp->sd_vfs->s_blocksize;
+       u64 chunk;
+       int error;
+
+       while (oldsize != newsize) {
+               chunk = oldsize - newsize;
+               if (chunk > max_chunk)
+                       chunk = max_chunk;
+               truncate_pagecache(inode, oldsize, oldsize - chunk);
+               oldsize -= chunk;
+               gfs2_trans_end(sdp);
+               error = gfs2_trans_begin(sdp, RES_DINODE, GFS2_JTRUNC_REVOKES);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
 static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
@@ -1000,8 +1035,10 @@ static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
        int journaled = gfs2_is_jdata(ip);
        int error;
 
-       error = gfs2_trans_begin(sdp,
-                                RES_DINODE + (journaled ? RES_JDATA : 0), 0);
+       if (journaled)
+               error = gfs2_trans_begin(sdp, RES_DINODE + RES_JDATA, GFS2_JTRUNC_REVOKES);
+       else
+               error = gfs2_trans_begin(sdp, RES_DINODE, 0);
        if (error)
                return error;
 
@@ -1026,7 +1063,16 @@ static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
        ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
        gfs2_dinode_out(ip, dibh->b_data);
 
-       truncate_pagecache(inode, oldsize, newsize);
+       if (journaled)
+               error = gfs2_journaled_truncate(inode, oldsize, newsize);
+       else
+               truncate_pagecache(inode, oldsize, newsize);
+
+       if (error) {
+               brelse(dibh);
+               return error;
+       }
+
 out_brelse:
        brelse(dibh);
 out:
@@ -1178,7 +1224,7 @@ static int do_grow(struct inode *inode, u64 size)
                if (error)
                        return error;
 
-               error = gfs2_inplace_reserve(ip, 1);
+               error = gfs2_inplace_reserve(ip, 1, 0);
                if (error)
                        goto do_grow_qunlock;
                unstuff = 1;