aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_vnodeops.c
diff options
context:
space:
mode:
authorDavid Chinner <dgc@sgi.com>2006-11-11 02:05:00 -0500
committerTim Shimmin <tes@sgi.com>2006-11-11 02:05:00 -0500
commit4c60658e0f4e253cf275f12b7c76bf128515a774 (patch)
tree72d591ce30b7bcc8e08b20aa325ac4360921f028 /fs/xfs/xfs_vnodeops.c
parent7a18c386078eaf17ae54595f66c0d64d9c1cb29c (diff)
[XFS] Prevent a deadlock when xfslogd unpins inodes.
The previous fixes for the use after free in xfs_iunpin left a nasty log deadlock when xfslogd unpinned the inode and dropped the last reference to the inode. the ->clear_inode() method can issue transactions, and if the log was full, the transaction could push on the log and get stuck trying to push the inode it was currently unpinning. To fix this, we provide xfs_iunpin a guarantee that it will always have a valid xfs_inode <-> linux inode link or a particular flag will be set on the inode. We then use log forces during lookup to ensure transactions are completed before we recycle the inode. This ensures that xfs_iunpin will never use the linux inode after it is being freed, and any lookup on an inode on the reclaim list will wait until it is safe to attach a new linux inode to the xfs inode. SGI-PV: 956832 SGI-Modid: xfs-linux-melb:xfs-kern:27359a Signed-off-by: David Chinner <dgc@sgi.com> Signed-off-by: Shailendra Tripathi <stripathi@agami.com> Signed-off-by: Takenori Nagano <t-nagano@ah.jp.nec.com> Signed-off-by: Tim Shimmin <tes@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
-rw-r--r--fs/xfs/xfs_vnodeops.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 4c5d73cbb901..bda774a04b8f 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -3827,11 +3827,16 @@ xfs_reclaim(
3827 */ 3827 */
3828 xfs_synchronize_atime(ip); 3828 xfs_synchronize_atime(ip);
3829 3829
3830 /* If we have nothing to flush with this inode then complete the 3830 /*
3831 * teardown now, otherwise break the link between the xfs inode 3831 * If we have nothing to flush with this inode then complete the
3832 * and the linux inode and clean up the xfs inode later. This 3832 * teardown now, otherwise break the link between the xfs inode and the
3833 * avoids flushing the inode to disk during the delete operation 3833 * linux inode and clean up the xfs inode later. This avoids flushing
3834 * itself. 3834 * the inode to disk during the delete operation itself.
3835 *
3836 * When breaking the link, we need to set the XFS_IRECLAIMABLE flag
3837 * first to ensure that xfs_iunpin() will never see an xfs inode
3838 * that has a linux inode being reclaimed. Synchronisation is provided
3839 * by the i_flags_lock.
3835 */ 3840 */
3836 if (!ip->i_update_core && (ip->i_itemp == NULL)) { 3841 if (!ip->i_update_core && (ip->i_itemp == NULL)) {
3837 xfs_ilock(ip, XFS_ILOCK_EXCL); 3842 xfs_ilock(ip, XFS_ILOCK_EXCL);
@@ -3840,11 +3845,13 @@ xfs_reclaim(
3840 } else { 3845 } else {
3841 xfs_mount_t *mp = ip->i_mount; 3846 xfs_mount_t *mp = ip->i_mount;
3842 3847
3843 /* Protect sync from us */ 3848 /* Protect sync and unpin from us */
3844 XFS_MOUNT_ILOCK(mp); 3849 XFS_MOUNT_ILOCK(mp);
3850 spin_lock(&ip->i_flags_lock);
3851 __xfs_iflags_set(ip, XFS_IRECLAIMABLE);
3845 vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip)); 3852 vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip));
3853 spin_unlock(&ip->i_flags_lock);
3846 list_add_tail(&ip->i_reclaim, &mp->m_del_inodes); 3854 list_add_tail(&ip->i_reclaim, &mp->m_del_inodes);
3847 xfs_iflags_set(ip, XFS_IRECLAIMABLE);
3848 XFS_MOUNT_IUNLOCK(mp); 3855 XFS_MOUNT_IUNLOCK(mp);
3849 } 3856 }
3850 return 0; 3857 return 0;