aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2012-11-13 04:50:28 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2012-11-13 04:50:28 -0500
commitfa731fc4e045a801814547188a63c2cd49a4cfe6 (patch)
tree639c3ac1ff3ceeb459981248596f996a656cd295 /fs
parent9dbe9610b9df4efe0946299804ed46bb8f91dec2 (diff)
GFS2: Fix truncation of journaled data files
This patch fixes an issue relating to not having enough revokes available when truncating journaled data files. In order to ensure that we do no run out, the truncation is broken into separate pieces if it is large enough. Tested using fsx on a journaled data file. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs')
-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: