aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2010-03-01 06:30:31 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-04-26 10:48:02 -0400
commit87bcb4b15d9443cf9a12943fb9162e53ac045b55 (patch)
tree80a5b56caeffb1d3e01c798ecac8e9ab6ca03d17 /fs/xfs
parent30cd163f7c089175033d643bcd475c552926fbbf (diff)
xfs: fix locking for inode cache radix tree tag updates
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>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c4
-rw-r--r--fs/xfs/xfs_iget.c19
2 files changed, 15 insertions, 8 deletions
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index 1f5e4bb5e970..687e9fc582ca 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -693,12 +693,12 @@ xfs_inode_set_reclaim_tag(
693 xfs_mount_t *mp = ip->i_mount; 693 xfs_mount_t *mp = ip->i_mount;
694 xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino); 694 xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino);
695 695
696 read_lock(&pag->pag_ici_lock); 696 write_lock(&pag->pag_ici_lock);
697 spin_lock(&ip->i_flags_lock); 697 spin_lock(&ip->i_flags_lock);
698 __xfs_inode_set_reclaim_tag(pag, ip); 698 __xfs_inode_set_reclaim_tag(pag, ip);
699 __xfs_iflags_set(ip, XFS_IRECLAIMABLE); 699 __xfs_iflags_set(ip, XFS_IRECLAIMABLE);
700 spin_unlock(&ip->i_flags_lock); 700 spin_unlock(&ip->i_flags_lock);
701 read_unlock(&pag->pag_ici_lock); 701 write_unlock(&pag->pag_ici_lock);
702 xfs_put_perag(mp, pag); 702 xfs_put_perag(mp, pag);
703} 703}
704 704
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index 155e798f30a1..fd21160a6238 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -190,13 +190,12 @@ xfs_iget_cache_hit(
190 trace_xfs_iget_reclaim(ip); 190 trace_xfs_iget_reclaim(ip);
191 191
192 /* 192 /*
193 * We need to set XFS_INEW atomically with clearing the 193 * We need to set XFS_IRECLAIM to prevent xfs_reclaim_inode
194 * reclaimable tag so that we do have an indicator of the 194 * from stomping over us while we recycle the inode. We can't
195 * inode still being initialized. 195 * clear the radix tree reclaimable tag yet as it requires
196 * pag_ici_lock to be held exclusive.
196 */ 197 */
197 ip->i_flags |= XFS_INEW; 198 ip->i_flags |= XFS_IRECLAIM;
198 ip->i_flags &= ~XFS_IRECLAIMABLE;
199 __xfs_inode_clear_reclaim_tag(mp, pag, ip);
200 199
201 spin_unlock(&ip->i_flags_lock); 200 spin_unlock(&ip->i_flags_lock);
202 read_unlock(&pag->pag_ici_lock); 201 read_unlock(&pag->pag_ici_lock);
@@ -216,7 +215,15 @@ xfs_iget_cache_hit(
216 trace_xfs_iget_reclaim(ip); 215 trace_xfs_iget_reclaim(ip);
217 goto out_error; 216 goto out_error;
218 } 217 }
218
219 write_lock(&pag->pag_ici_lock);
220 spin_lock(&ip->i_flags_lock);
221 ip->i_flags &= ~(XFS_IRECLAIMABLE | XFS_IRECLAIM);
222 ip->i_flags |= XFS_INEW;
223 __xfs_inode_clear_reclaim_tag(mp, pag, ip);
219 inode->i_state = I_NEW; 224 inode->i_state = I_NEW;
225 spin_unlock(&ip->i_flags_lock);
226 write_unlock(&pag->pag_ici_lock);
220 } else { 227 } else {
221 /* If the VFS inode is being torn down, pause and try again. */ 228 /* If the VFS inode is being torn down, pause and try again. */
222 if (!igrab(inode)) { 229 if (!igrab(inode)) {