diff options
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_sync.c')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.c | 81 |
1 files changed, 62 insertions, 19 deletions
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index c9b863eacab7..525260c7617f 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
@@ -706,12 +706,43 @@ __xfs_inode_clear_reclaim_tag( | |||
706 | XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); | 706 | XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); |
707 | } | 707 | } |
708 | 708 | ||
709 | /* | ||
710 | * Inodes in different states need to be treated differently, and the return | ||
711 | * value of xfs_iflush is not sufficient to get this right. The following table | ||
712 | * lists the inode states and the reclaim actions necessary for non-blocking | ||
713 | * reclaim: | ||
714 | * | ||
715 | * | ||
716 | * inode state iflush ret required action | ||
717 | * --------------- ---------- --------------- | ||
718 | * bad - reclaim | ||
719 | * shutdown EIO unpin and reclaim | ||
720 | * clean, unpinned 0 reclaim | ||
721 | * stale, unpinned 0 reclaim | ||
722 | * clean, pinned(*) 0 unpin and reclaim | ||
723 | * stale, pinned 0 unpin and reclaim | ||
724 | * dirty, async 0 block on flush lock, reclaim | ||
725 | * dirty, sync flush 0 block on flush lock, reclaim | ||
726 | * | ||
727 | * (*) dgc: I don't think the clean, pinned state is possible but it gets | ||
728 | * handled anyway given the order of checks implemented. | ||
729 | * | ||
730 | * Hence the order of actions after gaining the locks should be: | ||
731 | * bad => reclaim | ||
732 | * shutdown => unpin and reclaim | ||
733 | * pinned => unpin | ||
734 | * stale => reclaim | ||
735 | * clean => reclaim | ||
736 | * dirty => flush, wait and reclaim | ||
737 | */ | ||
709 | STATIC int | 738 | STATIC int |
710 | xfs_reclaim_inode( | 739 | xfs_reclaim_inode( |
711 | struct xfs_inode *ip, | 740 | struct xfs_inode *ip, |
712 | struct xfs_perag *pag, | 741 | struct xfs_perag *pag, |
713 | int sync_mode) | 742 | int sync_mode) |
714 | { | 743 | { |
744 | int error; | ||
745 | |||
715 | /* | 746 | /* |
716 | * The radix tree lock here protects a thread in xfs_iget from racing | 747 | * The radix tree lock here protects a thread in xfs_iget from racing |
717 | * with us starting reclaim on the inode. Once we have the | 748 | * with us starting reclaim on the inode. Once we have the |
@@ -729,30 +760,42 @@ xfs_reclaim_inode( | |||
729 | spin_unlock(&ip->i_flags_lock); | 760 | spin_unlock(&ip->i_flags_lock); |
730 | write_unlock(&pag->pag_ici_lock); | 761 | write_unlock(&pag->pag_ici_lock); |
731 | 762 | ||
732 | /* | ||
733 | * If the inode is still dirty, then flush it out. If the inode | ||
734 | * is not in the AIL, then it will be OK to flush it delwri as | ||
735 | * long as xfs_iflush() does not keep any references to the inode. | ||
736 | * We leave that decision up to xfs_iflush() since it has the | ||
737 | * knowledge of whether it's OK to simply do a delwri flush of | ||
738 | * the inode or whether we need to wait until the inode is | ||
739 | * pulled from the AIL. | ||
740 | * We get the flush lock regardless, though, just to make sure | ||
741 | * we don't free it while it is being flushed. | ||
742 | */ | ||
743 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 763 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
744 | xfs_iflock(ip); | 764 | xfs_iflock(ip); |
745 | 765 | ||
746 | /* | 766 | if (is_bad_inode(VFS_I(ip))) |
747 | * In the case of a forced shutdown we rely on xfs_iflush() to | 767 | goto reclaim; |
748 | * wait for the inode to be unpinned before returning an error. | 768 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { |
749 | */ | 769 | xfs_iunpin_wait(ip); |
750 | if (!is_bad_inode(VFS_I(ip)) && xfs_iflush(ip, sync_mode) == 0) { | 770 | goto reclaim; |
751 | /* synchronize with xfs_iflush_done */ | 771 | } |
752 | xfs_iflock(ip); | 772 | if (xfs_ipincount(ip)) |
753 | xfs_ifunlock(ip); | 773 | xfs_iunpin_wait(ip); |
774 | if (xfs_iflags_test(ip, XFS_ISTALE)) | ||
775 | goto reclaim; | ||
776 | if (xfs_inode_clean(ip)) | ||
777 | goto reclaim; | ||
778 | |||
779 | /* Now we have an inode that needs flushing */ | ||
780 | error = xfs_iflush(ip, sync_mode); | ||
781 | if (!error) { | ||
782 | switch(sync_mode) { | ||
783 | case XFS_IFLUSH_DELWRI_ELSE_ASYNC: | ||
784 | case XFS_IFLUSH_DELWRI: | ||
785 | case XFS_IFLUSH_ASYNC: | ||
786 | case XFS_IFLUSH_DELWRI_ELSE_SYNC: | ||
787 | case XFS_IFLUSH_SYNC: | ||
788 | /* IO issued, synchronise with IO completion */ | ||
789 | xfs_iflock(ip); | ||
790 | break; | ||
791 | default: | ||
792 | ASSERT(0); | ||
793 | break; | ||
794 | } | ||
754 | } | 795 | } |
755 | 796 | ||
797 | reclaim: | ||
798 | xfs_ifunlock(ip); | ||
756 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 799 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
757 | xfs_ireclaim(ip); | 800 | xfs_ireclaim(ip); |
758 | return 0; | 801 | return 0; |