Skip to content

Commit 8eb807b

Browse files
Dave Chinnerdjwong
authored andcommitted
xfs: tail updates only need to occur when LSN changes
We currently wake anything waiting on the log tail to move whenever the log item at the tail of the log is removed. Historically this was fine behaviour because there were very few items at any given LSN. But with delayed logging, there may be thousands of items at any given LSN, and we can't move the tail until they are all gone. Hence if we are removing them in near tail-first order, we might be waking up processes waiting on the tail LSN to change (e.g. log space waiters) repeatedly without them being able to make progress. This also occurs with the new sync push waiters, and can result in thousands of spurious wakeups every second when under heavy direct reclaim pressure. To fix this, check that the tail LSN has actually changed on the AIL before triggering wakeups. This will reduce the number of spurious wakeups when doing bulk AIL removal and make this code much more efficient. Signed-off-by: Dave Chinner <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Brian Foster <[email protected]> Reviewed-by: Allison Collins <[email protected]> Reviewed-by: Darrick J. Wong <[email protected]> Signed-off-by: Darrick J. Wong <[email protected]>
1 parent 4165994 commit 8eb807b

File tree

3 files changed

+51
-23
lines changed

3 files changed

+51
-23
lines changed

fs/xfs/xfs_inode_item.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -730,19 +730,27 @@ xfs_iflush_done(
730730
* holding the lock before removing the inode from the AIL.
731731
*/
732732
if (need_ail) {
733-
bool mlip_changed = false;
733+
xfs_lsn_t tail_lsn = 0;
734734

735735
/* this is an opencoded batch version of xfs_trans_ail_delete */
736736
spin_lock(&ailp->ail_lock);
737737
list_for_each_entry(blip, &tmp, li_bio_list) {
738738
if (INODE_ITEM(blip)->ili_logged &&
739-
blip->li_lsn == INODE_ITEM(blip)->ili_flush_lsn)
740-
mlip_changed |= xfs_ail_delete_one(ailp, blip);
741-
else {
739+
blip->li_lsn == INODE_ITEM(blip)->ili_flush_lsn) {
740+
/*
741+
* xfs_ail_update_finish() only cares about the
742+
* lsn of the first tail item removed, any
743+
* others will be at the same or higher lsn so
744+
* we just ignore them.
745+
*/
746+
xfs_lsn_t lsn = xfs_ail_delete_one(ailp, blip);
747+
if (!tail_lsn && lsn)
748+
tail_lsn = lsn;
749+
} else {
742750
xfs_clear_li_failed(blip);
743751
}
744752
}
745-
xfs_ail_update_finish(ailp, mlip_changed);
753+
xfs_ail_update_finish(ailp, tail_lsn);
746754
}
747755

748756
/*

fs/xfs/xfs_trans_ail.c

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,25 @@ xfs_ail_next(
109109
* We need the AIL lock in order to get a coherent read of the lsn of the last
110110
* item in the AIL.
111111
*/
112+
static xfs_lsn_t
113+
__xfs_ail_min_lsn(
114+
struct xfs_ail *ailp)
115+
{
116+
struct xfs_log_item *lip = xfs_ail_min(ailp);
117+
118+
if (lip)
119+
return lip->li_lsn;
120+
return 0;
121+
}
122+
112123
xfs_lsn_t
113124
xfs_ail_min_lsn(
114125
struct xfs_ail *ailp)
115126
{
116-
xfs_lsn_t lsn = 0;
117-
struct xfs_log_item *lip;
127+
xfs_lsn_t lsn;
118128

119129
spin_lock(&ailp->ail_lock);
120-
lip = xfs_ail_min(ailp);
121-
if (lip)
122-
lsn = lip->li_lsn;
130+
lsn = __xfs_ail_min_lsn(ailp);
123131
spin_unlock(&ailp->ail_lock);
124132

125133
return lsn;
@@ -684,11 +692,12 @@ xfs_ail_push_all_sync(
684692
void
685693
xfs_ail_update_finish(
686694
struct xfs_ail *ailp,
687-
bool do_tail_update) __releases(ailp->ail_lock)
695+
xfs_lsn_t old_lsn) __releases(ailp->ail_lock)
688696
{
689697
struct xfs_mount *mp = ailp->ail_mount;
690698

691-
if (!do_tail_update) {
699+
/* if the tail lsn hasn't changed, don't do updates or wakeups. */
700+
if (!old_lsn || old_lsn == __xfs_ail_min_lsn(ailp)) {
692701
spin_unlock(&ailp->ail_lock);
693702
return;
694703
}
@@ -733,7 +742,7 @@ xfs_trans_ail_update_bulk(
733742
xfs_lsn_t lsn) __releases(ailp->ail_lock)
734743
{
735744
struct xfs_log_item *mlip;
736-
int mlip_changed = 0;
745+
xfs_lsn_t tail_lsn = 0;
737746
int i;
738747
LIST_HEAD(tmp);
739748

@@ -748,9 +757,10 @@ xfs_trans_ail_update_bulk(
748757
continue;
749758

750759
trace_xfs_ail_move(lip, lip->li_lsn, lsn);
760+
if (mlip == lip && !tail_lsn)
761+
tail_lsn = lip->li_lsn;
762+
751763
xfs_ail_delete(ailp, lip);
752-
if (mlip == lip)
753-
mlip_changed = 1;
754764
} else {
755765
trace_xfs_ail_insert(lip, 0, lsn);
756766
}
@@ -761,23 +771,33 @@ xfs_trans_ail_update_bulk(
761771
if (!list_empty(&tmp))
762772
xfs_ail_splice(ailp, cur, &tmp, lsn);
763773

764-
xfs_ail_update_finish(ailp, mlip_changed);
774+
xfs_ail_update_finish(ailp, tail_lsn);
765775
}
766776

767-
bool
777+
/*
778+
* Delete one log item from the AIL.
779+
*
780+
* If this item was at the tail of the AIL, return the LSN of the log item so
781+
* that we can use it to check if the LSN of the tail of the log has moved
782+
* when finishing up the AIL delete process in xfs_ail_update_finish().
783+
*/
784+
xfs_lsn_t
768785
xfs_ail_delete_one(
769786
struct xfs_ail *ailp,
770787
struct xfs_log_item *lip)
771788
{
772789
struct xfs_log_item *mlip = xfs_ail_min(ailp);
790+
xfs_lsn_t lsn = lip->li_lsn;
773791

774792
trace_xfs_ail_delete(lip, mlip->li_lsn, lip->li_lsn);
775793
xfs_ail_delete(ailp, lip);
776794
xfs_clear_li_failed(lip);
777795
clear_bit(XFS_LI_IN_AIL, &lip->li_flags);
778796
lip->li_lsn = 0;
779797

780-
return mlip == lip;
798+
if (mlip == lip)
799+
return lsn;
800+
return 0;
781801
}
782802

783803
/**
@@ -808,7 +828,7 @@ xfs_trans_ail_delete(
808828
int shutdown_type)
809829
{
810830
struct xfs_mount *mp = ailp->ail_mount;
811-
bool need_update;
831+
xfs_lsn_t tail_lsn;
812832

813833
if (!test_bit(XFS_LI_IN_AIL, &lip->li_flags)) {
814834
spin_unlock(&ailp->ail_lock);
@@ -821,8 +841,8 @@ xfs_trans_ail_delete(
821841
return;
822842
}
823843

824-
need_update = xfs_ail_delete_one(ailp, lip);
825-
xfs_ail_update_finish(ailp, need_update);
844+
tail_lsn = xfs_ail_delete_one(ailp, lip);
845+
xfs_ail_update_finish(ailp, tail_lsn);
826846
}
827847

828848
int

fs/xfs/xfs_trans_priv.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ xfs_trans_ail_update(
9191
xfs_trans_ail_update_bulk(ailp, NULL, &lip, 1, lsn);
9292
}
9393

94-
bool xfs_ail_delete_one(struct xfs_ail *ailp, struct xfs_log_item *lip);
95-
void xfs_ail_update_finish(struct xfs_ail *ailp, bool do_tail_update)
94+
xfs_lsn_t xfs_ail_delete_one(struct xfs_ail *ailp, struct xfs_log_item *lip);
95+
void xfs_ail_update_finish(struct xfs_ail *ailp, xfs_lsn_t old_lsn)
9696
__releases(ailp->ail_lock);
9797
void xfs_trans_ail_delete(struct xfs_ail *ailp, struct xfs_log_item *lip,
9898
int shutdown_type);

0 commit comments

Comments
 (0)