mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
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>
This commit is contained in:
parent
9dbe9610b9
commit
fa731fc4e0
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user