Skip to content

Commit e267992

Browse files
committed
Merge branch 'for-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu
Pull percpu updates from Dennis Zhou: - percpu chunk depopulation - depopulate backing pages for chunks with empty pages when we exceed a global threshold without those pages. This lets us reclaim a portion of memory that would previously be lost until the full chunk would be freed (possibly never). - memcg accounting cleanup - previously separate chunks were managed for normal allocations and __GFP_ACCOUNT allocations. These are now consolidated which cleans up the code quite a bit. - a few misc clean ups for clang warnings * 'for-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu: percpu: optimize locking in pcpu_balance_workfn() percpu: initialize best_upa variable percpu: rework memcg accounting mm, memcg: introduce mem_cgroup_kmem_disabled() mm, memcg: mark cgroup_memory_nosocket, nokmem and noswap as __ro_after_init percpu: make symbol 'pcpu_free_slot' static percpu: implement partial chunk depopulation percpu: use pcpu_free_slot instead of pcpu_nr_slots - 1 percpu: factor out pcpu_check_block_hint() percpu: split __pcpu_balance_workfn() percpu: fix a comment about the chunks ordering
2 parents 19b4385 + e4d7770 commit e267992

File tree

7 files changed

+343
-186
lines changed

7 files changed

+343
-186
lines changed

include/linux/memcontrol.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,6 +1619,7 @@ static inline void set_shrinker_bit(struct mem_cgroup *memcg,
16191619
#endif
16201620

16211621
#ifdef CONFIG_MEMCG_KMEM
1622+
bool mem_cgroup_kmem_disabled(void);
16221623
int __memcg_kmem_charge_page(struct page *page, gfp_t gfp, int order);
16231624
void __memcg_kmem_uncharge_page(struct page *page, int order);
16241625

@@ -1672,6 +1673,10 @@ static inline int memcg_cache_id(struct mem_cgroup *memcg)
16721673
struct mem_cgroup *mem_cgroup_from_obj(void *p);
16731674

16741675
#else
1676+
static inline bool mem_cgroup_kmem_disabled(void)
1677+
{
1678+
return true;
1679+
}
16751680

16761681
static inline int memcg_kmem_charge_page(struct page *page, gfp_t gfp,
16771682
int order)

mm/memcontrol.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,14 @@ DEFINE_PER_CPU(struct mem_cgroup *, int_active_memcg);
8181
EXPORT_PER_CPU_SYMBOL_GPL(int_active_memcg);
8282

8383
/* Socket memory accounting disabled? */
84-
static bool cgroup_memory_nosocket;
84+
static bool cgroup_memory_nosocket __ro_after_init;
8585

8686
/* Kernel memory accounting disabled? */
87-
bool cgroup_memory_nokmem;
87+
bool cgroup_memory_nokmem __ro_after_init;
8888

8989
/* Whether the swap controller is active */
9090
#ifdef CONFIG_MEMCG_SWAP
91-
bool cgroup_memory_noswap __read_mostly;
91+
bool cgroup_memory_noswap __ro_after_init;
9292
#else
9393
#define cgroup_memory_noswap 1
9494
#endif
@@ -256,6 +256,11 @@ struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr)
256256
#ifdef CONFIG_MEMCG_KMEM
257257
extern spinlock_t css_set_lock;
258258

259+
bool mem_cgroup_kmem_disabled(void)
260+
{
261+
return cgroup_memory_nokmem;
262+
}
263+
259264
static void obj_cgroup_uncharge_pages(struct obj_cgroup *objcg,
260265
unsigned int nr_pages);
261266

mm/percpu-internal.h

Lines changed: 5 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,6 @@
55
#include <linux/types.h>
66
#include <linux/percpu.h>
77

8-
/*
9-
* There are two chunk types: root and memcg-aware.
10-
* Chunks of each type have separate slots list.
11-
*
12-
* Memcg-aware chunks have an attached vector of obj_cgroup pointers, which is
13-
* used to store memcg membership data of a percpu object. Obj_cgroups are
14-
* ref-counted pointers to a memory cgroup with an ability to switch dynamically
15-
* to the parent memory cgroup. This allows to reclaim a deleted memory cgroup
16-
* without reclaiming of all outstanding objects, which hold a reference at it.
17-
*/
18-
enum pcpu_chunk_type {
19-
PCPU_CHUNK_ROOT,
20-
#ifdef CONFIG_MEMCG_KMEM
21-
PCPU_CHUNK_MEMCG,
22-
#endif
23-
PCPU_NR_CHUNK_TYPES,
24-
PCPU_FAIL_ALLOC = PCPU_NR_CHUNK_TYPES
25-
};
26-
278
/*
289
* pcpu_block_md is the metadata block struct.
2910
* Each chunk's bitmap is split into a number of full blocks.
@@ -67,6 +48,8 @@ struct pcpu_chunk {
6748

6849
void *data; /* chunk data */
6950
bool immutable; /* no [de]population allowed */
51+
bool isolated; /* isolated from active chunk
52+
slots */
7053
int start_offset; /* the overlap with the previous
7154
region to have a page aligned
7255
base_addr */
@@ -87,7 +70,9 @@ extern spinlock_t pcpu_lock;
8770

