diff options
Diffstat (limited to 'fs/xfs/xfs_inode_item.c')
-rw-r--r-- | fs/xfs/xfs_inode_item.c | 90 |
1 files changed, 74 insertions, 16 deletions
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 7c8d30c453c3..fd4f398bd6f1 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c | |||
@@ -842,15 +842,64 @@ xfs_inode_item_destroy( | |||
842 | * flushed to disk. It is responsible for removing the inode item | 842 | * flushed to disk. It is responsible for removing the inode item |
843 | * from the AIL if it has not been re-logged, and unlocking the inode's | 843 | * from the AIL if it has not been re-logged, and unlocking the inode's |
844 | * flush lock. | 844 | * flush lock. |
845 | * | ||
846 | * To reduce AIL lock traffic as much as possible, we scan the buffer log item | ||
847 | * list for other inodes that will run this function. We remove them from the | ||
848 | * buffer list so we can process all the inode IO completions in one AIL lock | ||
849 | * traversal. | ||
845 | */ | 850 | */ |
846 | void | 851 | void |
847 | xfs_iflush_done( | 852 | xfs_iflush_done( |
848 | struct xfs_buf *bp, | 853 | struct xfs_buf *bp, |
849 | struct xfs_log_item *lip) | 854 | struct xfs_log_item *lip) |
850 | { | 855 | { |
851 | struct xfs_inode_log_item *iip = INODE_ITEM(lip); | 856 | struct xfs_inode_log_item *iip; |
852 | xfs_inode_t *ip = iip->ili_inode; | 857 | struct xfs_log_item *blip; |
858 | struct xfs_log_item *next; | ||
859 | struct xfs_log_item *prev; | ||
853 | struct xfs_ail *ailp = lip->li_ailp; | 860 | struct xfs_ail *ailp = lip->li_ailp; |
861 | int need_ail = 0; | ||
862 | |||
863 | /* | ||
864 | * Scan the buffer IO completions for other inodes being completed and | ||
865 | * attach them to the current inode log item. | ||
866 | */ | ||
867 | blip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); | ||
868 | prev = NULL; | ||
869 | while (blip != NULL) { | ||
870 | if (lip->li_cb != xfs_iflush_done) { | ||
871 | prev = blip; | ||
872 | blip = blip->li_bio_list; | ||
873 | continue; | ||
874 | } | ||
875 | |||
876 | /* remove from list */ | ||
877 | next = blip->li_bio_list; | ||
878 | if (!prev) { | ||
879 | XFS_BUF_SET_FSPRIVATE(bp, next); | ||
880 | } else { | ||
881 | prev->li_bio_list = next; | ||
882 | } | ||
883 | |||
884 | /* add to current list */ | ||
885 | blip->li_bio_list = lip->li_bio_list; | ||
886 | lip->li_bio_list = blip; | ||
887 | |||
888 | /* | ||
889 | * while we have the item, do the unlocked check for needing | ||
890 | * the AIL lock. | ||
891 | */ | ||
892 | iip = INODE_ITEM(blip); | ||
893 | if (iip->ili_logged && blip->li_lsn == iip->ili_flush_lsn) | ||
894 | need_ail++; | ||
895 | |||
896 | blip = next; | ||
897 | } | ||
898 | |||
899 | /* make sure we capture the state of the initial inode. */ | ||
900 | iip = INODE_ITEM(lip); | ||
901 | if (iip->ili_logged && lip->li_lsn == iip->ili_flush_lsn) | ||
902 | need_ail++; | ||
854 | 903 | ||
855 | /* | 904 | /* |
856 | * We only want to pull the item from the AIL if it is | 905 | * We only want to pull the item from the AIL if it is |
@@ -861,28 +910,37 @@ xfs_iflush_done( | |||
861 | * the lock since it's cheaper, and then we recheck while | 910 | * the lock since it's cheaper, and then we recheck while |
862 | * holding the lock before removing the inode from the AIL. | 911 | * holding the lock before removing the inode from the AIL. |
863 | */ | 912 | */ |
864 | if (iip->ili_logged && lip->li_lsn == iip->ili_flush_lsn) { | 913 | if (need_ail) { |
914 | struct xfs_log_item *log_items[need_ail]; | ||
915 | int i = 0; | ||
865 | spin_lock(&ailp->xa_lock); | 916 | spin_lock(&ailp->xa_lock); |
866 | if (lip->li_lsn == iip->ili_flush_lsn) { | 917 | for (blip = lip; blip; blip = blip->li_bio_list) { |
867 | /* xfs_trans_ail_delete() drops the AIL lock. */ | 918 | iip = INODE_ITEM(blip); |
868 | xfs_trans_ail_delete(ailp, lip); | 919 | if (iip->ili_logged && |
869 | } else { | 920 | blip->li_lsn == iip->ili_flush_lsn) { |
870 | spin_unlock(&ailp->xa_lock); | 921 | log_items[i++] = blip; |
922 | } | ||
923 | ASSERT(i <= need_ail); | ||
871 | } | 924 | } |
925 | /* xfs_trans_ail_delete_bulk() drops the AIL lock. */ | ||
926 | xfs_trans_ail_delete_bulk(ailp, log_items, i); | ||
872 | } | 927 | } |
873 | 928 | ||
874 | iip->ili_logged = 0; | ||
875 | 929 | ||
876 | /* | 930 | /* |
877 | * Clear the ili_last_fields bits now that we know that the | 931 | * clean up and unlock the flush lock now we are done. We can clear the |
878 | * data corresponding to them is safely on disk. | 932 | * ili_last_fields bits now that we know that the data corresponding to |
933 | * them is safely on disk. | ||
879 | */ | 934 | */ |
880 | iip->ili_last_fields = 0; | 935 | for (blip = lip; blip; blip = next) { |
936 | next = blip->li_bio_list; | ||
937 | blip->li_bio_list = NULL; | ||
881 | 938 | ||
882 | /* | 939 | iip = INODE_ITEM(blip); |
883 | * Release the inode's flush lock since we're done with it. | 940 | iip->ili_logged = 0; |
884 | */ | 941 | iip->ili_last_fields = 0; |
885 | xfs_ifunlock(ip); | 942 | xfs_ifunlock(iip->ili_inode); |
943 | } | ||
886 | } | 944 | } |
887 | 945 | ||
888 | /* | 946 | /* |