diff options
Diffstat (limited to 'fs/xfs/xfs_inode.c')
-rw-r--r-- | fs/xfs/xfs_inode.c | 47 |
1 files changed, 22 insertions, 25 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 17d2a471751e..d72c80dbfbb1 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -2741,42 +2741,39 @@ xfs_iunpin( | |||
2741 | { | 2741 | { |
2742 | ASSERT(atomic_read(&ip->i_pincount) > 0); | 2742 | ASSERT(atomic_read(&ip->i_pincount) > 0); |
2743 | 2743 | ||
2744 | if (atomic_dec_and_test(&ip->i_pincount)) { | 2744 | if (atomic_dec_and_lock(&ip->i_pincount, &ip->i_flags_lock)) { |
2745 | |||
2745 | /* | 2746 | /* |
2746 | * If the inode is currently being reclaimed, the | 2747 | * If the inode is currently being reclaimed, the link between |
2747 | * linux inode _and_ the xfs vnode may have been | 2748 | * the bhv_vnode and the xfs_inode will be broken after the |
2748 | * freed so we cannot reference either of them safely. | 2749 | * XFS_IRECLAIM* flag is set. Hence, if these flags are not |
2749 | * Hence we should not try to do anything to them | 2750 | * set, then we can move forward and mark the linux inode dirty |
2750 | * if the xfs inode is currently in the reclaim | 2751 | * knowing that it is still valid as it won't freed until after |
2751 | * path. | 2752 | * the bhv_vnode<->xfs_inode link is broken in xfs_reclaim. The |
2753 | * i_flags_lock is used to synchronise the setting of the | ||
2754 | * XFS_IRECLAIM* flags and the breaking of the link, and so we | ||
2755 | * can execute atomically w.r.t to reclaim by holding this lock | ||
2756 | * here. | ||
2752 | * | 2757 | * |
2753 | * However, we still need to issue the unpin wakeup | 2758 | * However, we still need to issue the unpin wakeup call as the |
2754 | * call as the inode reclaim may be blocked waiting for | 2759 | * inode reclaim may be blocked waiting for the inode to become |
2755 | * the inode to become unpinned. | 2760 | * unpinned. |
2756 | */ | 2761 | */ |
2757 | struct inode *inode = NULL; | ||
2758 | 2762 | ||
2759 | spin_lock(&ip->i_flags_lock); | ||
2760 | if (!__xfs_iflags_test(ip, XFS_IRECLAIM|XFS_IRECLAIMABLE)) { | 2763 | if (!__xfs_iflags_test(ip, XFS_IRECLAIM|XFS_IRECLAIMABLE)) { |
2761 | bhv_vnode_t *vp = XFS_ITOV_NULL(ip); | 2764 | bhv_vnode_t *vp = XFS_ITOV_NULL(ip); |
2765 | struct inode *inode = NULL; | ||
2766 | |||
2767 | BUG_ON(vp == NULL); | ||
2768 | inode = vn_to_inode(vp); | ||
2769 | BUG_ON(inode->i_state & I_CLEAR); | ||
2762 | 2770 | ||
2763 | /* make sync come back and flush this inode */ | 2771 | /* make sync come back and flush this inode */ |
2764 | if (vp) { | 2772 | if (!(inode->i_state & (I_NEW|I_FREEING))) |
2765 | inode = vn_to_inode(vp); | 2773 | mark_inode_dirty_sync(inode); |
2766 | |||
2767 | if (!(inode->i_state & | ||
2768 | (I_NEW|I_FREEING|I_CLEAR))) { | ||
2769 | inode = igrab(inode); | ||
2770 | if (inode) | ||
2771 | mark_inode_dirty_sync(inode); | ||
2772 | } else | ||
2773 | inode = NULL; | ||
2774 | } | ||
2775 | } | 2774 | } |
2776 | spin_unlock(&ip->i_flags_lock); | 2775 | spin_unlock(&ip->i_flags_lock); |
2777 | wake_up(&ip->i_ipin_wait); | 2776 | wake_up(&ip->i_ipin_wait); |
2778 | if (inode) | ||
2779 | iput(inode); | ||
2780 | } | 2777 | } |
2781 | } | 2778 | } |
2782 | 2779 | ||