diff options
Diffstat (limited to 'fs/xfs/xfs_iget.c')
-rw-r--r-- | fs/xfs/xfs_iget.c | 51 |
1 files changed, 37 insertions, 14 deletions
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index b73d216ecaf..c1c89dac19c 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -215,7 +215,7 @@ again: * If INEW is set this inode is being set up * we need to pause and try again. */ - if (ip->i_flags & XFS_INEW) { + if (xfs_iflags_test(ip, XFS_INEW)) { read_unlock(&ih->ih_lock); delay(1); XFS_STATS_INC(xs_ig_frecycle); @@ -230,22 +230,50 @@ again: * on its way out of the system, * we need to pause and try again. */ - if (ip->i_flags & XFS_IRECLAIM) { + if (xfs_iflags_test(ip, XFS_IRECLAIM)) { read_unlock(&ih->ih_lock); delay(1); XFS_STATS_INC(xs_ig_frecycle); 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); XFS_STATS_INC(xs_ig_found); - spin_lock(&ip->i_flags_lock); - ip->i_flags &= ~XFS_IRECLAIMABLE; - spin_unlock(&ip->i_flags_lock); + xfs_iflags_clear(ip, XFS_IRECLAIMABLE); version = ih->ih_version; read_unlock(&ih->ih_lock); xfs_ihash_promote(ih, ip, version); @@ -299,10 +327,7 @@ finish_inode: if (lock_flags != 0) xfs_ilock(ip, lock_flags); - spin_lock(&ip->i_flags_lock); - ip->i_flags &= ~XFS_ISTALE; - spin_unlock(&ip->i_flags_lock); - + xfs_iflags_clear(ip, XFS_ISTALE); vn_trace_exit(vp, "xfs_iget.found", (inst_t *)__return_address); goto return_ip; @@ -371,10 +396,7 @@ finish_inode: ih->ih_next = ip; ip->i_udquot = ip->i_gdquot = NULL; ih->ih_version++; - spin_lock(&ip->i_flags_lock); - ip->i_flags |= XFS_INEW; - spin_unlock(&ip->i_flags_lock); - + xfs_iflags_set(ip, XFS_INEW); write_unlock(&ih->ih_lock); /* @@ -625,7 +647,7 @@ xfs_iput_new(xfs_inode_t *ip, vn_trace_entry(vp, "xfs_iput_new", (inst_t *)__return_address); if ((ip->i_d.di_mode == 0)) { - ASSERT(!(ip->i_flags & XFS_IRECLAIMABLE)); + ASSERT(!xfs_iflags_test(ip, XFS_IRECLAIMABLE)); vn_mark_bad(vp); } if (inode->i_state & I_NEW) @@ -683,6 +705,7 @@ xfs_ireclaim(xfs_inode_t *ip) /* * Free all memory associated with the inode. */ + xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_idestroy(ip); } |