|
|
| version 1.453, 2006/11/07 14:39:38 | version 1.454, 2006/11/07 14:40:26 |
|---|---|
| Line 2741 xfs_iunpin( | Line 2741 xfs_iunpin( |
| { | { |
| ASSERT(atomic_read(&ip->i_pincount) > 0); | ASSERT(atomic_read(&ip->i_pincount) > 0); |
| if (atomic_dec_and_test(&ip->i_pincount)) { | if (atomic_dec_and_lock(&ip->i_pincount, &ip->i_flags_lock)) { |
| /* | /* |
| * If the inode is currently being reclaimed, the | * If the inode is currently being reclaimed, the link between |
| * linux inode _and_ the xfs vnode may have been | * the bhv_vnode and the xfs_inode will be broken after the |
| * freed so we cannot reference either of them safely. | * XFS_IRECLAIM* flag is set. Hence, if these flags are not |
| * Hence we should not try to do anything to them | * set, then we can move forward and mark the linux inode dirty |
| * if the xfs inode is currently in the reclaim | * knowing that it is still valid as it won't freed until after |
| * path. | * the bhv_vnode<->xfs_inode link is broken in xfs_reclaim. The |
| * i_flags_lock is used to synchronise the setting of the | |
| * XFS_IRECLAIM* flags and the breaking of the link, and so we | |
| * can execute atomically w.r.t to reclaim by holding this lock | |
| * here. | |
| * | * |
| * However, we still need to issue the unpin wakeup | * However, we still need to issue the unpin wakeup call as the |
| * call as the inode reclaim may be blocked waiting for | * inode reclaim may be blocked waiting for the inode to become |
| * the inode to become unpinned. | * unpinned. |
| */ | */ |
| struct inode *inode = NULL; | |
| spin_lock(&ip->i_flags_lock); | |
| if (!__xfs_iflags_test(ip, XFS_IRECLAIM|XFS_IRECLAIMABLE)) { | if (!__xfs_iflags_test(ip, XFS_IRECLAIM|XFS_IRECLAIMABLE)) { |
| bhv_vnode_t *vp = XFS_ITOV_NULL(ip); | bhv_vnode_t *vp = XFS_ITOV_NULL(ip); |
| struct inode *inode = NULL; | |
| /* make sync come back and flush this inode */ | BUG_ON(vp == NULL); |
| if (vp) { | inode = vn_to_inode(vp); |
| inode = vn_to_inode(vp); | BUG_ON(inode->i_state & I_CLEAR); |
| if (!(inode->i_state & | /* make sync come back and flush this inode */ |
| (I_NEW|I_FREEING|I_CLEAR))) { | if (!(inode->i_state & (I_NEW|I_FREEING))) |
| inode = igrab(inode); | mark_inode_dirty_sync(inode); |
| if (inode) | |
| mark_inode_dirty_sync(inode); | |
| } else | |
| inode = NULL; | |
| } | |
| } | } |
| spin_unlock(&ip->i_flags_lock); | spin_unlock(&ip->i_flags_lock); |
| wake_up(&ip->i_ipin_wait); | wake_up(&ip->i_ipin_wait); |
| if (inode) | |
| iput(inode); | |
| } | } |
| } | } |