Skip to content

Commit 83b6ba5

Browse files
ryncsn1Naim
authored andcommitted
mm/mglru: scan and count the exact number of folios
Make the scan helpers return the exact number of folios being scanned or isolated. Since the reclaim loop now has a natural scan budget that controls the scan progress, returning the scan number and consume the budget should make the scan more accurate and easier to follow. The number of scanned folios for each iteration is always positive and larger than 0, unless the reclaim must stop for a forced aging, so there is no more need for any special handling when there is no progress made: - `return isolated || !remaining ? scanned : 0` in scan_folios: both the function and the call now just return the exact scan count, combined with the scan budget introduced in the previous commit to avoid livelock or under scan. - `scanned += try_to_inc_min_seq` in evict_folios: adding a bool as a scan count was kind of confusing and no longer needed to, as scan number should never be zero as long as there are still evictable gens. We may encounter a empty old gen that return 0 scan count, to avoid that, do a try_to_inc_min_seq before isolation which have slight to none overhead in most cases. - `evictable_min_seq + MIN_NR_GENS > max_seq` guard in evict_folios: the per-type get_nr_gens == MIN_NR_GENS check in scan_folios naturally returns 0 when only two gens remain and breaks the loop. Also change try_to_inc_min_seq to return void, as its return value is no longer used by any caller. Move the call before isolate_folios so that any empty gens created by external folio freeing are flushed, and add another call after isolate_folios to also flush empty gens that isolation itself may create. The scan still stops if there are only two gens left as the scan number will be zero, this behavior is same as before. This force gen protection may get removed or softened later to improve the reclaim a bit more. Signed-off-by: Kairui Song <kasong@tencent.com> Reviewed-by: Axel Rasmussen <axelrasmussen@google.com>
1 parent cab143a commit 83b6ba5

1 file changed

Lines changed: 30 additions & 30 deletions

File tree

mm/vmscan.c

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3896,10 +3896,9 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, int swappiness)
38963896
return true;
38973897
}
38983898

3899-
static bool try_to_inc_min_seq(struct lruvec *lruvec, int swappiness)
3899+
static void try_to_inc_min_seq(struct lruvec *lruvec, int swappiness)
39003900
{
39013901
int gen, type, zone;
3902-
bool success = false;
39033902
bool seq_inc_flag = false;
39043903
struct lru_gen_folio *lrugen = &lruvec->lrugen;
39053904
DEFINE_MIN_SEQ(lruvec);
@@ -3925,11 +3924,10 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, int swappiness)
39253924

39263925
/*
39273926
* If min_seq[type] of both anonymous and file is not increased,
3928-
* we can directly return false to avoid unnecessary checking
3929-
* overhead later.
3927+
* return here to avoid unnecessary checking overhead later.
39303928
*/
39313929
if (!seq_inc_flag)
3932-
return success;
3930+
return;
39333931

39343932
/* see the comment on lru_gen_folio */
39353933
if (swappiness && swappiness <= MAX_SWAPPINESS) {
@@ -3947,10 +3945,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, int swappiness)
39473945

39483946
reset_ctrl_pos(lruvec, type, true);
39493947
WRITE_ONCE(lrugen->min_seq[type], min_seq[type]);
3950-
success = true;
39513948
}
3952-
3953-
return success;
39543949
}
39553950

39563951
static bool inc_max_seq(struct lruvec *lruvec, unsigned long seq, int swappiness)
@@ -4545,7 +4540,7 @@ static bool isolate_folio(struct lruvec *lruvec, struct folio *folio, struct sca
45454540

45464541
static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
45474542
struct scan_control *sc, int type, int tier,
4548-
struct list_head *list)
4543+
struct list_head *list, int *isolatedp)
45494544
{
45504545
int i;
45514546
int gen;
@@ -4620,11 +4615,9 @@ static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
46204615
type ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON);
46214616
if (type == LRU_GEN_FILE)
46224617
sc->nr.file_taken += isolated;
4623-
/*
4624-
* There might not be eligible folios due to reclaim_idx. Check the
4625-
* remaining to prevent livelock if it's not making progress.
4626-
*/
4627-
return isolated || !remaining ? scanned : 0;
4618+
4619+
*isolatedp = isolated;
4620+
return scanned;
46284621
}
46294622

