diff options
Diffstat (limited to 'fs/xfs/xfs_inode.c')
| -rw-r--r-- | fs/xfs/xfs_inode.c | 94 | 
1 files changed, 34 insertions, 60 deletions
| diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index b21022499c2e..bc46c0a133d3 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1656,14 +1656,13 @@ retry:  			iip = ip->i_itemp;  			if (!iip || xfs_inode_clean(ip)) {  				ASSERT(ip != free_ip); -				ip->i_update_core = 0;  				xfs_ifunlock(ip);  				xfs_iunlock(ip, XFS_ILOCK_EXCL);  				continue;  			} -			iip->ili_last_fields = iip->ili_format.ilf_fields; -			iip->ili_format.ilf_fields = 0; +			iip->ili_last_fields = iip->ili_fields; +			iip->ili_fields = 0;  			iip->ili_logged = 1;  			xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,  						&iip->ili_item.li_lsn); @@ -2177,7 +2176,7 @@ xfs_iflush_fork(  	mp = ip->i_mount;  	switch (XFS_IFORK_FORMAT(ip, whichfork)) {  	case XFS_DINODE_FMT_LOCAL: -		if ((iip->ili_format.ilf_fields & dataflag[whichfork]) && +		if ((iip->ili_fields & dataflag[whichfork]) &&  		    (ifp->if_bytes > 0)) {  			ASSERT(ifp->if_u1.if_data != NULL);  			ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); @@ -2187,8 +2186,8 @@ xfs_iflush_fork(  	case XFS_DINODE_FMT_EXTENTS:  		ASSERT((ifp->if_flags & XFS_IFEXTENTS) || -		       !(iip->ili_format.ilf_fields & extflag[whichfork])); -		if ((iip->ili_format.ilf_fields & extflag[whichfork]) && +		       !(iip->ili_fields & extflag[whichfork])); +		if ((iip->ili_fields & extflag[whichfork]) &&  		    (ifp->if_bytes > 0)) {  			ASSERT(xfs_iext_get_ext(ifp, 0));  			ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0); @@ -2198,7 +2197,7 @@ xfs_iflush_fork(  		break;  	case XFS_DINODE_FMT_BTREE: -		if ((iip->ili_format.ilf_fields & brootflag[whichfork]) && +		if ((iip->ili_fields & brootflag[whichfork]) &&  		    (ifp->if_broot_bytes > 0)) {  			ASSERT(ifp->if_broot != NULL);  			ASSERT(ifp->if_broot_bytes <= @@ -2211,14 +2210,14 @@ xfs_iflush_fork(  		break;  	case XFS_DINODE_FMT_DEV: -		if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) { +		if (iip->ili_fields & XFS_ILOG_DEV) {  			ASSERT(whichfork == XFS_DATA_FORK);  			xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev);  		}  		break;  	case XFS_DINODE_FMT_UUID: -		if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) { +		if (iip->ili_fields & XFS_ILOG_UUID) {  			ASSERT(whichfork == XFS_DATA_FORK);  			memcpy(XFS_DFORK_DPTR(dip),  			       &ip->i_df.if_u2.if_uuid, @@ -2451,9 +2450,8 @@ xfs_iflush(  	 * to disk, because the log record didn't make it to disk!  	 */  	if (XFS_FORCED_SHUTDOWN(mp)) { -		ip->i_update_core = 0;  		if (iip) -			iip->ili_format.ilf_fields = 0; +			iip->ili_fields = 0;  		xfs_ifunlock(ip);  		return XFS_ERROR(EIO);  	} @@ -2533,26 +2531,6 @@ xfs_iflush_int(  	/* set *dip = inode's place in the buffer */  	dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset); -	/* -	 * Clear i_update_core before copying out the data. -	 * This is for coordination with our timestamp updates -	 * that don't hold the inode lock. They will always -	 * update the timestamps BEFORE setting i_update_core, -	 * so if we clear i_update_core after they set it we -	 * are guaranteed to see their updates to the timestamps. -	 * I believe that this depends on strongly ordered memory -	 * semantics, but we have that.  We use the SYNCHRONIZE -	 * macro to make sure that the compiler does not reorder -	 * the i_update_core access below the data copy below. -	 */ -	ip->i_update_core = 0; -	SYNCHRONIZE(); - -	/* -	 * Make sure to get the latest timestamps from the Linux inode. -	 */ -	xfs_synchronize_times(ip); -  	if (XFS_TEST_ERROR(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC),  			       mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) {  		xfs_alert_tag(mp, XFS_PTAG_IFLUSH, @@ -2663,36 +2641,33 @@ xfs_iflush_int(  	xfs_inobp_check(mp, bp);  	/* -	 * We've recorded everything logged in the inode, so we'd -	 * like to clear the ilf_fields bits so we don't log and -	 * flush things unnecessarily.  However, we can't stop -	 * logging all this information until the data we've copied -	 * into the disk buffer is written to disk.  If we did we might -	 * overwrite the copy of the inode in the log with all the -	 * data after re-logging only part of it, and in the face of -	 * a crash we wouldn't have all the data we need to recover. +	 * We've recorded everything logged in the inode, so we'd like to clear +	 * the ili_fields bits so we don't log and flush things unnecessarily. +	 * However, we can't stop logging all this information until the data +	 * we've copied into the disk buffer is written to disk.  If we did we +	 * might overwrite the copy of the inode in the log with all the data +	 * after re-logging only part of it, and in the face of a crash we +	 * wouldn't have all the data we need to recover.  	 * -	 * What we do is move the bits to the ili_last_fields field. -	 * When logging the inode, these bits are moved back to the -	 * ilf_fields field.  In the xfs_iflush_done() routine we -	 * clear ili_last_fields, since we know that the information -	 * those bits represent is permanently on disk.  As long as -	 * the flush completes before the inode is logged again, then -	 * both ilf_fields and ili_last_fields will be cleared. +	 * What we do is move the bits to the ili_last_fields field.  When +	 * logging the inode, these bits are moved back to the ili_fields field. +	 * In the xfs_iflush_done() routine we clear ili_last_fields, since we +	 * know that the information those bits represent is permanently on +	 * disk.  As long as the flush completes before the inode is logged +	 * again, then both ili_fields and ili_last_fields will be cleared.  	 * -	 * We can play with the ilf_fields bits here, because the inode -	 * lock must be held exclusively in order to set bits there -	 * and the flush lock protects the ili_last_fields bits. -	 * Set ili_logged so the flush done -	 * routine can tell whether or not to look in the AIL. -	 * Also, store the current LSN of the inode so that we can tell -	 * whether the item has moved in the AIL from xfs_iflush_done(). -	 * In order to read the lsn we need the AIL lock, because -	 * it is a 64 bit value that cannot be read atomically. +	 * We can play with the ili_fields bits here, because the inode lock +	 * must be held exclusively in order to set bits there and the flush +	 * lock protects the ili_last_fields bits.  Set ili_logged so the flush +	 * done routine can tell whether or not to look in the AIL.  Also, store +	 * the current LSN of the inode so that we can tell whether the item has +	 * moved in the AIL from xfs_iflush_done().  In order to read the lsn we +	 * need the AIL lock, because it is a 64 bit value that cannot be read +	 * atomically.  	 */ -	if (iip != NULL && iip->ili_format.ilf_fields != 0) { -		iip->ili_last_fields = iip->ili_format.ilf_fields; -		iip->ili_format.ilf_fields = 0; +	if (iip != NULL && iip->ili_fields != 0) { +		iip->ili_last_fields = iip->ili_fields; +		iip->ili_fields = 0;  		iip->ili_logged = 1;  		xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, @@ -2711,8 +2686,7 @@ xfs_iflush_int(  	} else {  		/*  		 * We're flushing an inode which is not in the AIL and has -		 * not been logged but has i_update_core set.  For this -		 * case we can use a B_DELWRI flush and immediately drop +		 * not been logged.  For this case we can immediately drop  		 * the inode flush lock because we can avoid the whole  		 * AIL state thing.  It's OK to drop the flush lock now,  		 * because we've already locked the buffer and to do anything | 