8871
extern struct list_head *pcpu_chunk_lists;
8972
extern int pcpu_nr_slots;
90-
extern int pcpu_nr_empty_pop_pages[];
73+
extern int pcpu_sidelined_slot;
74+
extern int pcpu_to_depopulate_slot;
75+
extern int pcpu_nr_empty_pop_pages;
9176

9277
extern struct pcpu_chunk *pcpu_first_chunk;
9378
extern struct pcpu_chunk *pcpu_reserved_chunk;
@@ -128,37 +113,6 @@ static inline int pcpu_chunk_map_bits(struct pcpu_chunk *chunk)
128113
return pcpu_nr_pages_to_map_bits(chunk->nr_pages);
129114
}
130115

131-
#ifdef CONFIG_MEMCG_KMEM
132-
static inline enum pcpu_chunk_type pcpu_chunk_type(struct pcpu_chunk *chunk)
133-
{
134-
if (chunk->obj_cgroups)
135-
return PCPU_CHUNK_MEMCG;
136-
return PCPU_CHUNK_ROOT;
137-
}
138-
139-
static inline bool pcpu_is_memcg_chunk(enum pcpu_chunk_type chunk_type)
140-
{
141-
return chunk_type == PCPU_CHUNK_MEMCG;
142-
}
143-
144-
#else
145-
static inline enum pcpu_chunk_type pcpu_chunk_type(struct pcpu_chunk *chunk)
146-
{
147-
return PCPU_CHUNK_ROOT;
148-
}
149-
150-
static inline bool pcpu_is_memcg_chunk(enum pcpu_chunk_type chunk_type)
151-
{
152-
return false;
153-
}
154-
#endif
155-
156-
static inline struct list_head *pcpu_chunk_list(enum pcpu_chunk_type chunk_type)
157-
{
158-
return &pcpu_chunk_lists[pcpu_nr_slots *
159-
pcpu_is_memcg_chunk(chunk_type)];
160-
}
161-
162116
#ifdef CONFIG_PERCPU_STATS
163117

164118
#include <linux/spinlock.h>

mm/percpu-km.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,15 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk,
4444
/* nada */
4545
}
4646

47-
static struct pcpu_chunk *pcpu_create_chunk(enum pcpu_chunk_type type,
48-
gfp_t gfp)
47+
static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp)
4948
{
5049
const int nr_pages = pcpu_group_sizes[0] >> PAGE_SHIFT;
5150
struct pcpu_chunk *chunk;
5251
struct page *pages;
5352
unsigned long flags;
5453
int i;
5554

56-
chunk = pcpu_alloc_chunk(type, gfp);
55+
chunk = pcpu_alloc_chunk(gfp);
5756
if (!chunk)
5857
return NULL;
5958

@@ -118,3 +117,8 @@ static int __init pcpu_verify_alloc_info(const struct pcpu_alloc_info *ai)
118117

119118
return 0;
120119
}
120+
121+
static bool pcpu_should_reclaim_chunk(struct pcpu_chunk *chunk)
122+
{
123+
return false;
124+
}

mm/percpu-stats.c

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,11 @@ static int find_max_nr_alloc(void)
3434
{
3535
struct pcpu_chunk *chunk;
3636
int slot, max_nr_alloc;
37-
enum pcpu_chunk_type type;
3837

3938
max_nr_alloc = 0;
40-
for (type = 0; type < PCPU_NR_CHUNK_TYPES; type++)
41-
for (slot = 0; slot < pcpu_nr_slots; slot++)
42-
list_for_each_entry(chunk, &pcpu_chunk_list(type)[slot],
43-
list)
44-
max_nr_alloc = max(max_nr_alloc,
45-
chunk->nr_alloc);
39+
for (slot = 0; slot < pcpu_nr_slots; slot++)
40+
list_for_each_entry(chunk, &pcpu_chunk_lists[slot], list)
41+
max_nr_alloc = max(max_nr_alloc, chunk->nr_alloc);
4642

4743
return max_nr_alloc;
4844
}
@@ -133,9 +129,6 @@ static void chunk_map_stats(struct seq_file *m, struct pcpu_chunk *chunk,
133129
P("cur_min_alloc", cur_min_alloc);
134130
P("cur_med_alloc", cur_med_alloc);
135131
P("cur_max_alloc", cur_max_alloc);
136-
#ifdef CONFIG_MEMCG_KMEM
137-
P("memcg_aware", pcpu_is_memcg_chunk(pcpu_chunk_type(chunk)));
138-
#endif
139132
seq_putc(m, '\n');
140133
}
141134

@@ -144,8 +137,6 @@ static int percpu_stats_show(struct seq_file *m, void *v)
144137
struct pcpu_chunk *chunk;
145138
int slot, max_nr_alloc;
146139
int *buffer;
147-
enum pcpu_chunk_type type;
148-
int nr_empty_pop_pages;
149140

