]> Pileus Git - ~andy/linux/commitdiff
[XFS] Can't lock inodes in radix tree preload region
authorDavid Chinner <david@fromorbit.com>
Thu, 30 Oct 2008 06:55:27 +0000 (17:55 +1100)
committerLachlan McIlroy <lachlan@sgi.com>
Thu, 30 Oct 2008 06:55:27 +0000 (17:55 +1100)
When we are inside a radix tree preload region, we cannot sleep. Recently
we moved the inode locking inside the preload region for the inode radix
tree. Fix that, and fix a missed unlock in another error path in the same
code at the same time.

SGI-PV: 987246

SGI-Modid: xfs-linux-melb:xfs-kern:32385a

Signed-off-by: David Chinner <david@fromorbit.com>
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: Christoph Hellwig <hch@infradead.org>
fs/xfs/xfs_iget.c

index a1f209b0596f7c0dce26a83a226e661cdbf6c4cf..377c0cd149997883dbb8abca7b1042a1b04085c9 100644 (file)
@@ -159,18 +159,19 @@ xfs_iget_cache_miss(
                goto out_destroy;
        }
 
+       if (lock_flags)
+               xfs_ilock(ip, lock_flags);
+
        /*
         * Preload the radix tree so we can insert safely under the
-        * write spinlock.
+        * write spinlock. Note that we cannot sleep inside the preload
+        * region.
         */
        if (radix_tree_preload(GFP_KERNEL)) {
                error = EAGAIN;
-               goto out_destroy;
+               goto out_unlock;
        }
 
-       if (lock_flags)
-               xfs_ilock(ip, lock_flags);
-
        mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1);
        first_index = agino & mask;
        write_lock(&pag->pag_ici_lock);
@@ -181,7 +182,7 @@ xfs_iget_cache_miss(
                WARN_ON(error != -EEXIST);
                XFS_STATS_INC(xs_ig_dup);
                error = EAGAIN;
-               goto out_unlock;
+               goto out_preload_end;
        }
 
        /* These values _must_ be set before releasing the radix tree lock! */
@@ -193,9 +194,12 @@ xfs_iget_cache_miss(
        *ipp = ip;
        return 0;
 
-out_unlock:
+out_preload_end:
        write_unlock(&pag->pag_ici_lock);
        radix_tree_preload_end();
+out_unlock:
+       if (lock_flags)
+               xfs_iunlock(ip, lock_flags);
 out_destroy:
        xfs_idestroy(ip);
        return error;