Skip to content

Commit

Permalink
xfs: remove log item from AIL in xfs_iflush after a shutdown
Browse files Browse the repository at this point in the history
If a filesystem has been forced shutdown we are never going to write inodes
to disk, which means the inode items will stay in the AIL until we free
the inode. Currently that is not a problem, but a pending change requires us
to empty the AIL before shutting down the filesystem. In that case leaving
the inode in the AIL is lethal. Make sure to remove the log item from the AIL
to allow emptying the AIL on shutdown filesystems.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
  • Loading branch information
Christoph Hellwig authored and Ben Myers committed May 14, 2012
1 parent dea9609 commit 32ce90a
Show file tree
Hide file tree
Showing 4 changed files with 12 additions and 27 deletions.
3 changes: 1 addition & 2 deletions fs/xfs/xfs_dquot.c
Original file line number Diff line number Diff line change
Expand Up @@ -915,8 +915,7 @@ xfs_qm_dqflush(

spin_lock(&mp->m_ail->xa_lock);
if (lip->li_flags & XFS_LI_IN_AIL)
xfs_trans_ail_delete(mp->m_ail, lip,
SHUTDOWN_CORRUPT_INCORE);
xfs_trans_ail_delete(mp->m_ail, lip);
else
spin_unlock(&mp->m_ail->xa_lock);

Expand Down
18 changes: 1 addition & 17 deletions fs/xfs/xfs_iget.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,23 +123,7 @@ xfs_inode_free(
xfs_idestroy_fork(ip, XFS_ATTR_FORK);

if (ip->i_itemp) {
/*
* Only if we are shutting down the fs will we see an
* inode still in the AIL. If it is there, we should remove
* it to prevent a use-after-free from occurring.
*/
xfs_log_item_t *lip = &ip->i_itemp->ili_item;
struct xfs_ail *ailp = lip->li_ailp;

ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) ||
XFS_FORCED_SHUTDOWN(ip->i_mount));
if (lip->li_flags & XFS_LI_IN_AIL) {
spin_lock(&ailp->xa_lock);
if (lip->li_flags & XFS_LI_IN_AIL)
xfs_trans_ail_delete(ailp, lip);
else
spin_unlock(&ailp->xa_lock);
}
ASSERT(!(ip->i_itemp->ili_item.li_flags & XFS_LI_IN_AIL));
xfs_inode_item_destroy(ip);
ip->i_itemp = NULL;
}
Expand Down
17 changes: 9 additions & 8 deletions fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2397,7 +2397,6 @@ xfs_iflush(
xfs_inode_t *ip,
uint flags)
{
xfs_inode_log_item_t *iip;
xfs_buf_t *bp;
xfs_dinode_t *dip;
xfs_mount_t *mp;
Expand All @@ -2410,7 +2409,6 @@ xfs_iflush(
ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK));

iip = ip->i_itemp;
mp = ip->i_mount;

/*
Expand Down Expand Up @@ -2447,13 +2445,14 @@ xfs_iflush(
/*
* This may have been unpinned because the filesystem is shutting
* down forcibly. If that's the case we must not write this inode
* to disk, because the log record didn't make it to disk!
* to disk, because the log record didn't make it to disk.
*
* We also have to remove the log item from the AIL in this case,
* as we wait for an empty AIL as part of the unmount process.
*/
if (XFS_FORCED_SHUTDOWN(mp)) {
if (iip)
iip->ili_fields = 0;
xfs_ifunlock(ip);
return XFS_ERROR(EIO);
error = XFS_ERROR(EIO);
goto abort_out;
}

/*
Expand Down Expand Up @@ -2500,11 +2499,13 @@ xfs_iflush(
xfs_buf_relse(bp);
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
cluster_corrupt_out:
error = XFS_ERROR(EFSCORRUPTED);
abort_out:
/*
* Unlocks the flush lock
*/
xfs_iflush_abort(ip);
return XFS_ERROR(EFSCORRUPTED);
return error;
}


Expand Down
1 change: 1 addition & 0 deletions fs/xfs/xfs_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,7 @@ xfs_reclaim_inode(
goto reclaim;
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
xfs_iunpin_wait(ip);
xfs_iflush_abort(ip);
goto reclaim;
}
if (xfs_ipincount(ip)) {
Expand Down

0 comments on commit 32ce90a

Please sign in to comment.