diff options
author | Christoph Hellwig <hch@infradead.org> | 2009-09-29 09:48:56 -0400 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2009-12-11 16:11:19 -0500 |
commit | 848ce8f731aed0a2d4ab5884a4f6664af73d2dd0 (patch) | |
tree | cb8bdd8d2ce23f586e4bc0351dc934ae37a6db4e | |
parent | 22763c5cf3690a681551162c15d34d935308c8d7 (diff) |
xfs: simplify inode teardown
Currently the reclaim code for the case where we don't reclaim the
final reclaim is overly complicated. We know that the inode is clean
but instead of just directly reclaiming the clean inode we go through
the whole process of marking the inode reclaimable just to directly
reclaim it from the calling context. Besides being overly complicated
this introduces a race where iget could recycle an inode between
marked reclaimable and actually being reclaimed leading to panics.
This patch gets rid of the existing reclaim path, and replaces it with
a simple call to xfs_ireclaim if the inode was clean. While we're at
it we also use the slightly more lax xfs_inode_clean check we'd use
later to determine if we need to flush the inode here.
Finally get rid of xfs_reclaim function and place the remaining small
bits of reclaim code directly into xfs_fs_destroy_inode.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reported-by: Patrick Schreurs <patrick@news-service.com>
Reported-by: Tommy van Leeuwen <tommy@news-service.com>
Tested-by: Patrick Schreurs <patrick@news-service.com>
Reviewed-by: Alex Elder <aelder@sgi.com>
Signed-off-by: Alex Elder <aelder@sgi.com>
-rw-r--r-- | fs/xfs/linux-2.6/xfs_super.c | 34 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.c | 15 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 40 | ||||
-rw-r--r-- | fs/xfs/xfs_vnodeops.h | 1 |
5 files changed, 34 insertions, 57 deletions
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 18a4b8e11df2..a82a93db67c2 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
@@ -930,13 +930,39 @@ xfs_fs_alloc_inode( | |||
930 | */ | 930 | */ |
931 | STATIC void | 931 | STATIC void |
932 | xfs_fs_destroy_inode( | 932 | xfs_fs_destroy_inode( |
933 | struct inode *inode) | 933 | struct inode *inode) |
934 | { | 934 | { |
935 | xfs_inode_t *ip = XFS_I(inode); | 935 | struct xfs_inode *ip = XFS_I(inode); |
936 | |||
937 | xfs_itrace_entry(ip); | ||
936 | 938 | ||
937 | XFS_STATS_INC(vn_reclaim); | 939 | XFS_STATS_INC(vn_reclaim); |
938 | if (xfs_reclaim(ip)) | 940 | |
939 | panic("%s: cannot reclaim 0x%p\n", __func__, inode); | 941 | /* bad inode, get out here ASAP */ |
942 | if (is_bad_inode(inode)) | ||
943 | goto out_reclaim; | ||
944 | |||
945 | xfs_ioend_wait(ip); | ||
946 | |||
947 | ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0); | ||
948 | |||
949 | /* | ||
950 | * We should never get here with one of the reclaim flags already set. | ||
951 | */ | ||
952 | ASSERT_ALWAYS(!xfs_iflags_test(ip, XFS_IRECLAIMABLE)); | ||
953 | ASSERT_ALWAYS(!xfs_iflags_test(ip, XFS_IRECLAIM)); | ||
954 | |||
955 | /* | ||
956 | * If we have nothing to flush with this inode then complete the | ||
957 | * teardown now, otherwise delay the flush operation. | ||
958 | */ | ||
959 | if (!xfs_inode_clean(ip)) { | ||
960 | xfs_inode_set_reclaim_tag(ip); | ||
961 | return; | ||
962 | } | ||
963 | |||
964 | out_reclaim: | ||
965 | xfs_ireclaim(ip); | ||
940 | } | 966 | } |
941 | 967 | ||
942 | /* | 968 | /* |
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 961df0a22c78..d895a3a960f5 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
@@ -663,10 +663,9 @@ xfs_syncd_stop( | |||
663 | kthread_stop(mp->m_sync_task); | 663 | kthread_stop(mp->m_sync_task); |
664 | } | 664 | } |
665 | 665 | ||
666 | int | 666 | STATIC int |
667 | xfs_reclaim_inode( | 667 | xfs_reclaim_inode( |
668 | xfs_inode_t *ip, | 668 | xfs_inode_t *ip, |
669 | int locked, | ||
670 | int sync_mode) | 669 | int sync_mode) |
671 | { | 670 | { |
672 | xfs_perag_t *pag = xfs_get_perag(ip->i_mount, ip->i_ino); | 671 | xfs_perag_t *pag = xfs_get_perag(ip->i_mount, ip->i_ino); |
@@ -682,10 +681,6 @@ xfs_reclaim_inode( | |||
682 | !__xfs_iflags_test(ip, XFS_IRECLAIMABLE)) { | 681 | !__xfs_iflags_test(ip, XFS_IRECLAIMABLE)) { |
683 | spin_unlock(&ip->i_flags_lock); | 682 | spin_unlock(&ip->i_flags_lock); |
684 | write_unlock(&pag->pag_ici_lock); | 683 | write_unlock(&pag->pag_ici_lock); |
685 | if (locked) { | ||
686 | xfs_ifunlock(ip); | ||
687 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
688 | } | ||
689 | return -EAGAIN; | 684 | return -EAGAIN; |
690 | } | 685 | } |
691 | __xfs_iflags_set(ip, XFS_IRECLAIM); | 686 | __xfs_iflags_set(ip, XFS_IRECLAIM); |
@@ -704,10 +699,8 @@ xfs_reclaim_inode( | |||
704 | * We get the flush lock regardless, though, just to make sure | 699 | * We get the flush lock regardless, though, just to make sure |
705 | * we don't free it while it is being flushed. | 700 | * we don't free it while it is being flushed. |
706 | */ | 701 | */ |
707 | if (!locked) { | 702 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
708 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 703 | xfs_iflock(ip); |
709 | xfs_iflock(ip); | ||
710 | } | ||
711 | 704 | ||
712 | /* | 705 | /* |
713 | * In the case of a forced shutdown we rely on xfs_iflush() to | 706 | * In the case of a forced shutdown we rely on xfs_iflush() to |
@@ -778,7 +771,7 @@ xfs_reclaim_inode_now( | |||
778 | } | 771 | } |
779 | read_unlock(&pag->pag_ici_lock); | 772 | read_unlock(&pag->pag_ici_lock); |
780 | 773 | ||
781 | return xfs_reclaim_inode(ip, 0, flags); | 774 | return xfs_reclaim_inode(ip, flags); |
782 | } | 775 | } |
783 | 776 | ||
784 | int | 777 | int |
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h index 27920eb7a820..a500b4d91835 100644 --- a/fs/xfs/linux-2.6/xfs_sync.h +++ b/fs/xfs/linux-2.6/xfs_sync.h | |||
@@ -44,7 +44,6 @@ void xfs_quiesce_attr(struct xfs_mount *mp); | |||
44 | 44 | ||
45 | void xfs_flush_inodes(struct xfs_inode *ip); | 45 | void xfs_flush_inodes(struct xfs_inode *ip); |
46 | 46 | ||
47 | int xfs_reclaim_inode(struct xfs_inode *ip, int locked, int sync_mode); | ||
48 | int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); | 47 | int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); |
49 | 48 | ||
50 | void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); | 49 | void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index b572f7e840e0..3fac146b3b7d 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
@@ -2456,46 +2456,6 @@ xfs_set_dmattrs( | |||
2456 | return error; | 2456 | return error; |
2457 | } | 2457 | } |
2458 | 2458 | ||
2459 | int | ||
2460 | xfs_reclaim( | ||
2461 | xfs_inode_t *ip) | ||
2462 | { | ||
2463 | |||
2464 | xfs_itrace_entry(ip); | ||
2465 | |||
2466 | ASSERT(!VN_MAPPED(VFS_I(ip))); | ||
2467 | |||
2468 | /* bad inode, get out here ASAP */ | ||
2469 | if (is_bad_inode(VFS_I(ip))) { | ||
2470 | xfs_ireclaim(ip); | ||
2471 | return 0; | ||
2472 | } | ||
2473 | |||
2474 | xfs_ioend_wait(ip); | ||
2475 | |||
2476 | ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0); | ||
2477 | |||
2478 | /* | ||
2479 | * If we have nothing to flush with this inode then complete the | ||
2480 | * teardown now, otherwise break the link between the xfs inode and the | ||
2481 | * linux inode and clean up the xfs inode later. This avoids flushing | ||
2482 | * the inode to disk during the delete operation itself. | ||
2483 | * | ||
2484 | * When breaking the link, we need to set the XFS_IRECLAIMABLE flag | ||
2485 | * first to ensure that xfs_iunpin() will never see an xfs inode | ||
2486 | * that has a linux inode being reclaimed. Synchronisation is provided | ||
2487 | * by the i_flags_lock. | ||
2488 | */ | ||
2489 | if (!ip->i_update_core && (ip->i_itemp == NULL)) { | ||
2490 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
2491 | xfs_iflock(ip); | ||
2492 | xfs_iflags_set(ip, XFS_IRECLAIMABLE); | ||
2493 | return xfs_reclaim_inode(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC); | ||
2494 | } | ||
2495 | xfs_inode_set_reclaim_tag(ip); | ||
2496 | return 0; | ||
2497 | } | ||
2498 | |||
2499 | /* | 2459 | /* |
2500 | * xfs_alloc_file_space() | 2460 | * xfs_alloc_file_space() |
2501 | * This routine allocates disk space for the given file. | 2461 | * This routine allocates disk space for the given file. |
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index a9e102de71a1..167a467403a5 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h | |||
@@ -38,7 +38,6 @@ int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name, | |||
38 | const char *target_path, mode_t mode, struct xfs_inode **ipp, | 38 | const char *target_path, mode_t mode, struct xfs_inode **ipp, |
39 | cred_t *credp); | 39 | cred_t *credp); |
40 | int xfs_set_dmattrs(struct xfs_inode *ip, u_int evmask, u_int16_t state); | 40 | int xfs_set_dmattrs(struct xfs_inode *ip, u_int evmask, u_int16_t state); |
41 | int xfs_reclaim(struct xfs_inode *ip); | ||
42 | int xfs_change_file_space(struct xfs_inode *ip, int cmd, | 41 | int xfs_change_file_space(struct xfs_inode *ip, int cmd, |
43 | xfs_flock64_t *bf, xfs_off_t offset, int attr_flags); | 42 | xfs_flock64_t *bf, xfs_off_t offset, int attr_flags); |
44 | int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name, | 43 | int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name, |