diff options
author | Christoph Hellwig <hch@lst.de> | 2008-12-03 06:20:25 -0500 |
---|---|---|
committer | Niv Sardi <xaiki@sgi.com> | 2008-12-03 23:39:20 -0500 |
commit | 5cafdeb2891a415a5dbf0ad80f0afedf8369e6bb (patch) | |
tree | f1d6653c4dee098e46f4bdc4ddda60cf4a6d35fd | |
parent | ccd0be6cfc6943c4e0b3e3cdb598e0b7354a2d78 (diff) |
cleanup the inode reclaim path
Merge xfs_iextract and xfs_idestroy into xfs_ireclaim as they are never
called individually. Also rewrite most comments in this area as they
were severly out of date.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <david@fromorbit.com>
Signed-off-by: Niv Sardi <xaiki@sgi.com>
-rw-r--r-- | fs/xfs/xfs_iget.c | 128 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.c | 72 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 1 |
4 files changed, 86 insertions, 117 deletions
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 27ec2417b852..f58e5e000fce 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c | |||
@@ -450,65 +450,109 @@ xfs_iput_new( | |||
450 | IRELE(ip); | 450 | IRELE(ip); |
451 | } | 451 | } |
452 | 452 | ||
453 | |||
454 | /* | 453 | /* |
455 | * This routine embodies the part of the reclaim code that pulls | 454 | * This is called free all the memory associated with an inode. |
456 | * the inode from the inode hash table and the mount structure's | 455 | * It must free the inode itself and any buffers allocated for |
457 | * inode list. | 456 | * if_extents/if_data and if_broot. It must also free the lock |
458 | * This should only be called from xfs_reclaim(). | 457 | * associated with the inode. |
458 | * | ||
459 | * Note: because we don't initialise everything on reallocation out | ||
460 | * of the zone, we must ensure we nullify everything correctly before | ||
461 | * freeing the structure. | ||
459 | */ | 462 | */ |
460 | void | 463 | void |
461 | xfs_ireclaim(xfs_inode_t *ip) | 464 | xfs_ireclaim( |
465 | struct xfs_inode *ip) | ||
462 | { | 466 | { |
463 | /* | 467 | struct xfs_mount *mp = ip->i_mount; |
464 | * Remove from old hash list and mount list. | 468 | struct xfs_perag *pag; |
465 | */ | ||
466 | XFS_STATS_INC(xs_ig_reclaims); | ||
467 | 469 | ||
468 | xfs_iextract(ip); | 470 | XFS_STATS_INC(xs_ig_reclaims); |
469 | 471 | ||
470 | /* | 472 | /* |
471 | * Here we do a spurious inode lock in order to coordinate with inode | 473 | * Remove the inode from the per-AG radix tree. It doesn't matter |
472 | * cache radix tree lookups. This is because the lookup can reference | 474 | * if it was never added to it because radix_tree_delete can deal |
473 | * the inodes in the cache without taking references. We make that OK | 475 | * with that case just fine. |
474 | * here by ensuring that we wait until the inode is unlocked after the | ||
475 | * lookup before we go ahead and free it. We get both the ilock and | ||
476 | * the iolock because the code may need to drop the ilock one but will | ||
477 | * still hold the iolock. | ||
478 | */ | 476 | */ |
479 | xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | 477 | pag = xfs_get_perag(mp, ip->i_ino); |
478 | write_lock(&pag->pag_ici_lock); | ||
479 | radix_tree_delete(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, ip->i_ino)); | ||
480 | write_unlock(&pag->pag_ici_lock); | ||
481 | xfs_put_perag(mp, pag); | ||
480 | 482 | ||
481 | /* | 483 | /* |
482 | * Release dquots (and their references) if any. An inode may escape | 484 | * Here we do an (almost) spurious inode lock in order to coordinate |
483 | * xfs_inactive and get here via vn_alloc->vn_reclaim path. | 485 | * with inode cache radix tree lookups. This is because the lookup |
486 | * can reference the inodes in the cache without taking references. | ||
487 | * | ||
488 | * We make that OK here by ensuring that we wait until the inode is | ||
489 | * unlocked after the lookup before we go ahead and free it. We get | ||
490 | * both the ilock and the iolock because the code may need to drop the | ||
491 | * ilock one but will still hold the iolock. | ||
484 | */ | 492 | */ |
485 | XFS_QM_DQDETACH(ip->i_mount, ip); | 493 | xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); |
486 | |||
487 | /* | 494 | /* |
488 | * Free all memory associated with the inode. | 495 | * Release dquots (and their references) if any. |
489 | */ | 496 | */ |
497 | XFS_QM_DQDETACH(ip->i_mount, ip); | ||
490 | xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | 498 | xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); |
491 | xfs_idestroy(ip); | ||
492 | } | ||
493 | 499 | ||
494 | /* | 500 | switch (ip->i_d.di_mode & S_IFMT) { |
495 | * This routine removes an about-to-be-destroyed inode from | 501 | case S_IFREG: |
496 | * all of the lists in which it is located with the exception | 502 | case S_IFDIR: |
497 | * of the behavior chain. | 503 | case S_IFLNK: |
498 | */ | 504 | xfs_idestroy_fork(ip, XFS_DATA_FORK); |
499 | void | 505 | break; |
500 | xfs_iextract( | 506 | } |
501 | xfs_inode_t *ip) | ||
502 | { | ||
503 | xfs_mount_t *mp = ip->i_mount; | ||
504 | xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino); | ||
505 | 507 | ||
506 | write_lock(&pag->pag_ici_lock); | 508 | if (ip->i_afp) |
507 | radix_tree_delete(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, ip->i_ino)); | 509 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); |
508 | write_unlock(&pag->pag_ici_lock); | ||
509 | xfs_put_perag(mp, pag); | ||
510 | 510 | ||
511 | mp->m_ireclaims++; | 511 | #ifdef XFS_INODE_TRACE |
512 | ktrace_free(ip->i_trace); | ||
513 | #endif | ||
514 | #ifdef XFS_BMAP_TRACE | ||
515 | ktrace_free(ip->i_xtrace); | ||
516 | #endif | ||
517 | #ifdef XFS_BTREE_TRACE | ||
518 | ktrace_free(ip->i_btrace); | ||
519 | #endif | ||
520 | #ifdef XFS_RW_TRACE | ||
521 | ktrace_free(ip->i_rwtrace); | ||
522 | #endif | ||
523 | #ifdef XFS_ILOCK_TRACE | ||
524 | ktrace_free(ip->i_lock_trace); | ||
525 | #endif | ||
526 | #ifdef XFS_DIR2_TRACE | ||
527 | ktrace_free(ip->i_dir_trace); | ||
528 | #endif | ||
529 | if (ip->i_itemp) { | ||
530 | /* | ||
531 | * Only if we are shutting down the fs will we see an | ||
532 | * inode still in the AIL. If it is there, we should remove | ||
533 | * it to prevent a use-after-free from occurring. | ||
534 | */ | ||
535 | xfs_log_item_t *lip = &ip->i_itemp->ili_item; | ||
536 | struct xfs_ail *ailp = lip->li_ailp; | ||
537 | |||
538 | ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) || | ||
539 | XFS_FORCED_SHUTDOWN(ip->i_mount)); | ||
540 | if (lip->li_flags & XFS_LI_IN_AIL) { | ||
541 | spin_lock(&ailp->xa_lock); | ||
542 | if (lip->li_flags & XFS_LI_IN_AIL) | ||
543 | xfs_trans_ail_delete(ailp, lip); | ||
544 | else | ||
545 | spin_unlock(&ailp->xa_lock); | ||
546 | } | ||
547 | xfs_inode_item_destroy(ip); | ||
548 | ip->i_itemp = NULL; | ||
549 | } | ||
550 | /* asserts to verify all state is correct here */ | ||
551 | ASSERT(atomic_read(&ip->i_iocount) == 0); | ||
552 | ASSERT(atomic_read(&ip->i_pincount) == 0); | ||
553 | ASSERT(!spin_is_locked(&ip->i_flags_lock)); | ||
554 | ASSERT(completion_done(&ip->i_flush)); | ||
555 | kmem_zone_free(xfs_inode_zone, ip); | ||
512 | } | 556 | } |
513 | 557 | ||
514 | /* | 558 | /* |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 872191b46784..4e664f57860b 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -2450,78 +2450,6 @@ xfs_idestroy_fork( | |||
2450 | } | 2450 | } |
2451 | 2451 | ||
2452 | /* | 2452 | /* |
2453 | * This is called free all the memory associated with an inode. | ||
2454 | * It must free the inode itself and any buffers allocated for | ||
2455 | * if_extents/if_data and if_broot. It must also free the lock | ||
2456 | * associated with the inode. | ||
2457 | * | ||
2458 | * Note: because we don't initialise everything on reallocation out | ||
2459 | * of the zone, we must ensure we nullify everything correctly before | ||
2460 | * freeing the structure. | ||
2461 | */ | ||
2462 | void | ||
2463 | xfs_idestroy( | ||
2464 | xfs_inode_t *ip) | ||
2465 | { | ||
2466 | switch (ip->i_d.di_mode & S_IFMT) { | ||
2467 | case S_IFREG: | ||
2468 | case S_IFDIR: | ||
2469 | case S_IFLNK: | ||
2470 | xfs_idestroy_fork(ip, XFS_DATA_FORK); | ||
2471 | break; | ||
2472 | } | ||
2473 | if (ip->i_afp) | ||
2474 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); | ||
2475 | |||
2476 | #ifdef XFS_INODE_TRACE | ||
2477 | ktrace_free(ip->i_trace); | ||
2478 | #endif | ||
2479 | #ifdef XFS_BMAP_TRACE | ||
2480 | ktrace_free(ip->i_xtrace); | ||
2481 | #endif | ||
2482 | #ifdef XFS_BTREE_TRACE | ||
2483 | ktrace_free(ip->i_btrace); | ||
2484 | #endif | ||
2485 | #ifdef XFS_RW_TRACE | ||
2486 | ktrace_free(ip->i_rwtrace); | ||
2487 | #endif | ||
2488 | #ifdef XFS_ILOCK_TRACE | ||
2489 | ktrace_free(ip->i_lock_trace); | ||
2490 | #endif | ||
2491 | #ifdef XFS_DIR2_TRACE | ||
2492 | ktrace_free(ip->i_dir_trace); | ||
2493 | #endif | ||
2494 | if (ip->i_itemp) { | ||
2495 | /* | ||
2496 | * Only if we are shutting down the fs will we see an | ||
2497 | * inode still in the AIL. If it is there, we should remove | ||
2498 | * it to prevent a use-after-free from occurring. | ||
2499 | */ | ||
2500 | xfs_log_item_t *lip = &ip->i_itemp->ili_item; | ||
2501 | struct xfs_ail *ailp = lip->li_ailp; | ||
2502 | |||
2503 | ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) || | ||
2504 | XFS_FORCED_SHUTDOWN(ip->i_mount)); | ||
2505 | if (lip->li_flags & XFS_LI_IN_AIL) { | ||
2506 | spin_lock(&ailp->xa_lock); | ||
2507 | if (lip->li_flags & XFS_LI_IN_AIL) | ||
2508 | xfs_trans_ail_delete(ailp, lip); | ||
2509 | else | ||
2510 | spin_unlock(&ailp->xa_lock); | ||
2511 | } | ||
2512 | xfs_inode_item_destroy(ip); | ||
2513 | ip->i_itemp = NULL; | ||
2514 | } | ||
2515 | /* asserts to verify all state is correct here */ | ||
2516 | ASSERT(atomic_read(&ip->i_iocount) == 0); | ||
2517 | ASSERT(atomic_read(&ip->i_pincount) == 0); | ||
2518 | ASSERT(!spin_is_locked(&ip->i_flags_lock)); | ||
2519 | ASSERT(completion_done(&ip->i_flush)); | ||
2520 | kmem_zone_free(xfs_inode_zone, ip); | ||
2521 | } | ||
2522 | |||
2523 | |||
2524 | /* | ||
2525 | * Increment the pin count of the given buffer. | 2453 | * Increment the pin count of the given buffer. |
2526 | * This value is protected by ipinlock spinlock in the mount structure. | 2454 | * This value is protected by ipinlock spinlock in the mount structure. |
2527 | */ | 2455 | */ |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index c38d4509c66d..03ae96bdae7e 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -529,8 +529,6 @@ int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *, | |||
529 | xfs_fsize_t, int, int); | 529 | xfs_fsize_t, int, int); |
530 | int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); | 530 | int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); |
531 | 531 | ||
532 | void xfs_idestroy(xfs_inode_t *); | ||
533 | void xfs_iextract(xfs_inode_t *); | ||
534 | void xfs_iext_realloc(xfs_inode_t *, int, int); | 532 | void xfs_iext_realloc(xfs_inode_t *, int, int); |
535 | void xfs_ipin(xfs_inode_t *); | 533 | void xfs_ipin(xfs_inode_t *); |
536 | void xfs_iunpin(xfs_inode_t *); | 534 | void xfs_iunpin(xfs_inode_t *); |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 4fce22a8c355..38252554b1cc 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -241,7 +241,6 @@ typedef struct xfs_mount { | |||
241 | xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */ | 241 | xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */ |
242 | spinlock_t m_agirotor_lock;/* .. and lock protecting it */ | 242 | spinlock_t m_agirotor_lock;/* .. and lock protecting it */ |
243 | xfs_agnumber_t m_maxagi; /* highest inode alloc group */ | 243 | xfs_agnumber_t m_maxagi; /* highest inode alloc group */ |
244 | uint m_ireclaims; /* count of calls to reclaim*/ | ||
245 | uint m_readio_log; /* min read size log bytes */ | 244 | uint m_readio_log; /* min read size log bytes */ |
246 | uint m_readio_blocks; /* min read size blocks */ | 245 | uint m_readio_blocks; /* min read size blocks */ |
247 | uint m_writeio_log; /* min write size log bytes */ | 246 | uint m_writeio_log; /* min write size log bytes */ |