Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: memcg/percpu: account percpu memory to memory cgroups

Percpu memory is becoming more and more widely used by various subsystems,
and the total amount of memory controlled by the percpu allocator can make
a good part of the total memory.

As an example, bpf maps can consume a lot of percpu memory, and they are
created by a user. Also, some cgroup internals (e.g. memory controller
statistics) can be quite large. On a machine with many CPUs and big
number of cgroups they can consume hundreds of megabytes.

So the lack of memcg accounting is creating a breach in the memory
isolation. Similar to the slab memory, percpu memory should be accounted
by default.

To implement the perpcu accounting it's possible to take the slab memory
accounting as a model to follow. Let's introduce two types of percpu
chunks: root and memcg. What makes memcg chunks different is an
additional space allocated to store memcg membership information. If
__GFP_ACCOUNT is passed on allocation, a memcg chunk should be be used.
If it's possible to charge the corresponding size to the target memory
cgroup, allocation is performed, and the memcg ownership data is recorded.
System-wide allocations are performed using root chunks, so there is no
additional memory overhead.

To implement a fast reparenting of percpu memory on memcg removal, we
don't store mem_cgroup pointers directly: instead we use obj_cgroup API,
introduced for slab accounting.

[akpm@linux-foundation.org: fix CONFIG_MEMCG_KMEM=n build errors and warning]
[akpm@linux-foundation.org: move unreachable code, per Roman]
[cuibixuan@huawei.com: mm/percpu: fix 'defined but not used' warning]
Link: http://lkml.kernel.org/r/6d41b939-a741-b521-a7a2-e7296ec16219@huawei.com

Signed-off-by: Roman Gushchin <guro@fb.com>
Signed-off-by: Bixuan Cui <cuibixuan@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Shakeel Butt <shakeelb@google.com>
Acked-by: Dennis Zhou <dennis@kernel.org>
Cc: Christoph Lameter <cl@linux.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: Tobin C. Harding <tobin@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Waiman Long <longman@redhat.com>
Cc: Bixuan Cui <cuibixuan@huawei.com>
Cc: Michal Koutný <mkoutny@suse.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Link: http://lkml.kernel.org/r/20200623184515.4132564-3-guro@fb.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Roman Gushchin and committed by
Linus Torvalds
3c7be18a 5b32af91

