Skip to content

Commit 52e4412

Browse files
committed
Merge branch 'for-5.12-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu
Pull percpu fix from Dennis Zhou: "This contains a fix for sporadically failing atomic percpu allocations. I only caught it recently while I was reviewing a new series [1] and simultaneously saw reports by btrfs in xfstests [2] and [3]. In v5.9, memcg accounting was extended to percpu done by adding a second type of chunk. I missed an interaction with the free page float count used to ensure we can support atomic allocations. If one type of chunk has no free pages, but the other has enough to satisfy the free page float requirement, we will not repopulate the free pages for the former type of chunk. This led to the sporadically failing atomic allocations" Link: https://lore.kernel.org/linux-mm/[email protected]/ [1] Link: https://lore.kernel.org/linux-mm/[email protected]/ [2] Link: https://lore.kernel.org/linux-mm/CAL3q7H5RNBjCi708GH7jnczAOe0BLnacT9C+OBgA-Dx9jhB6SQ@mail.gmail.com/ [3] * 'for-5.12-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu: percpu: make pcpu_nr_empty_pop_pages per chunk type
2 parents efc2da9 + 0760fa3 commit 52e4412

File tree

3 files changed

+15
-10
lines changed

3 files changed

+15
-10
lines changed

mm/percpu-internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ extern spinlock_t pcpu_lock;
8787

8888
extern struct list_head *pcpu_chunk_lists;
8989
extern int pcpu_nr_slots;
90-
extern int pcpu_nr_empty_pop_pages;
90+
extern int pcpu_nr_empty_pop_pages[];
9191

9292
extern struct pcpu_chunk *pcpu_first_chunk;
9393
extern struct pcpu_chunk *pcpu_reserved_chunk;

mm/percpu-stats.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ static int percpu_stats_show(struct seq_file *m, void *v)
145145
int slot, max_nr_alloc;
146146
int *buffer;
147147
enum pcpu_chunk_type type;
148+
int nr_empty_pop_pages;
148149

149150
alloc_buffer:
150151
spin_lock_irq(&pcpu_lock);
@@ -165,7 +166,11 @@ static int percpu_stats_show(struct seq_file *m, void *v)
165166
goto alloc_buffer;
166167
}
167168

168-
#define PL(X) \
169+
nr_empty_pop_pages = 0;
170+
for (type = 0; type < PCPU_NR_CHUNK_TYPES; type++)
171+
nr_empty_pop_pages += pcpu_nr_empty_pop_pages[type];
172+
173+
#define PL(X) \
169174
seq_printf(m, " %-20s: %12lld\n", #X, (long long int)pcpu_stats_ai.X)
170175

171176
seq_printf(m,
@@ -196,7 +201,7 @@ static int percpu_stats_show(struct seq_file *m, void *v)
196201
PU(nr_max_chunks);
197202
PU(min_alloc_size);
198203
PU(max_alloc_size);
199-
P("empty_pop_pages", pcpu_nr_empty_pop_pages);
204+
P("empty_pop_pages", nr_empty_pop_pages);
200205
seq_putc(m, '\n');
201206

202207
#undef PU

mm/percpu.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,10 @@ struct list_head *pcpu_chunk_lists __ro_after_init; /* chunk list slots */
173173
static LIST_HEAD(pcpu_map_extend_chunks);
174174

175175
/*
176-
* The number of empty populated pages, protected by pcpu_lock. The
177-
* reserved chunk doesn't contribute to the count.
176+
* The number of empty populated pages by chunk type, protected by pcpu_lock.
177+
* The reserved chunk doesn't contribute to the count.
178178
*/
179-
int pcpu_nr_empty_pop_pages;
179+
int pcpu_nr_empty_pop_pages[PCPU_NR_CHUNK_TYPES];
180180

181181
/*
182182
* The number of populated pages in use by the allocator, protected by
@@ -556,7 +556,7 @@ static inline void pcpu_update_empty_pages(struct pcpu_chunk *chunk, int nr)
556556
{
557557
chunk->nr_empty_pop_pages += nr;
558558
if (chunk != pcpu_reserved_chunk)
559-
pcpu_nr_empty_pop_pages += nr;
559+
pcpu_nr_empty_pop_pages[pcpu_chunk_type(chunk)] += nr;
560560
}
561561

562562
/*
@@ -1832,7 +1832,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
18321832
mutex_unlock(&pcpu_alloc_mutex);
18331833
}
18341834

1835-
if (pcpu_nr_empty_pop_pages < PCPU_EMPTY_POP_PAGES_LOW)
1835+
if (pcpu_nr_empty_pop_pages[type] < PCPU_EMPTY_POP_PAGES_LOW)
18361836
pcpu_schedule_balance_work();
18371837

18381838
/* clear the areas and return address relative to base address */
@@ -2000,7 +2000,7 @@ static void __pcpu_balance_workfn(enum pcpu_chunk_type type)
20002000
pcpu_atomic_alloc_failed = false;
20012001
} else {
20022002
nr_to_pop = clamp(PCPU_EMPTY_POP_PAGES_HIGH -
2003-
pcpu_nr_empty_pop_pages,
2003+
pcpu_nr_empty_pop_pages[type],
20042004
0, PCPU_EMPTY_POP_PAGES_HIGH);
20052005
}
20062006

@@ -2580,7 +2580,7 @@ void __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
25802580

25812581
/* link the first chunk in */
25822582
pcpu_first_chunk = chunk;
2583-
pcpu_nr_empty_pop_pages = pcpu_first_chunk->nr_empty_pop_pages;
2583+
pcpu_nr_empty_pop_pages[PCPU_CHUNK_ROOT] = pcpu_first_chunk->nr_empty_pop_pages;
25842584
pcpu_chunk_relocate(pcpu_first_chunk, -1);
25852585

25862586
/* include all regions of the first chunk */

0 commit comments

Comments
 (0)