Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 40869
b: refs/heads/master
c: 4c60658
h: refs/heads/master
i:
  40867: e1a80b8
v: v3
  • Loading branch information
David Chinner authored and Tim Shimmin committed Nov 11, 2006
1 parent 867815f commit 93b4718
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 33 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7a18c386078eaf17ae54595f66c0d64d9c1cb29c
refs/heads/master: 4c60658e0f4e253cf275f12b7c76bf128515a774
30 changes: 30 additions & 0 deletions trunk/fs/xfs/xfs_iget.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,36 @@ xfs_iget_core(

goto again;
}
ASSERT(xfs_iflags_test(ip, XFS_IRECLAIMABLE));

/*
* If lookup is racing with unlink, then we
* should return an error immediately so we
* don't remove it from the reclaim list and
* potentially leak the inode.
*/
if ((ip->i_d.di_mode == 0) &&
!(flags & XFS_IGET_CREATE)) {
read_unlock(&ih->ih_lock);
return ENOENT;
}

/*
* There may be transactions sitting in the
* incore log buffers or being flushed to disk
* at this time. We can't clear the
* XFS_IRECLAIMABLE flag until these
* transactions have hit the disk, otherwise we
* will void the guarantee the flag provides
* xfs_iunpin()
*/
if (xfs_ipincount(ip)) {
read_unlock(&ih->ih_lock);
xfs_log_force(mp, 0,
XFS_LOG_FORCE|XFS_LOG_SYNC);
XFS_STATS_INC(xs_ig_frecycle);
goto again;
}

vn_trace_exit(vp, "xfs_iget.alloc",
(inst_t *)__return_address);
Expand Down
47 changes: 22 additions & 25 deletions trunk/fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2741,42 +2741,39 @@ xfs_iunpin(
{
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
* linux inode _and_ the xfs vnode may have been
* freed so we cannot reference either of them safely.
* Hence we should not try to do anything to them
* if the xfs inode is currently in the reclaim
* path.
* If the inode is currently being reclaimed, the link between
* the bhv_vnode and the xfs_inode will be broken after the
* XFS_IRECLAIM* flag is set. Hence, if these flags are not
* set, then we can move forward and mark the linux inode dirty
* knowing that it is still valid as it won't freed until after
* 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
* call as the inode reclaim may be blocked waiting for
* the inode to become unpinned.
* However, we still need to issue the unpin wakeup call as the
* inode reclaim may be blocked waiting for the inode to become
* unpinned.
*/
struct inode *inode = NULL;

spin_lock(&ip->i_flags_lock);
if (!__xfs_iflags_test(ip, XFS_IRECLAIM|XFS_IRECLAIMABLE)) {
bhv_vnode_t *vp = XFS_ITOV_NULL(ip);
struct inode *inode = NULL;

BUG_ON(vp == NULL);
inode = vn_to_inode(vp);
BUG_ON(inode->i_state & I_CLEAR);

/* make sync come back and flush this inode */
if (vp) {
inode = vn_to_inode(vp);

if (!(inode->i_state &
(I_NEW|I_FREEING|I_CLEAR))) {
inode = igrab(inode);
if (inode)
mark_inode_dirty_sync(inode);
} else
inode = NULL;
}
if (!(inode->i_state & (I_NEW|I_FREEING)))
mark_inode_dirty_sync(inode);
}
spin_unlock(&ip->i_flags_lock);
wake_up(&ip->i_ipin_wait);
if (inode)
iput(inode);
}
}

Expand Down
21 changes: 14 additions & 7 deletions trunk/fs/xfs/xfs_vnodeops.c
Original file line number Diff line number Diff line change
Expand Up @@ -3827,11 +3827,16 @@ xfs_reclaim(
*/
xfs_synchronize_atime(ip);

/* If we have nothing to flush with this inode then complete the
* teardown now, otherwise break the link between the xfs inode
* and the linux inode and clean up the xfs inode later. This
* avoids flushing the inode to disk during the delete operation
* itself.
/*
* If we have nothing to flush with this inode then complete the
* teardown now, otherwise break the link between the xfs inode and the
* linux inode and clean up the xfs inode later. This avoids flushing
* the inode to disk during the delete operation itself.
*
* When breaking the link, we need to set the XFS_IRECLAIMABLE flag
* first to ensure that xfs_iunpin() will never see an xfs inode
* that has a linux inode being reclaimed. Synchronisation is provided
* by the i_flags_lock.
*/
if (!ip->i_update_core && (ip->i_itemp == NULL)) {
xfs_ilock(ip, XFS_ILOCK_EXCL);
Expand All @@ -3840,11 +3845,13 @@ xfs_reclaim(
} else {
xfs_mount_t *mp = ip->i_mount;

/* Protect sync from us */
/* Protect sync and unpin from us */
XFS_MOUNT_ILOCK(mp);
spin_lock(&ip->i_flags_lock);
__xfs_iflags_set(ip, XFS_IRECLAIMABLE);
vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip));
spin_unlock(&ip->i_flags_lock);
list_add_tail(&ip->i_reclaim, &mp->m_del_inodes);
xfs_iflags_set(ip, XFS_IRECLAIMABLE);
XFS_MOUNT_IUNLOCK(mp);
}
return 0;
Expand Down

0 comments on commit 93b4718

Please sign in to comment.