diff options
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_inode.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 48146bdc6bdd..94b60dd03801 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -2732,16 +2732,29 @@ xfs_iunpin( | |||
2732 | ASSERT(atomic_read(&ip->i_pincount) > 0); | 2732 | ASSERT(atomic_read(&ip->i_pincount) > 0); |
2733 | 2733 | ||
2734 | if (atomic_dec_and_test(&ip->i_pincount)) { | 2734 | if (atomic_dec_and_test(&ip->i_pincount)) { |
2735 | vnode_t *vp = XFS_ITOV_NULL(ip); | 2735 | /* |
2736 | * If the inode is currently being reclaimed, the | ||
2737 | * linux inode _and_ the xfs vnode may have been | ||
2738 | * freed so we cannot reference either of them safely. | ||
2739 | * Hence we should not try to do anything to them | ||
2740 | * if the xfs inode is currently in the reclaim | ||
2741 | * path. | ||
2742 | * | ||
2743 | * However, we still need to issue the unpin wakeup | ||
2744 | * call as the inode reclaim may be blocked waiting for | ||
2745 | * the inode to become unpinned. | ||
2746 | */ | ||
2747 | if (!(ip->i_flags & (XFS_IRECLAIM|XFS_IRECLAIMABLE))) { | ||
2748 | vnode_t *vp = XFS_ITOV_NULL(ip); | ||
2736 | 2749 | ||
2737 | /* make sync come back and flush this inode */ | 2750 | /* make sync come back and flush this inode */ |
2738 | if (vp) { | 2751 | if (vp) { |
2739 | struct inode *inode = vn_to_inode(vp); | 2752 | struct inode *inode = vn_to_inode(vp); |
2740 | 2753 | ||
2741 | if (!(inode->i_state & I_NEW)) | 2754 | if (!(inode->i_state & I_NEW)) |
2742 | mark_inode_dirty_sync(inode); | 2755 | mark_inode_dirty_sync(inode); |
2756 | } | ||
2743 | } | 2757 | } |
2744 | |||
2745 | wake_up(&ip->i_ipin_wait); | 2758 | wake_up(&ip->i_ipin_wait); |
2746 | } | 2759 | } |
2747 | } | 2760 | } |