diff options
-rw-r--r-- | fs/gfs2/bmap.c | 52 |
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 | |||
1007 | static 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 | |||
994 | static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize) | 1029 | static 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 | |||
1030 | out_brelse: | 1076 | out_brelse: |
1031 | brelse(dibh); | 1077 | brelse(dibh); |
1032 | out: | 1078 | out: |