aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/gfs2/bmap.c52
1 files changed, 49 insertions, 3 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index de70e52caf3a..a68e91bcef3d 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -991,6 +991,41 @@ unlock:
991 return err; 991 return err;
992} 992}
993 993
994/**
995 * gfs2_journaled_truncate - Wrapper for truncate_pagecache for jdata files
996 * @inode: The inode being truncated
997 * @oldsize: The original (larger) size
998 * @newsize: The new smaller size
999 *
1000 * With jdata files, we have to journal a revoke for each block which is
1001 * truncated. As a result, we need to split this into separate transactions
1002 * if the number of pages being truncated gets too large.
1003 */
1004
1005#define GFS2_JTRUNC_REVOKES 8192
1006
1007static int gfs2_journaled_truncate(struct inode *inode, u64 oldsize, u64 newsize)
1008{
1009 struct gfs2_sbd *sdp = GFS2_SB(inode);
1010 u64 max_chunk = GFS2_JTRUNC_REVOKES * sdp->sd_vfs->s_blocksize;
1011 u64 chunk;
1012 int error;
1013
1014 while (oldsize != newsize) {
1015 chunk = oldsize - newsize;
1016 if (chunk > max_chunk)
1017 chunk = max_chunk;
1018 truncate_pagecache(inode, oldsize, oldsize - chunk);
1019 oldsize -= chunk;
1020 gfs2_trans_end(sdp);
1021 error = gfs2_trans_begin(sdp, RES_DINODE, GFS2_JTRUNC_REVOKES);
1022 if (error)
1023 return error;
1024 }
1025
1026 return 0;
1027}
1028
994static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize) 1029static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
995{ 1030{
996 struct gfs2_inode *ip = GFS2_I(inode); 1031 struct gfs2_inode *ip = GFS2_I(inode);
@@ -1000,8 +1035,10 @@ static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
1000 int journaled = gfs2_is_jdata(ip); 1035 int journaled = gfs2_is_jdata(ip);
1001 int error; 1036 int error;
1002 1037
1003 error = gfs2_trans_begin(sdp, 1038 if (journaled)
1004 RES_DINODE + (journaled ? RES_JDATA : 0), 0); 1039 error = gfs2_trans_begin(sdp, RES_DINODE + RES_JDATA, GFS2_JTRUNC_REVOKES);
1040 else
1041 error = gfs2_trans_begin(sdp, RES_DINODE, 0);
1005 if (error) 1042 if (error)
1006 return error; 1043 return error;
1007 1044
@@ -1026,7 +1063,16 @@ static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
1026 ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; 1063 ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
1027 gfs2_dinode_out(ip, dibh->b_data); 1064 gfs2_dinode_out(ip, dibh->b_data);
1028 1065
1029 truncate_pagecache(inode, oldsize, newsize); 1066 if (journaled)
1067 error = gfs2_journaled_truncate(inode, oldsize, newsize);
1068 else
1069 truncate_pagecache(inode, oldsize, newsize);
1070
1071 if (error) {
1072 brelse(dibh);
1073 return error;
1074 }
1075
1030out_brelse: 1076out_brelse:
1031 brelse(dibh); 1077 brelse(dibh);
1032out: 1078out: