aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_iget.c
diff options
context:
space:
mode:
authorDavid Chinner <david@fromorbit.com>2008-10-30 02:36:14 -0400
committerLachlan McIlroy <lachlan@sgi.com>2008-10-30 02:36:14 -0400
commitbf904248a2adb3f3be4eb4fb1837ce3bb28cca76 (patch)
tree288306924f640f19d881166a3b50fa59b6e9e7e7 /fs/xfs/xfs_iget.c
parent8290c35f87304a6b73d4fd17b03580b4f7425de8 (diff)
[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 @@
44 */ 44 */
45static int 45static int
46xfs_iget_cache_hit( 46xfs_iget_cache_hit(
47 struct inode *inode,
48 struct xfs_perag *pag, 47 struct xfs_perag *pag,
49 struct xfs_inode *ip, 48 struct xfs_inode *ip,
50 int flags, 49 int flags,
51 int lock_flags) __releases(pag->pag_ici_lock) 50 int lock_flags) __releases(pag->pag_ici_lock)
52{ 51{
53 struct xfs_mount *mp = ip->i_mount; 52 struct xfs_mount *mp = ip->i_mount;
54 struct inode *old_inode;
55 int error = 0; 53 int error = 0;
56 54
57 /* 55 /*
58 * If INEW is set this inode is being set up 56 * If INEW is set this inode is being set up
57 * If IRECLAIM is set this inode is being torn down
59 * Pause and try again. 58 * Pause and try again.
60 */ 59 */
61 if (xfs_iflags_test(ip, XFS_INEW)) { 60 if (xfs_iflags_test(ip, (XFS_INEW|XFS_IRECLAIM))) {
62 error = EAGAIN; 61 error = EAGAIN;
63 XFS_STATS_INC(xs_ig_frecycle); 62 XFS_STATS_INC(xs_ig_frecycle);
64 goto out_error; 63 goto out_error;
65 } 64 }
66 65
67 old_inode = ip->i_vnode; 66 /* If IRECLAIMABLE is set, we've torn down the vfs inode part */
68 if (old_inode == NULL) { 67 if (xfs_iflags_test(ip, XFS_IRECLAIMABLE)) {
68
69 /* 69 /*
70 * If IRECLAIM is set this inode is 70 * If lookup is racing with unlink, then we should return an
71 * on its way out of the system, 71 * error immediately so we don't remove it from the reclaim
72 * we need to pause and try again. 72 * list and potentially leak the inode.
73 */ 73 */
74 if (xfs_iflags_test(ip, XFS_IRECLAIM)) { 74
75 error = EAGAIN; 75 if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {
76 XFS_STATS_INC(xs_ig_frecycle); 76 error = ENOENT;
77 goto out_error; 77 goto out_error;
78 } 78 }
79 ASSERT(xfs_iflags_test(ip, XFS_IRECLAIMABLE)); 79
80 xfs_itrace_exit_tag(ip, "xfs_iget.alloc");
80 81
81 /* 82 /*
82 * If lookup is racing with unlink, then we 83 * We need to re-initialise the VFS inode as it has been
83 * should return an error immediately so we 84 * 'freed' by the VFS. Do this here so we can deal with
84 * don't remove it from the reclaim list and 85 * errors cleanly, then tag it so it can be set up correctly
85 * potentially leak the inode. 86 * later.
86 */ 87 */
87 if ((ip->i_d.di_mode == 0) && 88 if (!inode_init_always(mp->m_super, VFS_I(ip))) {
88 !(flags & XFS_IGET_CREATE)) { 89 error = ENOMEM;
89 error = ENOENT;
90 goto out_error; 90 goto out_error;
91 } 91 }
92 xfs_itrace_exit_tag(ip, "xfs_iget.alloc"); 92 xfs_iflags_set(ip, XFS_INEW);
93
94 xfs_iflags_clear(ip, XFS_IRECLAIMABLE); 93 xfs_iflags_clear(ip, XFS_IRECLAIMABLE);
95 read_unlock(&pag->pag_ici_lock); 94 read_unlock(&pag->pag_ici_lock);
96 95
97 XFS_MOUNT_ILOCK(mp); 96 XFS_MOUNT_ILOCK(mp);
98 list_del_init(&ip->i_reclaim); 97 list_del_init(&ip->i_reclaim);
99 XFS_MOUNT_IUNLOCK(mp); 98 XFS_MOUNT_IUNLOCK(mp);
100 99 } else if (!igrab(VFS_I(ip))) {
101 } else if (inode != old_inode) { 100 /* If the VFS inode is being torn down, pause and try again. */
102 /* The inode is being torn down, pause and 101 error = EAGAIN;
103 * try again. 102 XFS_STATS_INC(xs_ig_frecycle);
104 */ 103 goto out_error;
105 if (old_inode->i_state & (I_FREEING | I_CLEAR)) {
106 error = EAGAIN;
107 XFS_STATS_INC(xs_ig_frecycle);
108 goto out_error;
109 }
110/* Chances are the other vnode (the one in the inode) is being torn
111* down right now, and we landed on top of it. Question is, what do
112* we do? Unhook the old inode and hook up the new one?
113*/
114 cmn_err(CE_PANIC,
115 "xfs_iget_core: ambiguous vns: vp/0x%p, invp/0x%p",
116 old_inode, inode);
117 } else { 104 } else {
105 /* we've got a live one */
118 read_unlock(&pag->pag_ici_lock); 106 read_unlock(&pag->pag_ici_lock);
119 } 107 }
120 108
@@ -215,11 +203,11 @@ out_destroy:
215/* 203/*
216 * Look up an inode by number in the given file system. 204 * Look up an inode by number in the given file system.
217 * The inode is looked up in the cache held in each AG. 205 * The inode is looked up in the cache held in each AG.
218 * If the inode is found in the cache, attach it to the provided 206 * If the inode is found in the cache, initialise the vfs inode
219 * vnode. 207 * if necessary.
220 * 208 *
221 * If it is not in core, read it in from the file system's device, 209 * If it is not in core, read it in from the file system's device,
222 * add it to the cache and attach the provided vnode. 210 * add it to the cache and initialise the vfs inode.
223 * 211 *
224 * The inode is locked according to the value of the lock_flags parameter. 212 * The inode is locked according to the value of the lock_flags parameter.
225 * This flag parameter indicates how and if the inode's IO lock and inode lock 213 * This flag parameter indicates how and if the inode's IO lock and inode lock
@@ -236,9 +224,8 @@ out_destroy:
236 * bno -- the block number starting the buffer containing the inode, 224 * bno -- the block number starting the buffer containing the inode,
237 * if known (as by bulkstat), else 0. 225 * if known (as by bulkstat), else 0.
238 */ 226 */
239STATIC int 227int
240xfs_iget_core( 228xfs_iget(
241 struct inode *inode,
242 xfs_mount_t *mp, 229 xfs_mount_t *mp,
243 xfs_trans_t *tp, 230 xfs_trans_t *tp,
244 xfs_ino_t ino, 231 xfs_ino_t ino,
@@ -269,7 +256,7 @@ again:
269 ip = radix_tree_lookup(&pag->pag_ici_root, agino); 256 ip = radix_tree_lookup(&pag->pag_ici_root, agino);
270 257
271 if (ip) { 258 if (ip) {
272 error = xfs_iget_cache_hit(inode, pag, ip, flags, lock_flags); 259 error = xfs_iget_cache_hit(pag, ip, flags, lock_flags);
273 if (error) 260 if (error)
274 goto out_error_or_again; 261 goto out_error_or_again;
275 } else { 262 } else {
@@ -283,23 +270,16 @@ again:
283 } 270 }
284 xfs_put_perag(mp, pag); 271 xfs_put_perag(mp, pag);
285 272
286 ASSERT(ip->i_df.if_ext_max ==
287 XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));
288
289 xfs_iflags_set(ip, XFS_IMODIFIED); 273 xfs_iflags_set(ip, XFS_IMODIFIED);
290 *ipp = ip; 274 *ipp = ip;
291 275
292 /* 276 ASSERT(ip->i_df.if_ext_max ==
293 * Set up the Linux with the Linux inode. 277 XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));
294 */
295 ip->i_vnode = inode;
296 inode->i_private = ip;
297
298 /* 278 /*
299 * If we have a real type for an on-disk inode, we can set ops(&unlock) 279 * If we have a real type for an on-disk inode, we can set ops(&unlock)
300 * now. If it's a new inode being created, xfs_ialloc will handle it. 280 * now. If it's a new inode being created, xfs_ialloc will handle it.
301 */ 281 */
302 if (ip->i_d.di_mode != 0) 282 if (xfs_iflags_test(ip, XFS_INEW) && ip->i_d.di_mode != 0)
303 xfs_setup_inode(ip); 283 xfs_setup_inode(ip);
304 return 0; 284 return 0;
305 285
@@ -314,75 +294,6 @@ out_error_or_again:
314 294
315 295
316/* 296/*
317 * The 'normal' internal xfs_iget, if needed it will
318 * 'allocate', or 'get', the vnode.
319 */
320int
321xfs_iget(
322 xfs_mount_t *mp,
323 xfs_trans_t *tp,
324 xfs_ino_t ino,
325 uint flags,
326 uint lock_flags,
327 xfs_inode_t **ipp,
328 xfs_daddr_t bno)
329{
330 struct inode *inode;
331 xfs_inode_t *ip;
332 int error;
333
334 XFS_STATS_INC(xs_ig_attempts);
335
336retry:
337 inode = iget_locked(mp->m_super, ino);
338 if (!inode)
339 /* If we got no inode we are out of memory */
340 return ENOMEM;
341
342 if (inode->i_state & I_NEW) {
343 XFS_STATS_INC(vn_active);
344 XFS_STATS_INC(vn_alloc);
345
346 error = xfs_iget_core(inode, mp, tp, ino, flags,
347 lock_flags, ipp, bno);
348 if (error) {
349 make_bad_inode(inode);
350 if (inode->i_state & I_NEW)
351 unlock_new_inode(inode);
352 iput(inode);
353 }
354 return error;
355 }
356
357 /*
358 * If the inode is not fully constructed due to
359 * filehandle mismatches wait for the inode to go
360 * away and try again.
361 *
362 * iget_locked will call __wait_on_freeing_inode
363 * to wait for the inode to go away.
364 */
365 if (is_bad_inode(inode)) {
366 iput(inode);
367 delay(1);
368 goto retry;
369 }
370
371 ip = XFS_I(inode);
372 if (!ip) {
373 iput(inode);
374 delay(1);
375 goto retry;
376 }
377
378 if (lock_flags != 0)
379 xfs_ilock(ip, lock_flags);
380 XFS_STATS_INC(xs_ig_found);
381 *ipp = ip;
382 return 0;
383}
384
385/*
386 * Look for the inode corresponding to the given ino in the hash table. 297 * Look for the inode corresponding to the given ino in the hash table.
387 * If it is there and its i_transp pointer matches tp, return it. 298 * If it is there and its i_transp pointer matches tp, return it.
388 * Otherwise, return NULL. 299 * Otherwise, return NULL.
@@ -482,14 +393,6 @@ xfs_ireclaim(xfs_inode_t *ip)
482 XFS_QM_DQDETACH(ip->i_mount, ip); 393 XFS_QM_DQDETACH(ip->i_mount, ip);
483 394
484 /* 395 /*
485 * Pull our behavior descriptor from the vnode chain.
486 */
487 if (ip->i_vnode) {
488 ip->i_vnode->i_private = NULL;
489 ip->i_vnode = NULL;
490 }
491
492 /*
493 * Free all memory associated with the inode. 396 * Free all memory associated with the inode.
494 */ 397 */
495 xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); 398 xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);