aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2010-12-19 20:03:17 -0500
committerDave Chinner <david@fromorbit.com>2010-12-19 20:03:17 -0500
commit3013683253ad04f67d8cfaa25be708353686b90a (patch)
treeeadc35b70c0169096a7dbaf4eb9966be7630db04 /fs/xfs
parentc90821a26a8c90ad1e3116393b8a8260ab46bffb (diff)
xfs: remove all the inodes on a buffer from the AIL in bulk
When inode buffer IO completes, usually all of the inodes are removed from the AIL. This involves processing them one at a time and taking the AIL lock once for every inode. When all CPUs are processing inode IO completions, this causes excessive amount sof contention on the AIL lock. Instead, change the way we process inode IO completion in the buffer IO done callback. Allow the inode IO done callback to walk the list of IO done callbacks and pull all the inodes off the buffer in one go and then process them as a batch. Once all the inodes for removal are collected, take the AIL lock once and do a bulk removal operation to minimise traffic on the AIL lock. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_inode_item.c90
-rw-r--r--fs/xfs/xfs_trans_ail.c73
-rw-r--r--fs/xfs/xfs_trans_priv.h4
3 files changed, 151 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 */
846void 851void
847xfs_iflush_done( 852xfs_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/*
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index fe991a76bf14..218f96861c80 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -639,6 +639,79 @@ xfs_trans_ail_delete(
639 } 639 }
640} 640}
641 641
642/*
643 * xfs_trans_ail_delete_bulk - remove multiple log items from the AIL
644 *
645 * @xfs_trans_ail_delete_bulk takes an array of log items that all need to
646 * removed from the AIL. The caller is already holding the AIL lock, and done
647 * all the checks necessary to ensure the items passed in via @log_items are
648 * ready for deletion. This includes checking that the items are in the AIL.
649 *
650 * For each log item to be removed, unlink it from the AIL, clear the IN_AIL
651 * flag from the item and reset the item's lsn to 0. If we remove the first
652 * item in the AIL, update the log tail to match the new minimum LSN in the
653 * AIL.
654 *
655 * This function will not drop the AIL lock until all items are removed from
656 * the AIL to minimise the amount of lock traffic on the AIL. This does not
657 * greatly increase the AIL hold time, but does significantly reduce the amount
658 * of traffic on the lock, especially during IO completion.
659 *
660 * This function must be called with the AIL lock held. The lock is dropped
661 * before returning.
662 */
663void
664xfs_trans_ail_delete_bulk(
665 struct xfs_ail *ailp,
666 struct xfs_log_item **log_items,
667 int nr_items) __releases(ailp->xa_lock)
668{
669 xfs_log_item_t *mlip;
670 xfs_lsn_t tail_lsn;
671 int mlip_changed = 0;
672 int i;
673
674 mlip = xfs_ail_min(ailp);
675
676 for (i = 0; i < nr_items; i++) {
677 struct xfs_log_item *lip = log_items[i];
678 if (!(lip->li_flags & XFS_LI_IN_AIL)) {
679 struct xfs_mount *mp = ailp->xa_mount;
680
681 spin_unlock(&ailp->xa_lock);
682 if (!XFS_FORCED_SHUTDOWN(mp)) {
683 xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp,
684 "%s: attempting to delete a log item that is not in the AIL",
685 __func__);
686 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
687 }
688 return;
689 }
690
691 xfs_ail_delete(ailp, lip);
692 lip->li_flags &= ~XFS_LI_IN_AIL;
693 lip->li_lsn = 0;
694 if (mlip == lip)
695 mlip_changed = 1;
696 }
697
698 if (!mlip_changed) {
699 spin_unlock(&ailp->xa_lock);
700 return;
701 }
702
703 /*
704 * It is not safe to access mlip after the AIL lock is dropped, so we
705 * must get a copy of li_lsn before we do so. This is especially
706 * important on 32-bit platforms where accessing and updating 64-bit
707 * values like li_lsn is not atomic. It is possible we've emptied the
708 * AIL here, so if that is the case, pass an LSN of 0 to the tail move.
709 */
710 mlip = xfs_ail_min(ailp);
711 tail_lsn = mlip ? mlip->li_lsn : 0;
712 spin_unlock(&ailp->xa_lock);
713 xfs_log_move_tail(ailp->xa_mount, tail_lsn);
714}
642 715
643 716
644/* 717/*
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index e039729186e9..246ca4dcb5c4 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -85,6 +85,10 @@ void xfs_trans_ail_update_bulk(struct xfs_ail *ailp,
85void xfs_trans_ail_delete(struct xfs_ail *ailp, 85void xfs_trans_ail_delete(struct xfs_ail *ailp,
86 struct xfs_log_item *lip) 86 struct xfs_log_item *lip)
87 __releases(ailp->xa_lock); 87 __releases(ailp->xa_lock);
88void xfs_trans_ail_delete_bulk(struct xfs_ail *ailp,
89 struct xfs_log_item **log_items,
90 int nr_items)
91 __releases(ailp->xa_lock);
88void xfs_trans_ail_push(struct xfs_ail *, xfs_lsn_t); 92void xfs_trans_ail_push(struct xfs_ail *, xfs_lsn_t);
89void xfs_trans_unlocked_item(struct xfs_ail *, 93void xfs_trans_unlocked_item(struct xfs_ail *,
90 xfs_log_item_t *); 94 xfs_log_item_t *);