summaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_iget.c
diff options
context:
space:
mode:
authorDavid Chinner <david@fromorbit.com>2008-10-30 17:36:14 +1100
committerLachlan McIlroy <lachlan@sgi.com>2008-10-30 17:36:14 +1100
commitbf904248a2adb3f3be4eb4fb1837ce3bb28cca76 (patch)
tree288306924f640f19d881166a3b50fa59b6e9e7e7 /fs/xfs/xfs_iget.c
parent8290c35f87304a6b73d4fd17b03580b4f7425de8 (diff)
downloadlinux-bf904248a2adb3f3be4eb4fb1837ce3bb28cca76.tar.bz2
[XFS] Combine the XFS and Linux inodes
To avoid issues with different lifecycles of XFS and Linux inodes, embedd the linux inode inside the XFS inode. This means that the linux inode has the same lifecycle as the XFS inode, even when it has been released by the OS. XFS inodes don't live much longer than this (a short stint in reclaim at most), so there isn't significant memory usage penalties here. Version 3 o kill xfs_icount() Version 2 o remove unused commented out code from xfs_iget(). o kill useless cast in VFS_I() SGI-PV: 988141 SGI-Modid: xfs-linux-melb:xfs-kern:32323a Signed-off-by: David Chinner <david@fromorbit.com> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com> Signed-off-by: Christoph Hellwig <hch@infradead.org>
Diffstat (limited to 'fs/xfs/xfs_iget.c')
-rw-r--r--fs/xfs/xfs_iget.c167
1 files changed, 35 insertions, 132 deletions
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index b2539b17c954..c4414e8bce8d 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -44,77 +44,65 @@
*/
static int
xfs_iget_cache_hit(
- struct inode *inode,
struct xfs_perag *pag,
struct xfs_inode *ip,
int flags,
int lock_flags) __releases(pag->pag_ici_lock)
{
struct xfs_mount *mp = ip->i_mount;
- struct inode *old_inode;
int error = 0;
/*
* If INEW is set this inode is being set up
+ * If IRECLAIM is set this inode is being torn down
* Pause and try again.
*/
- if (xfs_iflags_test(ip, XFS_INEW)) {
+ if (xfs_iflags_test(ip, (XFS_INEW|XFS_IRECLAIM))) {
error = EAGAIN;
XFS_STATS_INC(xs_ig_frecycle);
goto out_error;
}
- old_inode = ip->i_vnode;
- if (old_inode == NULL) {
+ /* If IRECLAIMABLE is set, we've torn down the vfs inode part */
+ if (xfs_iflags_test(ip, XFS_IRECLAIMABLE)) {
+
/*
- * If IRECLAIM is set this inode is
- * on its way out of the system,
- * we need to pause and try again.
+ * 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 (xfs_iflags_test(ip, XFS_IRECLAIM)) {
- error = EAGAIN;
- XFS_STATS_INC(xs_ig_frecycle);
+
+ if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {
+ error = ENOENT;
goto out_error;
}
- ASSERT(xfs_iflags_test(ip, XFS_IRECLAIMABLE));
+
+ xfs_itrace_exit_tag(ip, "xfs_iget.alloc");
/*
- * 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.
+ * We need to re-initialise the VFS inode as it has been
+ * 'freed' by the VFS. Do this here so we can deal with
+ * errors cleanly, then tag it so it can be set up correctly
+ * later.
*/
- if ((ip->i_d.di_mode == 0) &&
- !(flags & XFS_IGET_CREATE)) {
- error = ENOENT;
+ if (!inode_init_always(mp->m_super, VFS_I(ip))) {
+ error = ENOMEM;
goto out_error;
}
- xfs_itrace_exit_tag(ip, "xfs_iget.alloc");
-
+ xfs_iflags_set(ip, XFS_INEW);
xfs_iflags_clear(ip, XFS_IRECLAIMABLE);
read_unlock(&pag->pag_ici_lock);
XFS_MOUNT_ILOCK(mp);
list_del_init(&ip->i_reclaim);
XFS_MOUNT_IUNLOCK(mp);
-
- } else if (inode != old_inode) {
- /* The inode is being torn down, pause and
- * try again.
- */
- if (old_inode->i_state & (I_FREEING | I_CLEAR)) {
- error = EAGAIN;
- XFS_STATS_INC(xs_ig_frecycle);
- goto out_error;
- }
-/* Chances are the other vnode (the one in the inode) is being torn
-* down right now, and we landed on top of it. Question is, what do
-* we do? Unhook the old inode and hook up the new one?
-*/
- cmn_err(CE_PANIC,
- "xfs_iget_core: ambiguous vns: vp/0x%p, invp/0x%p",
- old_inode, inode);
+ } else if (!igrab(VFS_I(ip))) {
+ /* If the VFS inode is being torn down, pause and try again. */
+ error = EAGAIN;
+ XFS_STATS_INC(xs_ig_frecycle);
+ goto out_error;
} else {
+ /* we've got a live one */
read_unlock(&pag->pag_ici_lock);
}
@@ -215,11 +203,11 @@ out_destroy:
/*
* Look up an inode by number in the given file system.
* The inode is looked up in the cache held in each AG.
- * If the inode is found in the cache, attach it to the provided
- * vnode.
+ * If the inode is found in the cache, initialise the vfs inode
+ * if necessary.
*
* If it is not in core, read it in from the file system's device,
- * add it to the cache and attach the provided vnode.
+ * add it to the cache and initialise the vfs inode.
*
* The inode is locked according to the value of the lock_flags parameter.
* This flag parameter indicates how and if the inode's IO lock and inode lock
@@ -236,9 +224,8 @@ out_destroy:
* bno -- the block number starting the buffer containing the inode,
* if known (as by bulkstat), else 0.
*/
-STATIC int
-xfs_iget_core(
- struct inode *inode,
+int
+xfs_iget(
xfs_mount_t *mp,
xfs_trans_t *tp,
xfs_ino_t ino,
@@ -269,7 +256,7 @@ again:
ip = radix_tree_lookup(&pag->pag_ici_root, agino);
if (ip) {
- error = xfs_iget_cache_hit(inode, pag, ip, flags, lock_flags);
+ error = xfs_iget_cache_hit(pag, ip, flags, lock_flags);
if (error)
goto out_error_or_again;
} else {
@@ -283,23 +270,16 @@ again:
}
xfs_put_perag(mp, pag);
- ASSERT(ip->i_df.if_ext_max ==
- XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));
-
xfs_iflags_set(ip, XFS_IMODIFIED);
*ipp = ip;
- /*
- * Set up the Linux with the Linux inode.
- */
- ip->i_vnode = inode;
- inode->i_private = ip;
-
+ ASSERT(ip->i_df.if_ext_max ==
+ XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));
/*
* If we have a real type for an on-disk inode, we can set ops(&unlock)
* now. If it's a new inode being created, xfs_ialloc will handle it.
*/
- if (ip->i_d.di_mode != 0)
+ if (xfs_iflags_test(ip, XFS_INEW) && ip->i_d.di_mode != 0)
xfs_setup_inode(ip);
return 0;
@@ -314,75 +294,6 @@ out_error_or_again:
/*
- * The 'normal' internal xfs_iget, if needed it will
- * 'allocate', or 'get', the vnode.
- */
-int
-xfs_iget(
- xfs_mount_t *mp,
- xfs_trans_t *tp,
- xfs_ino_t ino,
- uint flags,
- uint lock_flags,
- xfs_inode_t **ipp,
- xfs_daddr_t bno)
-{
- struct inode *inode;
- xfs_inode_t *ip;
- int error;
-
- XFS_STATS_INC(xs_ig_attempts);
-
-retry:
- inode = iget_locked(mp->m_super, ino);
- if (!inode)
- /* If we got no inode we are out of memory */
- return ENOMEM;
-
- if (inode->i_state & I_NEW) {
- XFS_STATS_INC(vn_active);
- XFS_STATS_INC(vn_alloc);
-
- error = xfs_iget_core(inode, mp, tp, ino, flags,
- lock_flags, ipp, bno);
- if (error) {
- make_bad_inode(inode);
- if (inode->i_state & I_NEW)
- unlock_new_inode(inode);
- iput(inode);
- }
- return error;
- }
-
- /*
- * If the inode is not fully constructed due to
- * filehandle mismatches wait for the inode to go
- * away and try again.
- *
- * iget_locked will call __wait_on_freeing_inode
- * to wait for the inode to go away.
- */
- if (is_bad_inode(inode)) {
- iput(inode);
- delay(1);
- goto retry;
- }
-
- ip = XFS_I(inode);
- if (!ip) {
- iput(inode);
- delay(1);
- goto retry;
- }
-
- if (lock_flags != 0)
- xfs_ilock(ip, lock_flags);
- XFS_STATS_INC(xs_ig_found);
- *ipp = ip;
- return 0;
-}
-
-/*
* Look for the inode corresponding to the given ino in the hash table.
* If it is there and its i_transp pointer matches tp, return it.
* Otherwise, return NULL.
@@ -482,14 +393,6 @@ xfs_ireclaim(xfs_inode_t *ip)
XFS_QM_DQDETACH(ip->i_mount, ip);
/*
- * Pull our behavior descriptor from the vnode chain.
- */
- if (ip->i_vnode) {
- ip->i_vnode->i_private = NULL;
- ip->i_vnode = NULL;
- }
-
- /*
* Free all memory associated with the inode.
*/
xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);