diff options
Diffstat (limited to 'fs/gfs2/bmap.c')
| -rw-r--r-- | fs/gfs2/bmap.c | 71 | 
1 files changed, 40 insertions, 31 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 6306eaae378b..770f3a720db9 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -1351,9 +1351,15 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi  	return ret;  } +/* + * NOTE: Never call gfs2_block_zero_range with an open transaction because it + * uses iomap write to perform its actions, which begin their own transactions + * (iomap_begin, page_prepare, etc.) + */  static int gfs2_block_zero_range(struct inode *inode, loff_t from,  				 unsigned int length)  { +	BUG_ON(current->journal_info);  	return iomap_zero_range(inode, from, length, NULL, &gfs2_iomap_ops);  } @@ -1414,6 +1420,16 @@ static int trunc_start(struct inode *inode, u64 newsize)  	u64 oldsize = inode->i_size;  	int error; +	if (!gfs2_is_stuffed(ip)) { +		unsigned int blocksize = i_blocksize(inode); +		unsigned int offs = newsize & (blocksize - 1); +		if (offs) { +			error = gfs2_block_zero_range(inode, newsize, +						      blocksize - offs); +			if (error) +				return error; +		} +	}  	if (journaled)  		error = gfs2_trans_begin(sdp, RES_DINODE + RES_JDATA, GFS2_JTRUNC_REVOKES);  	else @@ -1427,19 +1443,10 @@ static int trunc_start(struct inode *inode, u64 newsize)  	gfs2_trans_add_meta(ip->i_gl, dibh); -	if (gfs2_is_stuffed(ip)) { +	if (gfs2_is_stuffed(ip))  		gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize); -	} else { -		unsigned int blocksize = i_blocksize(inode); -		unsigned int offs = newsize & (blocksize - 1); -		if (offs) { -			error = gfs2_block_zero_range(inode, newsize, -						      blocksize - offs); -			if (error) -				goto out; -		} +	else  		ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG; -	}  	i_size_write(inode, newsize);  	ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode); @@ -1761,7 +1768,7 @@ static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length)  	u64 lblock = (offset + (1 << bsize_shift) - 1) >> bsize_shift;  	__u16 start_list[GFS2_MAX_META_HEIGHT];  	__u16 __end_list[GFS2_MAX_META_HEIGHT], *end_list = NULL; -	unsigned int start_aligned, uninitialized_var(end_aligned); +	unsigned int start_aligned, end_aligned;  	unsigned int strip_h = ip->i_height - 1;  	u32 btotal = 0;  	int ret, state; @@ -2448,25 +2455,7 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)  	loff_t start, end;  	int error; -	start = round_down(offset, blocksize); -	end = round_up(offset + length, blocksize) - 1; -	error = filemap_write_and_wait_range(inode->i_mapping, start, end); -	if (error) -		return error; - -	if (gfs2_is_jdata(ip)) -		error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA, -					 GFS2_JTRUNC_REVOKES); -	else -		error = gfs2_trans_begin(sdp, RES_DINODE, 0); -	if (error) -		return error; - -	if (gfs2_is_stuffed(ip)) { -		error = stuffed_zero_range(inode, offset, length); -		if (error) -			goto out; -	} else { +	if (!gfs2_is_stuffed(ip)) {  		unsigned int start_off, end_len;  		start_off = offset & (blocksize - 1); @@ -2489,6 +2478,26 @@ int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length)  		}  	} +	start = round_down(offset, blocksize); +	end = round_up(offset + length, blocksize) - 1; +	error = filemap_write_and_wait_range(inode->i_mapping, start, end); +	if (error) +		return error; + +	if (gfs2_is_jdata(ip)) +		error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_JDATA, +					 GFS2_JTRUNC_REVOKES); +	else +		error = gfs2_trans_begin(sdp, RES_DINODE, 0); +	if (error) +		return error; + +	if (gfs2_is_stuffed(ip)) { +		error = stuffed_zero_range(inode, offset, length); +		if (error) +			goto out; +	} +  	if (gfs2_is_jdata(ip)) {  		BUG_ON(!current->journal_info);  		gfs2_journaled_truncate_range(inode, offset, length);  |