FAILED: patch "[PATCH] Multi-gen LRU: avoid race in inc_min_seq()" failed to apply to 6.1-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x bb5e7f234eacf34b65be67ebb3613e3b8cf11b87
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2023091354-atom-tinderbox-b9be@gregkh' --subject-prefix 'PATCH 6.1.y' HEAD^..
Possible dependencies:
bb5e7f234eac ("Multi-gen LRU: avoid race in inc_min_seq()") 391655fe08d1 ("mm: multi-gen LRU: rename lru_gen_struct to lru_gen_folio")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From bb5e7f234eacf34b65be67ebb3613e3b8cf11b87 Mon Sep 17 00:00:00 2001
From: Kalesh Singh <[email protected]>
Date: Tue, 1 Aug 2023 19:56:03 -0700
Subject: [PATCH] Multi-gen LRU: avoid race in inc_min_seq()
inc_max_seq() will try to inc_min_seq() if nr_gens == MAX_NR_GENS. This is because the generations are reused (the last oldest now empty generation will become the next youngest generation).
inc_min_seq() is retried until successful, dropping the lru_lock and yielding the CPU on each failure, and retaking the lock before trying again:
while (!inc_min_seq(lruvec, type, can_swap)) {
spin_unlock_irq(&lruvec->lru_lock);
cond_resched();
spin_lock_irq(&lruvec->lru_lock);
}However, the initial condition that required incrementing the min_seq (nr_gens == MAX_NR_GENS) is not retested. This can change by another call to inc_max_seq() from run_aging() with force_scan=true from the debugfs interface.
Since the eviction stalls when the nr_gens == MIN_NR_GENS, avoid unnecessarily incrementing the min_seq by rechecking the number of generations before each attempt.
This issue was uncovered in previous discussion on the list by Yu Zhao and Aneesh Kumar [1].
[1] https://lore.kernel.org/linux-mm/CAOUHufbO7CaVm=xjEb1avDhHVvnC8pJmGyKcFf2iY_dpf+zR3w@mail.gmail.com/
mm/vmscan.c +7 -6
@@ -4439,7 +4439,7 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap, bool force_scan)int prev, next;int type, zone;struct lru_gen_folio *lrugen = &lruvec->lrugen; - +restart:spin_lock_irq (&lruvec->lru_lock);VM_WARN_ON_ONCE (!seq_is_valid (lruvec));
@@ -4450,11 +4450,12 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap, bool force_scan)VM_WARN_ON_ONCE (!force_scan && (type ==LRU_GEN_FILE || can_swap)); -while (!inc_min_seq (lruvec, type, can_swap)) { -spin_unlock_irq (&lruvec->lru_lock); -cond_resched (); -spin_lock_irq (&lruvec->lru_lock); - } +if (inc_min_seq (lruvec, type, can_swap)) +continue ; + +spin_unlock_irq (&lruvec->lru_lock); +cond_resched (); + goto restart; }/*
PATCH 1/1 Multi-gen LRU: avoid race in inc_min_seq()
inc_max_seq() will try to inc_min_seq() if nr_gens == MAX_NR_GENS. This is because the generations are reused (the last oldest now empty generation will become the next youngest generation).
inc_min_seq() is retried until successful, dropping the lru_lock and yielding the CPU on each failure, and retaking the lock before trying again:
while (!inc_min_seq(lruvec, type, can_swap)) {
spin_unlock_irq(&lruvec->lru_lock);
cond_resched();
spin_lock_irq(&lruvec->lru_lock);
}However, the initial condition that required incrementing the min_seq (nr_gens == MAX_NR_GENS) is not retested. This can change by another call to inc_max_seq() from run_aging() with force_scan=true from the debugfs interface.
Since the eviction stalls when the nr_gens == MIN_NR_GENS, avoid unnecessarily incrementing the min_seq by rechecking the number of generations before each attempt.
This issue was uncovered in previous discussion on the list by Yu Zhao and Aneesh Kumar [1].
[1] https://lore.kernel.org/linux-mm/CAOUHufbO7CaVm=xjEb1avDhHVvnC8pJmGyKcFf2iY_dpf+zR3w@mail.gmail.com/
--- mm/vmscan.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
mm/vmscan.c +7 -5
@@ -4331,6 +4331,7 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap, bool force_scan)int type, zone;struct lru_gen_struct *lrugen = &lruvec->lrugen; +restart:spin_lock_irq (&lruvec->lru_lock);VM_WARN_ON_ONCE (!seq_is_valid (lruvec));
@@ -4341,11 +4342,12 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap, bool force_scan)VM_WARN_ON_ONCE (!force_scan && (type ==LRU_GEN_FILE || can_swap)); -while (!inc_min_seq (lruvec, type, can_swap)) { -spin_unlock_irq (&lruvec->lru_lock); -cond_resched (); -spin_lock_irq (&lruvec->lru_lock); - } +if (inc_min_seq (lruvec, type, can_swap)) +continue ; + +spin_unlock_irq (&lruvec->lru_lock); +cond_resched (); + goto restart; }/*
Signature · 1 line
2.42.0.283.g2d96d420d3-goog
Greg KH
maintainerRe: [PATCH 6.1.y] Multi-gen LRU: avoid race in inc_min_seq()
Quoted 3 lines · Kalesh Singh
inc_max_seq()will try toinc_min_seq()ifnr_gens==MAX_NR_GENS. This is because the generations are reused (the last oldest now empty generation will become the next youngest generation).
Now queued up, thanks.
greg k-h