|
@@ -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:
|