+246 -40
+54 -1
mm/percpu-internal.h
··· 6 6 #include <linux/percpu.h> 7 7 8 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 + 27 + /* 9 28 * pcpu_block_md is the metadata block struct. 10 29 * Each chunk's bitmap is split into a number of full blocks. 11 30 * All units are in terms of bits. ··· 73 54 int end_offset; /* additional area required to 74 55 have the region end page 75 56 aligned */ 57 + #ifdef CONFIG_MEMCG_KMEM 58 + struct obj_cgroup **obj_cgroups; /* vector of object cgroups */ 59 + #endif 76 60 77 61 int nr_pages; /* # of pages served by this chunk */ 78 62 int nr_populated; /* # of populated pages */ ··· 85 63 86 64 extern spinlock_t pcpu_lock; 87 65 88 - extern struct list_head *pcpu_slot; 66 + extern struct list_head *pcpu_chunk_lists; 89 67 extern int pcpu_nr_slots; 90 68 extern int pcpu_nr_empty_pop_pages; 91 69 ··· 126 104 static inline int pcpu_chunk_map_bits(struct pcpu_chunk *chunk) 127 105 { 128 106 return pcpu_nr_pages_to_map_bits(chunk->nr_pages); 107 + } 108 + 109 + #ifdef CONFIG_MEMCG_KMEM 110 + static inline enum pcpu_chunk_type pcpu_chunk_type(struct pcpu_chunk *chunk) 111 + { 112 + if (chunk->obj_cgroups) 113 + return PCPU_CHUNK_MEMCG; 114 + return PCPU_CHUNK_ROOT; 115 + } 116 + 117 + static inline bool pcpu_is_memcg_chunk(enum pcpu_chunk_type chunk_type) 118 + { 119 + return chunk_type == PCPU_CHUNK_MEMCG; 120 + } 121 + 122 + #else 123 + static inline enum pcpu_chunk_type pcpu_chunk_type(struct pcpu_chunk *chunk) 124 + { 125 + return PCPU_CHUNK_ROOT; 126 + } 127 + 128 + static inline bool pcpu_is_memcg_chunk(enum pcpu_chunk_type chunk_type) 129 + { 130 + return false; 131 + } 132 + #endif 133 + 134 + static inline struct list_head *pcpu_chunk_list(enum pcpu_chunk_type chunk_type) 135 + { 136 + return &pcpu_chunk_lists[pcpu_nr_slots * 137 + pcpu_is_memcg_chunk(chunk_type)]; 129 138 } 130 139 131 140 #ifdef CONFIG_PERCPU_STATS
+3 -2
mm/percpu-km.c
··· 44 44 /* nada */ 45 45 } 46 46 47 - static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp) 47 + static struct pcpu_chunk *pcpu_create_chunk(enum pcpu_chunk_type type, 48 + gfp_t gfp) 48 49 { 49 50 const int nr_pages = pcpu_group_sizes[0] >> PAGE_SHIFT; 50 51 struct pcpu_chunk *chunk; ··· 53 52 unsigned long flags; 54 53 int i; 55 54 56 - chunk = pcpu_alloc_chunk(gfp); 55 + chunk = pcpu_alloc_chunk(type, gfp); 57 56 if (!chunk) 58 57 return NULL; 59 58
+22 -14
mm/percpu-stats.c
··· 34 34 { 35 35 struct pcpu_chunk *chunk; 36 36 int slot, max_nr_alloc; 37 + enum pcpu_chunk_type type; 37 38 38 39 max_nr_alloc = 0; 39 - for (slot = 0; slot < pcpu_nr_slots; slot++) 40 - list_for_each_entry(chunk, &pcpu_slot[slot], list) 41 - max_nr_alloc = max(max_nr_alloc, chunk->nr_alloc); 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); 42 46 43 47 return max_nr_alloc; 44 48 } ··· 133 129 P("cur_min_alloc", cur_min_alloc); 134 130 P("cur_med_alloc", cur_med_alloc); 135 131 P("cur_max_alloc", cur_max_alloc); 132 + #ifdef CONFIG_MEMCG_KMEM 133 + P("memcg_aware", pcpu_is_memcg_chunk(pcpu_chunk_type(chunk))); 134 + #endif 136 135 seq_putc(m, '\n'); 137 136 } 138 137 ··· 144 137 struct pcpu_chunk *chunk; 145 138 int slot, max_nr_alloc; 146 139 int *buffer; 140 + enum pcpu_chunk_type type; 147 141 148 142 alloc_buffer: 149 143 spin_lock_irq(&pcpu_lock); ··· 210 202 chunk_map_stats(m, pcpu_reserved_chunk, buffer); 211 203 } 212 204 213 - for (slot = 0; slot < pcpu_nr_slots; slot++) { 214 - list_for_each_entry(chunk, &pcpu_slot[slot], list) { 215 - if (chunk == pcpu_first_chunk) { 216 - seq_puts(m, "Chunk: <- First Chunk\n"); 217 - chunk_map_stats(m, chunk, buffer); 218 - 219 - 220 - } else { 221 - seq_puts(m, "Chunk:\n"); 222 - chunk_map_stats(m, chunk, buffer); 205 + for (type = 0; type < PCPU_NR_CHUNK_TYPES; type++) { 206 + for (slot = 0; slot < pcpu_nr_slots; slot++) { 207 + list_for_each_entry(chunk, &pcpu_chunk_list(type)[slot], 208 + list) { 209 + if (chunk == pcpu_first_chunk) { 210 + seq_puts(m, "Chunk: <- First Chunk\n"); 211 + chunk_map_stats(m, chunk, buffer); 212 + } else { 213 + seq_puts(m, "Chunk:\n"); 214 + chunk_map_stats(m, chunk, buffer); 215 + } 223 216 } 224 - 225 217 } 226 218 } 227 219
+3 -2
mm/percpu-vm.c
··· 328 328 pcpu_free_pages(chunk, pages, page_start, page_end); 329 329 } 330 330 331 - static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp) 331 + static struct pcpu_chunk *pcpu_create_chunk(enum pcpu_chunk_type type, 332 + gfp_t gfp) 332 333 { 333 334 struct pcpu_chunk *chunk; 334 335 struct vm_struct **vms; 335 336 336 - chunk = pcpu_alloc_chunk(gfp); 337 + chunk = pcpu_alloc_chunk(type, gfp); 337 338 if (!chunk) 338 339 return NULL; 339 340
+164 -21
mm/percpu.c
··· 37 37 * takes care of normal allocations. 38 38 * 39 39 * The allocator organizes chunks into lists according to free size and 40 - * tries to allocate from the fullest chunk first. Each chunk is managed 41 - * by a bitmap with metadata blocks. The allocation map is updated on 42 - * every allocation and free to reflect the current state while the boundary 40 + * memcg-awareness. To make a percpu allocation memcg-aware the __GFP_ACCOUNT 41 + * flag should be passed. All memcg-aware allocations are sharing one set 42 + * of chunks and all unaccounted allocations and allocations performed 43 + * by processes belonging to the root memory cgroup are using the second set. 44 + * 45 + * The allocator tries to allocate from the fullest chunk first. Each chunk 46 + * is managed by a bitmap with metadata blocks. The allocation map is updated 47 + * on every allocation and free to reflect the current state while the boundary 43 48 * map is only updated on allocation. Each metadata block contains 44 49 * information to help mitigate the need to iterate over large portions 45 50 * of the bitmap. The reverse mapping from page to chunk is stored in ··· 86 81 #include <linux/kmemleak.h> 87 82 #include <linux/sched.h> 88 83 #include <linux/sched/mm.h> 84 + #include <linux/memcontrol.h> 89 85 90 86 #include <asm/cacheflush.h> 91 87 #include <asm/sections.h> ··· 166 160 DEFINE_SPINLOCK(pcpu_lock); /* all internal data structures */ 167 161 static DEFINE_MUTEX(pcpu_alloc_mutex); /* chunk create/destroy, [de]pop, map ext */ 168 162 169 - struct list_head *pcpu_slot __ro_after_init; /* chunk list slots */ 163 + struct list_head *pcpu_chunk_lists __ro_after_init; /* chunk list slots */ 170 164 171 165 /* chunks which need their map areas extended, protected by pcpu_lock */ 172 166 static LIST_HEAD(pcpu_map_extend_chunks); ··· 506 500 bool move_front) 507 501 { 508 502 if (chunk != pcpu_reserved_chunk) { 503 + struct list_head *pcpu_slot; 504 + 505 + pcpu_slot = pcpu_chunk_list(pcpu_chunk_type(chunk)); 509 506 if (move_front) 510 507 list_move(&chunk->list, &pcpu_slot[slot]); 511 508 else ··· 1350 1341 panic("%s: Failed to allocate %zu bytes\n", __func__, 1351 1342 alloc_size); 1352 1343 1344 + #ifdef CONFIG_MEMCG_KMEM 1345 + /* first chunk isn't memcg-aware */ 1346 + chunk->obj_cgroups = NULL; 1347 + #endif 1353 1348 pcpu_init_md_blocks(chunk); 1354 1349 1355 1350 /* manage populated page bitmap */ ··· 1393 1380 return chunk; 1394 1381 } 1395 1382 1396 - static struct pcpu_chunk *pcpu_alloc_chunk(gfp_t gfp) 1383 + static struct pcpu_chunk *pcpu_alloc_chunk(enum pcpu_chunk_type type, gfp_t gfp) 1397 1384 { 1398 1385 struct pcpu_chunk *chunk; 1399 1386 int region_bits; ··· 1421 1408 if (!chunk->md_blocks) 1422 1409 goto md_blocks_fail; 1423 1410 1411 + #ifdef CONFIG_MEMCG_KMEM 1412 + if (pcpu_is_memcg_chunk(type)) { 1413 + chunk->obj_cgroups = 1414 + pcpu_mem_zalloc(pcpu_chunk_map_bits(chunk) * 1415 + sizeof(struct obj_cgroup *), gfp); 1416 + if (!chunk->obj_cgroups) 1417 + goto objcg_fail; 1418 + } 1419 + #endif 1420 + 1424 1421 pcpu_init_md_blocks(chunk); 1425 1422 1426 1423 /* init metadata */ ··· 1438 1415 1439 1416 return chunk; 1440 1417 1418 + #ifdef CONFIG_MEMCG_KMEM 1419 + objcg_fail: 1420 + pcpu_mem_free(chunk->md_blocks); 1421 + #endif 1441 1422 md_blocks_fail: 1442 1423 pcpu_mem_free(chunk->bound_map); 1443 1424 bound_map_fail: ··· 1456 1429 { 1457 1430 if (!chunk) 1458 1431 return; 1432 + #ifdef CONFIG_MEMCG_KMEM 1433 + pcpu_mem_free(chunk->obj_cgroups); 1434 + #endif 1459 1435 pcpu_mem_free(chunk->md_blocks); 1460 1436 pcpu_mem_free(chunk->bound_map); 1461 1437 pcpu_mem_free(chunk->alloc_map); ··· 1535 1505 int page_start, int page_end, gfp_t gfp); 1536 1506 static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, 1537 1507 int page_start, int page_end); 1538 - static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp); 1508 + static struct pcpu_chunk *pcpu_create_chunk(enum pcpu_chunk_type type, 1509 + gfp_t gfp); 1539 1510 static void pcpu_destroy_chunk(struct pcpu_chunk *chunk); 1540 1511 static struct page *pcpu_addr_to_page(void *addr); 1541 1512 static int __init pcpu_verify_alloc_info(const struct pcpu_alloc_info *ai); ··· 1578 1547 return pcpu_get_page_chunk(pcpu_addr_to_page(addr)); 1579 1548 } 1580 1549 1550 + #ifdef CONFIG_MEMCG_KMEM 1551 + static enum pcpu_chunk_type pcpu_memcg_pre_alloc_hook(size_t size, gfp_t gfp, 1552 + struct obj_cgroup **objcgp) 1553 + { 1554 + struct obj_cgroup *objcg; 1555 + 1556 + if (!memcg_kmem_enabled() || !(gfp & __GFP_ACCOUNT) || 1557 + memcg_kmem_bypass()) 1558 + return PCPU_CHUNK_ROOT; 1559 + 1560 + objcg = get_obj_cgroup_from_current(); 1561 + if (!objcg) 1562 + return PCPU_CHUNK_ROOT; 1563 + 1564 + if (obj_cgroup_charge(objcg, gfp, size * num_possible_cpus())) { 1565 + obj_cgroup_put(objcg); 1566 + return PCPU_FAIL_ALLOC; 1567 + } 1568 + 1569 + *objcgp = objcg; 1570 + return PCPU_CHUNK_MEMCG; 1571 + } 1572 + 1573 + static void pcpu_memcg_post_alloc_hook(struct obj_cgroup *objcg, 1574 + struct pcpu_chunk *chunk, int off, 1575 + size_t size) 1576 + { 1577 + if (!objcg) 1578 + return; 1579 + 1580 + if (chunk) { 1581 + chunk->obj_cgroups[off >> PCPU_MIN_ALLOC_SHIFT] = objcg; 1582 + } else { 1583 + obj_cgroup_uncharge(objcg, size * num_possible_cpus()); 1584 + obj_cgroup_put(objcg); 1585 + } 1586 + } 1587 + 1588 + static void pcpu_memcg_free_hook(struct pcpu_chunk *chunk, int off, size_t size) 1589 + { 1590 + struct obj_cgroup *objcg; 1591 + 1592 + if (!pcpu_is_memcg_chunk(pcpu_chunk_type(chunk))) 1593 + return; 1594 + 1595 + objcg = chunk->obj_cgroups[off >> PCPU_MIN_ALLOC_SHIFT]; 1596 + chunk->obj_cgroups[off >> PCPU_MIN_ALLOC_SHIFT] = NULL; 1597 + 1598 + obj_cgroup_uncharge(objcg, size * num_possible_cpus()); 1599 + 1600 + obj_cgroup_put(objcg); 1601 + } 1602 + 1603 + #else /* CONFIG_MEMCG_KMEM */ 1604 + static enum pcpu_chunk_type 1605 + pcpu_memcg_pre_alloc_hook(size_t size, gfp_t gfp, struct obj_cgroup **objcgp) 1606 + { 1607 + return PCPU_CHUNK_ROOT; 1608 + } 1609 + 1610 + static void pcpu_memcg_post_alloc_hook(struct obj_cgroup *objcg, 1611 + struct pcpu_chunk *chunk, int off, 1612 + size_t size) 1613 + { 1614 + } 1615 + 1616 + static void pcpu_memcg_free_hook(struct pcpu_chunk *chunk, int off, size_t size) 1617 + { 1618 + } 1619 + #endif /* CONFIG_MEMCG_KMEM */ 1620 + 1581 1621 /** 1582 1622 * pcpu_alloc - the percpu allocator 1583 1623 * @size: size of area to allocate in bytes ··· 1670 1568 gfp_t pcpu_gfp; 1671 1569 bool is_atomic; 1672 1570 bool do_warn; 1571 + enum pcpu_chunk_type type; 1572 + struct list_head *pcpu_slot; 1573 + struct obj_cgroup *objcg = NULL; 1673 1574 static int warn_limit = 10; 1674 1575 struct pcpu_chunk *chunk, *next; 1675 1576 const char *err; ··· 1707 1602 return NULL; 1708 1603 } 1709 1604 1605 + type = pcpu_memcg_pre_alloc_hook(size, gfp, &objcg); 1606 + if (unlikely(type == PCPU_FAIL_ALLOC)) 1607 + return NULL; 1608 + pcpu_slot = pcpu_chunk_list(type); 1609 + 1710 1610 if (!is_atomic) { 1711 1611 /* 1712 1612 * pcpu_balance_workfn() allocates memory under this mutex, 1713 1613 * and it may wait for memory reclaim. Allow current task 1714 1614 * to become OOM victim, in case of memory pressure. 1715 1615 */ 1716 - if (gfp & __GFP_NOFAIL) 1616 + if (gfp & __GFP_NOFAIL) { 1717 1617 mutex_lock(&pcpu_alloc_mutex); 1718 - else if (mutex_lock_killable(&pcpu_alloc_mutex)) 1618 + } else if (mutex_lock_killable(&pcpu_alloc_mutex)) { 1619 + pcpu_memcg_post_alloc_hook(objcg, NULL, 0, size); 1719 1620 return NULL; 1621 + } 1720 1622 } 1721 1623 1722 1624 spin_lock_irqsave(&pcpu_lock, flags); ··· 1778 1666 } 1779 1667 1780 1668 if (list_empty(&pcpu_slot[pcpu_nr_slots - 1])) { 1781 - chunk = pcpu_create_chunk(pcpu_gfp); 1669 + chunk = pcpu_create_chunk(type, pcpu_gfp); 1782 1670 if (!chunk) { 1783 1671 err = "failed to allocate new chunk"; 1784 1672 goto fail; ··· 1835 1723 trace_percpu_alloc_percpu(reserved, is_atomic, size, align, 1836 1724 chunk->base_addr, off, ptr); 1837 1725 1726 + pcpu_memcg_post_alloc_hook(objcg, chunk, off, size); 1727 + 1838 1728 return ptr; 1839 1729 1840 1730 fail_unlock: ··· 1858 1744 } else { 1859 1745 mutex_unlock(&pcpu_alloc_mutex); 1860 1746 } 1747 + 1748 + pcpu_memcg_post_alloc_hook(objcg, NULL, 0, size); 1749 + 1861 1750 return NULL; 1862 1751 } 1863 1752 ··· 1920 1803 } 1921 1804 1922 1805 /** 1923 - * pcpu_balance_workfn - manage the amount of free chunks and populated pages 1924 - * @work: unused 1806 + * __pcpu_balance_workfn - manage the amount of free chunks and populated pages 1807 + * @type: chunk type 1925 1808 * 1926 1809 * Reclaim all fully free chunks except for the first one. This is also 1927 1810 * responsible for maintaining the pool of empty populated pages. However, ··· 1930 1813 * allocation causes the failure as it is possible that requests can be 1931 1814 * serviced from already backed regions. 1932 1815 */ 1933 - static void pcpu_balance_workfn(struct work_struct *work) 1816 + static void __pcpu_balance_workfn(enum pcpu_chunk_type type) 1934 1817 { 1935 1818 /* gfp flags passed to underlying allocators */ 1936 1819 const gfp_t gfp = GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN; 1937 1820 LIST_HEAD(to_free); 1821 + struct list_head *pcpu_slot = pcpu_chunk_list(type); 1938 1822 struct list_head *free_head = &pcpu_slot[pcpu_nr_slots - 1]; 1939 1823 struct pcpu_chunk *chunk, *next; 1940 1824 int slot, nr_to_pop, ret; ··· 2033 1915 2034 1916 if (nr_to_pop) { 2035 1917 /* ran out of chunks to populate, create a new one and retry */ 2036 - chunk = pcpu_create_chunk(gfp); 1918 + chunk = pcpu_create_chunk(type, gfp); 2037 1919 if (chunk) { 2038 1920 spin_lock_irq(&pcpu_lock); 2039 1921 pcpu_chunk_relocate(chunk, -1); ··· 2043 1925 } 2044 1926 2045 1927 mutex_unlock(&pcpu_alloc_mutex); 1928 + } 1929 + 1930 + /** 1931 + * pcpu_balance_workfn - manage the amount of free chunks and populated pages 1932 + * @work: unused 1933 + * 1934 + * Call __pcpu_balance_workfn() for each chunk type. 1935 + */ 1936 + static void pcpu_balance_workfn(struct work_struct *work) 1937 + { 1938 + enum pcpu_chunk_type type; 1939 + 1940 + for (type = 0; type < PCPU_NR_CHUNK_TYPES; type++) 1941 + __pcpu_balance_workfn(type); 2046 1942 } 2047 1943 2048 1944 /** ··· 2073 1941 void *addr; 2074 1942 struct pcpu_chunk *chunk; 2075 1943 unsigned long flags; 2076 - int off; 1944 + int size, off; 2077 1945 bool need_balance = false; 1946 + struct list_head *pcpu_slot; 2078 1947 2079 1948 if (!ptr) 2080 1949 return; ··· 2089 1956 chunk = pcpu_chunk_addr_search(addr); 2090 1957 off = addr - chunk->base_addr; 2091 1958 2092 - pcpu_free_area(chunk, off); 1959 + size = pcpu_free_area(chunk, off); 1960 + 1961 + pcpu_slot = pcpu_chunk_list(pcpu_chunk_type(chunk)); 1962 + 1963 + pcpu_memcg_free_hook(chunk, off, size); 2093 1964 2094 1965 /* if there are more than one fully free chunks, wake up grim reaper */ 2095 1966 if (chunk->free_bytes == pcpu_unit_size) { ··· 2404 2267 int map_size; 2405 2268 unsigned long tmp_addr; 2406 2269 size_t alloc_size; 2270 + enum pcpu_chunk_type type; 2407 2271 2408 2272 #define PCPU_SETUP_BUG_ON(cond) do { \ 2409 2273 if (unlikely(cond)) { \ ··· 2522 2384 * empty chunks. 2523 2385 */ 2524 2386 pcpu_nr_slots = __pcpu_size_to_slot(pcpu_unit_size) + 2; 2525 - pcpu_slot = memblock_alloc(pcpu_nr_slots * sizeof(pcpu_slot[0]), 2526 - SMP_CACHE_BYTES); 2527 - if (!pcpu_slot) 2387 + pcpu_chunk_lists = memblock_alloc(pcpu_nr_slots * 2388 + sizeof(pcpu_chunk_lists[0]) * 2389 + PCPU_NR_CHUNK_TYPES, 2390 + SMP_CACHE_BYTES); 2391 + if (!pcpu_chunk_lists) 2528 2392 panic("%s: Failed to allocate %zu bytes\n", __func__, 2529 - pcpu_nr_slots * sizeof(pcpu_slot[0])); 2530 - for (i = 0; i < pcpu_nr_slots; i++) 2531 - INIT_LIST_HEAD(&pcpu_slot[i]); 2393 + pcpu_nr_slots * sizeof(pcpu_chunk_lists[0]) * 2394 + PCPU_NR_CHUNK_TYPES); 2395 + 2396 + for (type = 0; type < PCPU_NR_CHUNK_TYPES; type++) 2397 + for (i = 0; i < pcpu_nr_slots; i++) 2398 + INIT_LIST_HEAD(&pcpu_chunk_list(type)[i]); 2532 2399 2533 2400 /* 2534 2401 * The end of the static region needs to be aligned with the