xfs: remove log item from AIL in xfs_iflush after a shutdown
authorChristoph Hellwig <hch@infradead.org>
Mon, 23 Apr 2012 05:58:32 +0000 (15:58 +1000)
committerBen Myers <bpm@sgi.com>
Mon, 14 May 2012 21:20:25 +0000 (16:20 -0500)
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>
fs/xfs/xfs_dquot.c
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_sync.c

index e2f6f7c877db32e6d74e69be4c1409d45bd314c8..786a61e1cccd3a41324a1d189980cc5f92dc0d77 100644 (file)
@@ -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);
 
index bcc6c249b2c76016ad26efd15523073c569273a9..ab89ca7fdb95a9272e13951006daa6f956b80454 100644 (file)
@@ -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;
        }
index bc46c0a133d373d3afffad99f1323a8d15b52c19..00f9c2f34e1ff1174ca51366897348c5a57636e9 100644 (file)
@@ -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;
 }
 
 
index c318d8a4a631bb3292c2d50f106629887bebc93c..7648776e0a9ed68c53b8756a40eb72d56567a52d 100644 (file)
@@ -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)) {