Revert "writeback: fix WB_SYNC_NONE writeback from umount"
[safe/jmp/linux-2.6] / fs / xfs / xfs_iget.c
index f5c904a..6845db9 100644 (file)
@@ -73,7 +73,6 @@ xfs_inode_alloc(
        ASSERT(atomic_read(&ip->i_pincount) == 0);
        ASSERT(!spin_is_locked(&ip->i_flags_lock));
        ASSERT(completion_done(&ip->i_flush));
-       ASSERT(!rwsem_is_locked(&ip->i_iolock.mr_lock));
 
        mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino);
 
@@ -91,7 +90,7 @@ xfs_inode_alloc(
        ip->i_new_size = 0;
 
        /* prevent anyone from using this yet */
-       VFS_I(ip)->i_state = I_NEW|I_LOCK;
+       VFS_I(ip)->i_state = I_NEW;
 
        return ip;
 }
@@ -191,13 +190,12 @@ xfs_iget_cache_hit(
                trace_xfs_iget_reclaim(ip);
 
                /*
-                * We need to set XFS_INEW atomically with clearing the
-                * reclaimable tag so that we do have an indicator of the
-                * inode still being initialized.
+                * We need to set XFS_IRECLAIM to prevent xfs_reclaim_inode
+                * from stomping over us while we recycle the inode.  We can't
+                * clear the radix tree reclaimable tag yet as it requires
+                * pag_ici_lock to be held exclusive.
                 */
-               ip->i_flags |= XFS_INEW;
-               ip->i_flags &= ~XFS_IRECLAIMABLE;
-               __xfs_inode_clear_reclaim_tag(mp, pag, ip);
+               ip->i_flags |= XFS_IRECLAIM;
 
                spin_unlock(&ip->i_flags_lock);
                read_unlock(&pag->pag_ici_lock);
@@ -217,7 +215,15 @@ xfs_iget_cache_hit(
                        trace_xfs_iget_reclaim(ip);
                        goto out_error;
                }
-               inode->i_state = I_LOCK|I_NEW;
+
+               write_lock(&pag->pag_ici_lock);
+               spin_lock(&ip->i_flags_lock);
+               ip->i_flags &= ~(XFS_IRECLAIMABLE | XFS_IRECLAIM);
+               ip->i_flags |= XFS_INEW;
+               __xfs_inode_clear_reclaim_tag(mp, pag, ip);
+               inode->i_state = I_NEW;
+               spin_unlock(&ip->i_flags_lock);
+               write_unlock(&pag->pag_ici_lock);
        } else {
                /* If the VFS inode is being torn down, pause and try again. */
                if (!igrab(inode)) {
@@ -375,7 +381,7 @@ xfs_iget(
                return EINVAL;
 
        /* get the perag structure and ensure that it's inode capable */
-       pag = xfs_get_perag(mp, ino);
+       pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino));
        if (!pag->pagi_inodeok)
                return EINVAL;
        ASSERT(pag->pag_ici_init);
@@ -399,7 +405,7 @@ again:
                if (error)
                        goto out_error_or_again;
        }
-       xfs_put_perag(mp, pag);
+       xfs_perag_put(pag);
 
        *ipp = ip;
 
@@ -418,7 +424,7 @@ out_error_or_again:
                delay(1);
                goto again;
        }
-       xfs_put_perag(mp, pag);
+       xfs_perag_put(pag);
        return error;
 }
 
@@ -478,19 +484,23 @@ xfs_ireclaim(
 {
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_perag        *pag;
+       xfs_agino_t             agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
 
        XFS_STATS_INC(xs_ig_reclaims);
 
        /*
-        * Remove the inode from the per-AG radix tree.  It doesn't matter
-        * if it was never added to it because radix_tree_delete can deal
-        * with that case just fine.
+        * Remove the inode from the per-AG radix tree.
+        *
+        * Because radix_tree_delete won't complain even if the item was never
+        * added to the tree assert that it's been there before to catch
+        * problems with the inode life time early on.
         */
-       pag = xfs_get_perag(mp, ip->i_ino);
+       pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
        write_lock(&pag->pag_ici_lock);
-       radix_tree_delete(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, ip->i_ino));
+       if (!radix_tree_delete(&pag->pag_ici_root, agino))
+               ASSERT(0);
        write_unlock(&pag->pag_ici_lock);
-       xfs_put_perag(mp, pag);
+       xfs_perag_put(pag);
 
        /*
         * Here we do an (almost) spurious inode lock in order to coordinate