]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
xfs: fix locking for inode cache radix tree tag updates
authorChristoph Hellwig <hch@infradead.org>
Mon, 1 Mar 2010 11:30:31 +0000 (11:30 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 26 Apr 2010 14:48:02 +0000 (07:48 -0700)
commit f1f724e4b523d444c5a598d74505aefa3d6844d2 upstream.

The radix-tree code requires it's users to serialize tag updates
against other updates to the tree.  While XFS protects tag updates
against each other it does not serialize them against updates of the
tree contents, which can lead to tag corruption.  Fix the inode
cache to always take pag_ici_lock in exclusive mode when updating
radix tree tags.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reported-by: Patrick Schreurs <patrick@news-service.com>
Tested-by: Patrick Schreurs <patrick@news-service.com>
Signed-off-by: Alex Elder <aelder@sgi.com>
Cc: Dave Chinner <david@fromorbit.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
fs/xfs/linux-2.6/xfs_sync.c
fs/xfs/xfs_iget.c

index 1f5e4bb5e970af2d74f31ef97d3f371fe3061f87..687e9fc582ca771774c65d5793347fdd98731181 100644 (file)
@@ -693,12 +693,12 @@ xfs_inode_set_reclaim_tag(
        xfs_mount_t     *mp = ip->i_mount;
        xfs_perag_t     *pag = xfs_get_perag(mp, ip->i_ino);
 
-       read_lock(&pag->pag_ici_lock);
+       write_lock(&pag->pag_ici_lock);
        spin_lock(&ip->i_flags_lock);
        __xfs_inode_set_reclaim_tag(pag, ip);
        __xfs_iflags_set(ip, XFS_IRECLAIMABLE);
        spin_unlock(&ip->i_flags_lock);
-       read_unlock(&pag->pag_ici_lock);
+       write_unlock(&pag->pag_ici_lock);
        xfs_put_perag(mp, pag);
 }
 
index 155e798f30a166a9697fd6fad56f42163b6340c7..fd21160a6238d7a994b2c49f25c7e1fb0801904b 100644 (file)
@@ -190,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);
@@ -216,7 +215,15 @@ xfs_iget_cache_hit(
                        trace_xfs_iget_reclaim(ip);
                        goto out_error;
                }
+
+               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)) {