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);
        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;
 
        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: