diff options
Diffstat (limited to 'fs/xfs/xfs_iget.c')
-rw-r--r-- | fs/xfs/xfs_iget.c | 167 |
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 | */ |
45 | static int | 45 | static int |
46 | xfs_iget_cache_hit( | 46 | xfs_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 | */ |
239 | STATIC int | 227 | int |
240 | xfs_iget_core( | 228 | xfs_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 | */ | ||
320 | int | ||
321 | xfs_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 | |||
336 | retry: | ||
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); |