diff options
Diffstat (limited to 'fs/xfs/xfs_inode.c')
| -rw-r--r-- | fs/xfs/xfs_inode.c | 58 | 
1 files changed, 44 insertions, 14 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 3da9829c19d..3ca5d43b834 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -442,6 +442,7 @@ xfs_iformat(  			return XFS_ERROR(EFSCORRUPTED);  		}  		ip->i_d.di_size = 0; +		ip->i_size = 0;  		ip->i_df.if_u2.if_rdev = INT_GET(dip->di_u.di_dev, ARCH_CONVERT);  		break; @@ -980,6 +981,7 @@ xfs_iread(  	}  	ip->i_delayed_blks = 0; +	ip->i_size = ip->i_d.di_size;  	/*  	 * Mark the buffer containing the inode as something to keep @@ -1170,6 +1172,7 @@ xfs_ialloc(  	}  	ip->i_d.di_size = 0; +	ip->i_size = 0;  	ip->i_d.di_nextents = 0;  	ASSERT(ip->i_d.di_nblocks == 0);  	xfs_ichgtime(ip, XFS_ICHGTIME_CHG|XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD); @@ -1340,7 +1343,7 @@ xfs_file_last_byte(  	} else {  		last_block = 0;  	} -	size_last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)ip->i_d.di_size); +	size_last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)ip->i_size);  	last_block = XFS_FILEOFF_MAX(last_block, size_last_block);  	last_byte = XFS_FSB_TO_B(mp, last_block); @@ -1421,7 +1424,7 @@ xfs_itrunc_trace(   * must be called again with all the same restrictions as the initial   * call.   */ -void +int  xfs_itruncate_start(  	xfs_inode_t	*ip,  	uint		flags, @@ -1431,9 +1434,10 @@ xfs_itruncate_start(  	xfs_off_t	toss_start;  	xfs_mount_t	*mp;  	bhv_vnode_t	*vp; +	int		error = 0;  	ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0); -	ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size)); +	ASSERT((new_size == 0) || (new_size <= ip->i_size));  	ASSERT((flags == XFS_ITRUNC_DEFINITE) ||  	       (flags == XFS_ITRUNC_MAYBE)); @@ -1468,7 +1472,7 @@ xfs_itruncate_start(  		 * file size, so there is no way that the data extended  		 * out there.  		 */ -		return; +		return 0;  	}  	last_byte = xfs_file_last_byte(ip);  	xfs_itrunc_trace(XFS_ITRUNC_START, ip, flags, new_size, toss_start, @@ -1477,7 +1481,7 @@ xfs_itruncate_start(  		if (flags & XFS_ITRUNC_DEFINITE) {  			bhv_vop_toss_pages(vp, toss_start, -1, FI_REMAPF_LOCKED);  		} else { -			bhv_vop_flushinval_pages(vp, toss_start, -1, FI_REMAPF_LOCKED); +			error = bhv_vop_flushinval_pages(vp, toss_start, -1, FI_REMAPF_LOCKED);  		}  	} @@ -1486,6 +1490,7 @@ xfs_itruncate_start(  		ASSERT(VN_CACHED(vp) == 0);  	}  #endif +	return error;  }  /* @@ -1556,7 +1561,7 @@ xfs_itruncate_finish(  	ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0);  	ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0); -	ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size)); +	ASSERT((new_size == 0) || (new_size <= ip->i_size));  	ASSERT(*tp != NULL);  	ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);  	ASSERT(ip->i_transp == *tp); @@ -1630,8 +1635,20 @@ xfs_itruncate_finish(  	 */  	if (fork == XFS_DATA_FORK) {  		if (ip->i_d.di_nextents > 0) { -			ip->i_d.di_size = new_size; -			xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE); +			/* +			 * If we are not changing the file size then do +			 * not update the on-disk file size - we may be +			 * called from xfs_inactive_free_eofblocks().  If we +			 * update the on-disk file size and then the system +			 * crashes before the contents of the file are +			 * flushed to disk then the files may be full of +			 * holes (ie NULL files bug). +			 */ +			if (ip->i_size != new_size) { +				ip->i_d.di_size = new_size; +				ip->i_size = new_size; +				xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE); +			}  		}  	} else if (sync) {  		ASSERT(!(mp->m_flags & XFS_MOUNT_WSYNC)); @@ -1746,7 +1763,7 @@ xfs_itruncate_finish(  			xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);  		}  		ntp = xfs_trans_dup(ntp); -		(void) xfs_trans_commit(*tp, 0, NULL); +		(void) xfs_trans_commit(*tp, 0);  		*tp = ntp;  		error = xfs_trans_reserve(ntp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,  					  XFS_TRANS_PERM_LOG_RES, @@ -1767,7 +1784,19 @@ xfs_itruncate_finish(  	 */  	if (fork == XFS_DATA_FORK) {  		xfs_isize_check(mp, ip, new_size); -		ip->i_d.di_size = new_size; +		/* +		 * If we are not changing the file size then do +		 * not update the on-disk file size - we may be +		 * called from xfs_inactive_free_eofblocks().  If we +		 * update the on-disk file size and then the system +		 * crashes before the contents of the file are +		 * flushed to disk then the files may be full of +		 * holes (ie NULL files bug). +		 */ +		if (ip->i_size != new_size) { +			ip->i_d.di_size = new_size; +			ip->i_size = new_size; +		}  	}  	xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);  	ASSERT((new_size != 0) || @@ -1800,7 +1829,7 @@ xfs_igrow_start(  	ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0);  	ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0); -	ASSERT(new_size > ip->i_d.di_size); +	ASSERT(new_size > ip->i_size);  	/*  	 * Zero any pages that may have been created by @@ -1808,7 +1837,7 @@ xfs_igrow_start(  	 * and any blocks between the old and new file sizes.  	 */  	error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size, -			     ip->i_d.di_size); +			     ip->i_size);  	return error;  } @@ -1832,13 +1861,14 @@ xfs_igrow_finish(  	ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0);  	ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0);  	ASSERT(ip->i_transp == tp); -	ASSERT(new_size > ip->i_d.di_size); +	ASSERT(new_size > ip->i_size);  	/*  	 * Update the file size.  Update the inode change timestamp  	 * if change_flag set.  	 */  	ip->i_d.di_size = new_size; +	ip->i_size = new_size;  	if (change_flag)  		xfs_ichgtime(ip, XFS_ICHGTIME_CHG);  	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); @@ -2321,7 +2351,7 @@ xfs_ifree(  	ASSERT(ip->i_d.di_nlink == 0);  	ASSERT(ip->i_d.di_nextents == 0);  	ASSERT(ip->i_d.di_anextents == 0); -	ASSERT((ip->i_d.di_size == 0) || +	ASSERT((ip->i_d.di_size == 0 && ip->i_size == 0) ||  	       ((ip->i_d.di_mode & S_IFMT) != S_IFREG));  	ASSERT(ip->i_d.di_nblocks == 0);  | 