150141
alloc_buffer:
151142
spin_lock_irq(&pcpu_lock);
@@ -166,10 +157,6 @@ static int percpu_stats_show(struct seq_file *m, void *v)
166157
goto alloc_buffer;
167158
}
168159

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-
173160
#define PL(X) \
174161
seq_printf(m, " %-20s: %12lld\n", #X, (long long int)pcpu_stats_ai.X)
175162

@@ -201,7 +188,7 @@ static int percpu_stats_show(struct seq_file *m, void *v)
201188
PU(nr_max_chunks);
202189
PU(min_alloc_size);
203190
PU(max_alloc_size);
204-
P("empty_pop_pages", nr_empty_pop_pages);
191+
P("empty_pop_pages", pcpu_nr_empty_pop_pages);
205192
seq_putc(m, '\n');
206193

207194
#undef PU
@@ -215,18 +202,17 @@ static int percpu_stats_show(struct seq_file *m, void *v)
215202
chunk_map_stats(m, pcpu_reserved_chunk, buffer);
216203
}
217204

218-
for (type = 0; type < PCPU_NR_CHUNK_TYPES; type++) {
219-
for (slot = 0; slot < pcpu_nr_slots; slot++) {
220-
list_for_each_entry(chunk, &pcpu_chunk_list(type)[slot],
221-
list) {
222-
if (chunk == pcpu_first_chunk) {
223-
seq_puts(m, "Chunk: <- First Chunk\n");
224-
chunk_map_stats(m, chunk, buffer);
225-
} else {
226-
seq_puts(m, "Chunk:\n");
227-
chunk_map_stats(m, chunk, buffer);
228-
}
229-
}
205+
for (slot = 0; slot < pcpu_nr_slots; slot++) {
206+
list_for_each_entry(chunk, &pcpu_chunk_lists[slot], list) {
207+
if (chunk == pcpu_first_chunk)
208+
seq_puts(m, "Chunk: <- First Chunk\n");
209+
else if (slot == pcpu_to_depopulate_slot)
210+
seq_puts(m, "Chunk (to_depopulate)\n");
211+
else if (slot == pcpu_sidelined_slot)
212+
seq_puts(m, "Chunk (sidelined):\n");
213+
else
214+
seq_puts(m, "Chunk:\n");
215+
chunk_map_stats(m, chunk, buffer);
230216
}
231217
}
232218

mm/percpu-vm.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -329,13 +329,12 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk,
329329
pcpu_free_pages(chunk, pages, page_start, page_end);
330330
}
331331

332-
static struct pcpu_chunk *pcpu_create_chunk(enum pcpu_chunk_type type,
333-
gfp_t gfp)
332+
static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp)
334333
{
335334
struct pcpu_chunk *chunk;
336335
struct vm_struct **vms;
337336

338-
chunk = pcpu_alloc_chunk(type, gfp);
337+
chunk = pcpu_alloc_chunk(gfp);
339338
if (!chunk)
340339
return NULL;
341340

@@ -378,3 +377,33 @@ static int __init pcpu_verify_alloc_info(const struct pcpu_alloc_info *ai)
378377
/* no extra restriction */
379378
return 0;
380379
}
380+
381+
/**
382+
* pcpu_should_reclaim_chunk - determine if a chunk should go into reclaim
383+
* @chunk: chunk of interest
384+
*
385+
* This is the entry point for percpu reclaim. If a chunk qualifies, it is then
386+
* isolated and managed in separate lists at the back of pcpu_slot: sidelined
387+
* and to_depopulate respectively. The to_depopulate list holds chunks slated
388+
* for depopulation. They no longer contribute to pcpu_nr_empty_pop_pages once
389+
* they are on this list. Once depopulated, they are moved onto the sidelined
390+
* list which enables them to be pulled back in for allocation if no other chunk
391+
* can suffice the allocation.
392+
*/
393+
static bool pcpu_should_reclaim_chunk(struct pcpu_chunk *chunk)
394+
{
395+
/* do not reclaim either the first chunk or reserved chunk */
396+
if (chunk == pcpu_first_chunk || chunk == pcpu_reserved_chunk)
397+
return false;
398+
399+
/*
400+
* If it is isolated, it may be on the sidelined list so move it back to
401+
* the to_depopulate list. If we hit at least 1/4 pages empty pages AND
402+
* there is no system-wide shortage of empty pages aside from this
403+
* chunk, move it to the to_depopulate list.
404+
*/
405+
return ((chunk->isolated && chunk->nr_empty_pop_pages) ||
406+
(pcpu_nr_empty_pop_pages >
407+
(PCPU_EMPTY_POP_PAGES_HIGH + chunk->nr_empty_pop_pages) &&
408+
chunk->nr_empty_pop_pages >= chunk->nr_pages / 4));
409+
}

0 commit comments

Comments
 (0)