diff options
| -rw-r--r-- | fs/ocfs2/file.c | 99 | 
1 files changed, 60 insertions, 39 deletions
| diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 53bb46ce3cbb..54d7843c0211 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1529,6 +1529,45 @@ static void ocfs2_truncate_cluster_pages(struct inode *inode, u64 byte_start,  	}  } +/* + * zero out partial blocks of one cluster. + * + * start: file offset where zero starts, will be made upper block aligned. + * len: it will be trimmed to the end of current cluster if "start + len" + *      is bigger than it. + */ +static int ocfs2_zeroout_partial_cluster(struct inode *inode, +					u64 start, u64 len) +{ +	int ret; +	u64 start_block, end_block, nr_blocks; +	u64 p_block, offset; +	u32 cluster, p_cluster, nr_clusters; +	struct super_block *sb = inode->i_sb; +	u64 end = ocfs2_align_bytes_to_clusters(sb, start); + +	if (start + len < end) +		end = start + len; + +	start_block = ocfs2_blocks_for_bytes(sb, start); +	end_block = ocfs2_blocks_for_bytes(sb, end); +	nr_blocks = end_block - start_block; +	if (!nr_blocks) +		return 0; + +	cluster = ocfs2_bytes_to_clusters(sb, start); +	ret = ocfs2_get_clusters(inode, cluster, &p_cluster, +				&nr_clusters, NULL); +	if (ret) +		return ret; +	if (!p_cluster) +		return 0; + +	offset = start_block - ocfs2_clusters_to_blocks(sb, cluster); +	p_block = ocfs2_clusters_to_blocks(sb, p_cluster) + offset; +	return sb_issue_zeroout(sb, p_block, nr_blocks, GFP_NOFS); +} +  static int ocfs2_zero_partial_clusters(struct inode *inode,  				       u64 start, u64 len)  { @@ -1538,6 +1577,7 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,  	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);  	unsigned int csize = osb->s_clustersize;  	handle_t *handle; +	loff_t isize = i_size_read(inode);  	/*  	 * The "start" and "end" values are NOT necessarily part of @@ -1558,6 +1598,26 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,  	if ((start & (csize - 1)) == 0 && (end & (csize - 1)) == 0)  		goto out; +	/* No page cache for EOF blocks, issue zero out to disk. */ +	if (end > isize) { +		/* +		 * zeroout eof blocks in last cluster starting from +		 * "isize" even "start" > "isize" because it is +		 * complicated to zeroout just at "start" as "start" +		 * may be not aligned with block size, buffer write +		 * would be required to do that, but out of eof buffer +		 * write is not supported. +		 */ +		ret = ocfs2_zeroout_partial_cluster(inode, isize, +					end - isize); +		if (ret) { +			mlog_errno(ret); +			goto out; +		} +		if (start >= isize) +			goto out; +		end = isize; +	}  	handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);  	if (IS_ERR(handle)) {  		ret = PTR_ERR(handle); @@ -1856,45 +1916,6 @@ out:  }  /* - * zero out partial blocks of one cluster. - * - * start: file offset where zero starts, will be made upper block aligned. - * len: it will be trimmed to the end of current cluster if "start + len" - *      is bigger than it. - */ -static int ocfs2_zeroout_partial_cluster(struct inode *inode, -					u64 start, u64 len) -{ -	int ret; -	u64 start_block, end_block, nr_blocks; -	u64 p_block, offset; -	u32 cluster, p_cluster, nr_clusters; -	struct super_block *sb = inode->i_sb; -	u64 end = ocfs2_align_bytes_to_clusters(sb, start); - -	if (start + len < end) -		end = start + len; - -	start_block = ocfs2_blocks_for_bytes(sb, start); -	end_block = ocfs2_blocks_for_bytes(sb, end); -	nr_blocks = end_block - start_block; -	if (!nr_blocks) -		return 0; - -	cluster = ocfs2_bytes_to_clusters(sb, start); -	ret = ocfs2_get_clusters(inode, cluster, &p_cluster, -				&nr_clusters, NULL); -	if (ret) -		return ret; -	if (!p_cluster) -		return 0; - -	offset = start_block - ocfs2_clusters_to_blocks(sb, cluster); -	p_block = ocfs2_clusters_to_blocks(sb, p_cluster) + offset; -	return sb_issue_zeroout(sb, p_block, nr_blocks, GFP_NOFS); -} - -/*   * Parts of this function taken from xfs_change_file_space()   */  static int __ocfs2_change_file_space(struct file *file, struct inode *inode, | 
