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 /fs/xfs/xfs_iget.c | |
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>
Diffstat (limited to 'fs/xfs/xfs_iget.c')
-rw-r--r-- | fs/xfs/xfs_iget.c | 128 |
1 files changed, 86 insertions, 42 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 | /* |