Commit 52e44129 authored by Linus Torvalds's avatar Linus Torvalds

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/20210324190626.564297-1-guro@fb.com/ [1]
Link: https://lore.kernel.org/linux-mm/20210401185158.3275.409509F4@e16-tech.com/ [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
parents efc2da92 0760fa3d
...@@ -87,7 +87,7 @@ extern spinlock_t pcpu_lock; ...@@ -87,7 +87,7 @@ extern spinlock_t pcpu_lock;
extern struct list_head *pcpu_chunk_lists; extern struct list_head *pcpu_chunk_lists;
extern int pcpu_nr_slots; extern int pcpu_nr_slots;
extern int pcpu_nr_empty_pop_pages; extern int pcpu_nr_empty_pop_pages[];
extern struct pcpu_chunk *pcpu_first_chunk; extern struct pcpu_chunk *pcpu_first_chunk;
extern struct pcpu_chunk *pcpu_reserved_chunk; extern struct pcpu_chunk *pcpu_reserved_chunk;
......
...@@ -145,6 +145,7 @@ static int percpu_stats_show(struct seq_file *m, void *v) ...@@ -145,6 +145,7 @@ static int percpu_stats_show(struct seq_file *m, void *v)
int slot, max_nr_alloc; int slot, max_nr_alloc;
int *buffer; int *buffer;
enum pcpu_chunk_type type; enum pcpu_chunk_type type;
int nr_empty_pop_pages;
alloc_buffer: alloc_buffer:
spin_lock_irq(&pcpu_lock); spin_lock_irq(&pcpu_lock);
...@@ -165,7 +166,11 @@ static int percpu_stats_show(struct seq_file *m, void *v) ...@@ -165,7 +166,11 @@ static int percpu_stats_show(struct seq_file *m, void *v)
goto alloc_buffer; goto alloc_buffer;
} }
#define PL(X) \ nr_empty_pop_pages = 0;
for (type = 0; type < PCPU_NR_CHUNK_TYPES; type++)
nr_empty_pop_pages += pcpu_nr_empty_pop_pages[type];
#define PL(X) \
seq_printf(m, " %-20s: %12lld\n", #X, (long long int)pcpu_stats_ai.X) seq_printf(m, " %-20s: %12lld\n", #X, (long long int)pcpu_stats_ai.X)
seq_printf(m, seq_printf(m,
...@@ -196,7 +201,7 @@ static int percpu_stats_show(struct seq_file *m, void *v) ...@@ -196,7 +201,7 @@ static int percpu_stats_show(struct seq_file *m, void *v)
PU(nr_max_chunks); PU(nr_max_chunks);
PU(min_alloc_size); PU(min_alloc_size);
PU(max_alloc_size); PU(max_alloc_size);
P("empty_pop_pages", pcpu_nr_empty_pop_pages); P("empty_pop_pages", nr_empty_pop_pages);
seq_putc(m, '\n'); seq_putc(m, '\n');
#undef PU #undef PU
......
...@@ -173,10 +173,10 @@ struct list_head *pcpu_chunk_lists __ro_after_init; /* chunk list slots */ ...@@ -173,10 +173,10 @@ struct list_head *pcpu_chunk_lists __ro_after_init; /* chunk list slots */
static LIST_HEAD(pcpu_map_extend_chunks); static LIST_HEAD(pcpu_map_extend_chunks);
/* /*
* The number of empty populated pages, protected by pcpu_lock. The * The number of empty populated pages by chunk type, protected by pcpu_lock.
* reserved chunk doesn't contribute to the count. * The reserved chunk doesn't contribute to the count.
*/ */
int pcpu_nr_empty_pop_pages; int pcpu_nr_empty_pop_pages[PCPU_NR_CHUNK_TYPES];
/* /*
* The number of populated pages in use by the allocator, protected by * 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) ...@@ -556,7 +556,7 @@ static inline void pcpu_update_empty_pages(struct pcpu_chunk *chunk, int nr)
{ {
chunk->nr_empty_pop_pages += nr; chunk->nr_empty_pop_pages += nr;
if (chunk != pcpu_reserved_chunk) if (chunk != pcpu_reserved_chunk)
pcpu_nr_empty_pop_pages += nr; pcpu_nr_empty_pop_pages[pcpu_chunk_type(chunk)] += nr;
} }
/* /*
...@@ -1832,7 +1832,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved, ...@@ -1832,7 +1832,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
mutex_unlock(&pcpu_alloc_mutex); mutex_unlock(&pcpu_alloc_mutex);
} }
if (pcpu_nr_empty_pop_pages < PCPU_EMPTY_POP_PAGES_LOW) if (pcpu_nr_empty_pop_pages[type] < PCPU_EMPTY_POP_PAGES_LOW)
pcpu_schedule_balance_work(); pcpu_schedule_balance_work();
/* clear the areas and return address relative to base address */ /* clear the areas and return address relative to base address */
...@@ -2000,7 +2000,7 @@ static void __pcpu_balance_workfn(enum pcpu_chunk_type type) ...@@ -2000,7 +2000,7 @@ static void __pcpu_balance_workfn(enum pcpu_chunk_type type)
pcpu_atomic_alloc_failed = false; pcpu_atomic_alloc_failed = false;
} else { } else {
nr_to_pop = clamp(PCPU_EMPTY_POP_PAGES_HIGH - nr_to_pop = clamp(PCPU_EMPTY_POP_PAGES_HIGH -
pcpu_nr_empty_pop_pages, pcpu_nr_empty_pop_pages[type],
0, PCPU_EMPTY_POP_PAGES_HIGH); 0, PCPU_EMPTY_POP_PAGES_HIGH);
} }
...@@ -2580,7 +2580,7 @@ void __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, ...@@ -2580,7 +2580,7 @@ void __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
/* link the first chunk in */ /* link the first chunk in */
pcpu_first_chunk = chunk; pcpu_first_chunk = chunk;
pcpu_nr_empty_pop_pages = pcpu_first_chunk->nr_empty_pop_pages; pcpu_nr_empty_pop_pages[PCPU_CHUNK_ROOT] = pcpu_first_chunk->nr_empty_pop_pages;
pcpu_chunk_relocate(pcpu_first_chunk, -1); pcpu_chunk_relocate(pcpu_first_chunk, -1);
/* include all regions of the first chunk */ /* include all regions of the first chunk */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment