diff options
author | Alex Elder <elder@dreamhost.com> | 2012-02-16 17:01:00 -0500 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2012-02-25 14:55:49 -0500 |
commit | ad637a10f444fc66b1f6d4a28fe30d4c61ed0161 (patch) | |
tree | c4512d9553696d9d5e36e40a909c3f7dabdcb1fb /fs | |
parent | 9006fb91cfdf22812923f0536c7531c429c1aeab (diff) |
xfs: only take the ILOCK in xfs_reclaim_inode()
At the end of xfs_reclaim_inode(), the inode is locked in order to
we wait for a possible concurrent lookup to complete before the
inode is freed. This synchronization step was taking both the ILOCK
and the IOLOCK, but the latter was causing lockdep to produce
reports of the possibility of deadlock.
It turns out that there's no need to acquire the IOLOCK at this
point anyway. It may have been required in some earlier version of
the code, but there should be no need to take the IOLOCK in
xfs_iget(), so there's no (longer) any need to get it here for
synchronization. Add an assertion in xfs_iget() as a reminder
of this assumption.
Dave Chinner diagnosed this on IRC, and Christoph Hellwig suggested
no longer including the IOLOCK. I just put together the patch.
Signed-off-by: Alex Elder <elder@dreamhost.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_iget.c | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_sync.c | 10 |
2 files changed, 13 insertions, 6 deletions
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 19dcfb2aac9a..37f22dad5f59 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c | |||
@@ -418,6 +418,15 @@ xfs_iget( | |||
418 | xfs_perag_t *pag; | 418 | xfs_perag_t *pag; |
419 | xfs_agino_t agino; | 419 | xfs_agino_t agino; |
420 | 420 | ||
421 | /* | ||
422 | * xfs_reclaim_inode() uses the ILOCK to ensure an inode | ||
423 | * doesn't get freed while it's being referenced during a | ||
424 | * radix tree traversal here. It assumes this function | ||
425 | * aqcuires only the ILOCK (and therefore it has no need to | ||
426 | * involve the IOLOCK in this synchronization). | ||
427 | */ | ||
428 | ASSERT((lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED)) == 0); | ||
429 | |||
421 | /* reject inode numbers outside existing AGs */ | 430 | /* reject inode numbers outside existing AGs */ |
422 | if (!ino || XFS_INO_TO_AGNO(mp, ino) >= mp->m_sb.sb_agcount) | 431 | if (!ino || XFS_INO_TO_AGNO(mp, ino) >= mp->m_sb.sb_agcount) |
423 | return EINVAL; | 432 | return EINVAL; |
diff --git a/fs/xfs/xfs_sync.c b/fs/xfs/xfs_sync.c index 40b75eecd2b4..71bf846b7280 100644 --- a/fs/xfs/xfs_sync.c +++ b/fs/xfs/xfs_sync.c | |||
@@ -913,17 +913,15 @@ reclaim: | |||
913 | * can reference the inodes in the cache without taking references. | 913 | * can reference the inodes in the cache without taking references. |
914 | * | 914 | * |
915 | * We make that OK here by ensuring that we wait until the inode is | 915 | * We make that OK here by ensuring that we wait until the inode is |
916 | * unlocked after the lookup before we go ahead and free it. We get | 916 | * unlocked after the lookup before we go ahead and free it. |
917 | * both the ilock and the iolock because the code may need to drop the | ||
918 | * ilock one but will still hold the iolock. | ||
919 | */ | 917 | */ |
920 | xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | 918 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
921 | xfs_qm_dqdetach(ip); | 919 | xfs_qm_dqdetach(ip); |
922 | xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | 920 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
923 | 921 | ||
924 | xfs_inode_free(ip); | 922 | xfs_inode_free(ip); |
925 | return error; | ||
926 | 923 | ||
924 | return error; | ||
927 | } | 925 | } |
928 | 926 | ||
929 | /* | 927 | /* |