46304623
static int get_tier_idx(struct lruvec *lruvec, int type)
@@ -4668,53 +4661,60 @@ static int get_type_to_scan(struct lruvec *lruvec, int swappiness)
46684661

46694662
static int isolate_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
46704663
struct scan_control *sc, int swappiness,
4671-
int *type_scanned, struct list_head *list)
4664+
struct list_head *list, int *isolated,
4665+
int *isolate_type, int *isolate_scanned)
46724666
{
46734667
int i;
4668+
int scanned = 0;
46744669
int type = get_type_to_scan(lruvec, swappiness);
46754670

46764671
for_each_evictable_type(i, swappiness) {
4677-
int scanned;
4672+
int type_scan;
46784673
int tier = get_tier_idx(lruvec, type);
46794674

4680-
*type_scanned = type;
4675+
type_scan = scan_folios(nr_to_scan, lruvec, sc,
4676+
type, tier, list, isolated);
46814677

4682-
scanned = scan_folios(nr_to_scan, lruvec, sc, type, tier, list);
4683-
if (scanned)
4684-
return scanned;
4678+
scanned += type_scan;
4679+
if (*isolated) {
4680+
*isolate_type = type;
4681+
*isolate_scanned = type_scan;
4682+
break;
4683+
}
46854684

46864685
type = !type;
46874686
}
46884687

4689-
return 0;
4688+
return scanned;
46904689
}
46914690

46924691
static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
46934692
struct scan_control *sc, int swappiness)
46944693
{
4695-
int type;
4696-
int scanned;
4697-
int reclaimed;
46984694
LIST_HEAD(list);
46994695
LIST_HEAD(clean);
47004696
struct folio *folio;
47014697
struct folio *next;
47024698
enum vm_event_item item;
47034699
struct reclaim_stat stat;
47044700
struct lru_gen_mm_walk *walk;
4701+
int scanned, reclaimed;
4702+
int isolated = 0, type, type_scanned;
47054703
bool skip_retry = false;
4706-
struct lru_gen_folio *lrugen = &lruvec->lrugen;
47074704
struct mem_cgroup *memcg = lruvec_memcg(lruvec);
47084705
struct pglist_data *pgdat = lruvec_pgdat(lruvec);
47094706

47104707
spin_lock_irq(&lruvec->lru_lock);
47114708

4712-
scanned = isolate_folios(nr_to_scan, lruvec, sc, swappiness, &type, &list);
4709+
/* In case folio deletion left empty old gens, flush them */
4710+
try_to_inc_min_seq(lruvec, swappiness);
47134711

4714-
scanned += try_to_inc_min_seq(lruvec, swappiness);
4712+
scanned = isolate_folios(nr_to_scan, lruvec, sc, swappiness,
4713+
&list, &isolated, &type, &type_scanned);
47154714

4716-
if (evictable_min_seq(lrugen->min_seq, swappiness) + MIN_NR_GENS > lrugen->max_seq)
4717-
scanned = 0;
4715+
/* Isolation might create empty gen, flush them */
4716+
if (scanned)
4717+
try_to_inc_min_seq(lruvec, swappiness);
47184718

47194719
spin_unlock_irq(&lruvec->lru_lock);
47204720

@@ -4725,7 +4725,7 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
47254725
sc->nr.unqueued_dirty += stat.nr_unqueued_dirty;
47264726
sc->nr_reclaimed += reclaimed;
47274727
trace_mm_vmscan_lru_shrink_inactive(pgdat->node_id,
4728-
scanned, reclaimed, &stat, sc->priority,
4728+
type_scanned, reclaimed, &stat, sc->priority,
47294729
type ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON);
47304730

47314731
list_for_each_entry_safe_reverse(folio, next, &list, lru) {

0 commit comments

Comments
 (0)