xfs: remove log item from AIL in xfs_iflush after a shutdown
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>
This commit is contained in:
parent
dea9609527
commit
32ce90a4b7
4 changed files with 12 additions and 27 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2500,11 +2499,13 @@ corrupt_out:
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -782,6 +782,7 @@ restart:
|
|||
goto reclaim;
|
||||
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
|
||||
xfs_iunpin_wait(ip);
|
||||
xfs_iflush_abort(ip);
|
||||
goto reclaim;
|
||||
}
|
||||
if (xfs_ipincount(ip)) {
|
||||
|
|
Loading…
Reference in a new issue