diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-22 23:54:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-22 23:54:20 -0400 |
commit | b1386cedda177b10fac009ca8d3681034f15b5b3 (patch) | |
tree | e979766970249b4cf3b1bae41a91ee7430041bd8 | |
parent | d15ae814ccb0df179e93d64c4642e7f58ee8398b (diff) | |
parent | 368301f2fe4b07e5fb71dba3cc566bc59eb6705f (diff) |
Merge branch 'akpm' (patches from Andrew)
Merge misc fixes from Andrew Morton:
"Five fixes"
* emailed patches from Andrew Morton <akpm@linux-foundation.org>:
pps: do not crash when failed to register
tools/vm/slabinfo: fix an unintentional printf
testing/radix-tree: fix a macro expansion bug
radix-tree: fix radix_tree_iter_retry() for tagged iterators.
mm: memcontrol: fix cgroup creation failure after many small jobs
-rw-r--r-- | drivers/pps/clients/pps_parport.c | 2 | ||||
-rw-r--r-- | include/linux/memcontrol.h | 25 | ||||
-rw-r--r-- | include/linux/radix-tree.h | 1 | ||||
-rw-r--r-- | mm/memcontrol.c | 82 | ||||
-rw-r--r-- | mm/slab_common.c | 4 | ||||
-rw-r--r-- | tools/testing/radix-tree/tag_check.c | 2 | ||||
-rw-r--r-- | tools/vm/slabinfo.c | 3 |
7 files changed, 92 insertions, 27 deletions
diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c index 38a8bbe74810..83797d89c30f 100644 --- a/drivers/pps/clients/pps_parport.c +++ b/drivers/pps/clients/pps_parport.c | |||
@@ -195,7 +195,7 @@ static void parport_detach(struct parport *port) | |||
195 | struct pps_client_pp *device; | 195 | struct pps_client_pp *device; |
196 | 196 | ||
197 | /* FIXME: oooh, this is ugly! */ | 197 | /* FIXME: oooh, this is ugly! */ |
198 | if (strcmp(pardev->name, KBUILD_MODNAME)) | 198 | if (!pardev || strcmp(pardev->name, KBUILD_MODNAME)) |
199 | /* not our port */ | 199 | /* not our port */ |
200 | return; | 200 | return; |
201 | 201 | ||
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index a805474df4ab..56e6069d2452 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h | |||
@@ -97,6 +97,11 @@ enum mem_cgroup_events_target { | |||
97 | #define MEM_CGROUP_ID_SHIFT 16 | 97 | #define MEM_CGROUP_ID_SHIFT 16 |
98 | #define MEM_CGROUP_ID_MAX USHRT_MAX | 98 | #define MEM_CGROUP_ID_MAX USHRT_MAX |
99 | 99 | ||
100 | struct mem_cgroup_id { | ||
101 | int id; | ||
102 | atomic_t ref; | ||
103 | }; | ||
104 | |||
100 | struct mem_cgroup_stat_cpu { | 105 | struct mem_cgroup_stat_cpu { |
101 | long count[MEMCG_NR_STAT]; | 106 | long count[MEMCG_NR_STAT]; |
102 | unsigned long events[MEMCG_NR_EVENTS]; | 107 | unsigned long events[MEMCG_NR_EVENTS]; |
@@ -172,6 +177,9 @@ enum memcg_kmem_state { | |||
172 | struct mem_cgroup { | 177 | struct mem_cgroup { |
173 | struct cgroup_subsys_state css; | 178 | struct cgroup_subsys_state css; |
174 | 179 | ||
180 | /* Private memcg ID. Used to ID objects that outlive the cgroup */ | ||
181 | struct mem_cgroup_id id; | ||
182 | |||
175 | /* Accounted resources */ | 183 | /* Accounted resources */ |
176 | struct page_counter memory; | 184 | struct page_counter memory; |
177 | struct page_counter swap; | 185 | struct page_counter swap; |
@@ -330,22 +338,9 @@ static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg) | |||
330 | if (mem_cgroup_disabled()) | 338 | if (mem_cgroup_disabled()) |
331 | return 0; | 339 | return 0; |
332 | 340 | ||
333 | return memcg->css.id; | 341 | return memcg->id.id; |
334 | } | ||
335 | |||
336 | /** | ||
337 | * mem_cgroup_from_id - look up a memcg from an id | ||
338 | * @id: the id to look up | ||
339 | * | ||
340 | * Caller must hold rcu_read_lock() and use css_tryget() as necessary. | ||
341 | */ | ||
342 | static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id) | ||
343 | { | ||
344 | struct cgroup_subsys_state *css; | ||
345 | |||
346 | css = css_from_id(id, &memory_cgrp_subsys); | ||
347 | return mem_cgroup_from_css(css); | ||
348 | } | 342 | } |
343 | struct mem_cgroup *mem_cgroup_from_id(unsigned short id); | ||
349 | 344 | ||
350 | /** | 345 | /** |
351 | * parent_mem_cgroup - find the accounting parent of a memcg | 346 | * parent_mem_cgroup - find the accounting parent of a memcg |
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index cb4b7e8cee81..eca6f626c16e 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h | |||
@@ -407,6 +407,7 @@ static inline __must_check | |||
407 | void **radix_tree_iter_retry(struct radix_tree_iter *iter) | 407 | void **radix_tree_iter_retry(struct radix_tree_iter *iter) |
408 | { | 408 | { |
409 | iter->next_index = iter->index; | 409 | iter->next_index = iter->index; |
410 | iter->tags = 0; | ||
410 | return NULL; | 411 | return NULL; |
411 | } | 412 | } |
412 | 413 | ||
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index ac8664db3823..5339c89dff63 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -4057,6 +4057,60 @@ static struct cftype mem_cgroup_legacy_files[] = { | |||
4057 | { }, /* terminate */ | 4057 | { }, /* terminate */ |
4058 | }; | 4058 | }; |
4059 | 4059 | ||
4060 | /* | ||
4061 | * Private memory cgroup IDR | ||
4062 | * | ||
4063 | * Swap-out records and page cache shadow entries need to store memcg | ||
4064 | * references in constrained space, so we maintain an ID space that is | ||
4065 | * limited to 16 bit (MEM_CGROUP_ID_MAX), limiting the total number of | ||
4066 | * memory-controlled cgroups to 64k. | ||
4067 | * | ||
4068 | * However, there usually are many references to the oflline CSS after | ||
4069 | * the cgroup has been destroyed, such as page cache or reclaimable | ||
4070 | * slab objects, that don't need to hang on to the ID. We want to keep | ||
4071 | * those dead CSS from occupying IDs, or we might quickly exhaust the | ||
4072 | * relatively small ID space and prevent the creation of new cgroups | ||
4073 | * even when there are much fewer than 64k cgroups - possibly none. | ||
4074 | * | ||
4075 | * Maintain a private 16-bit ID space for memcg, and allow the ID to | ||
4076 | * be freed and recycled when it's no longer needed, which is usually | ||
4077 | * when the CSS is offlined. | ||
4078 | * | ||
4079 | * The only exception to that are records of swapped out tmpfs/shmem | ||
4080 | * pages that need to be attributed to live ancestors on swapin. But | ||
4081 | * those references are manageable from userspace. | ||
4082 | */ | ||
4083 | |||
4084 | static DEFINE_IDR(mem_cgroup_idr); | ||
4085 | |||
4086 | static void mem_cgroup_id_get(struct mem_cgroup *memcg) | ||
4087 | { | ||
4088 | atomic_inc(&memcg->id.ref); | ||
4089 | } | ||
4090 | |||
4091 | static void mem_cgroup_id_put(struct mem_cgroup *memcg) | ||
4092 | { | ||
4093 | if (atomic_dec_and_test(&memcg->id.ref)) { | ||
4094 | idr_remove(&mem_cgroup_idr, memcg->id.id); | ||
4095 | memcg->id.id = 0; | ||
4096 | |||
4097 | /* Memcg ID pins CSS */ | ||
4098 | css_put(&memcg->css); | ||
4099 | } | ||
4100 | } | ||
4101 | |||
4102 | /** | ||
4103 | * mem_cgroup_from_id - look up a memcg from a memcg id | ||
4104 | * @id: the memcg id to look up | ||
4105 | * | ||
4106 | * Caller must hold rcu_read_lock(). | ||
4107 | */ | ||
4108 | struct mem_cgroup *mem_cgroup_from_id(unsigned short id) | ||
4109 | { | ||
4110 | WARN_ON_ONCE(!rcu_read_lock_held()); | ||
4111 | return idr_find(&mem_cgroup_idr, id); | ||
4112 | } | ||
4113 | |||
4060 | static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node) | 4114 | static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node) |
4061 | { | 4115 | { |
4062 | struct mem_cgroup_per_node *pn; | 4116 | struct mem_cgroup_per_node *pn; |
@@ -4116,6 +4170,12 @@ static struct mem_cgroup *mem_cgroup_alloc(void) | |||
4116 | if (!memcg) | 4170 | if (!memcg) |
4117 | return NULL; | 4171 | return NULL; |
4118 | 4172 | ||
4173 | memcg->id.id = idr_alloc(&mem_cgroup_idr, NULL, | ||
4174 | 1, MEM_CGROUP_ID_MAX, | ||
4175 | GFP_KERNEL); | ||
4176 | if (memcg->id.id < 0) | ||
4177 | goto fail; | ||
4178 | |||
4119 | memcg->stat = alloc_percpu(struct mem_cgroup_stat_cpu); | 4179 | memcg->stat = alloc_percpu(struct mem_cgroup_stat_cpu); |
4120 | if (!memcg->stat) | 4180 | if (!memcg->stat) |
4121 | goto fail; | 4181 | goto fail; |
@@ -4142,8 +4202,11 @@ static struct mem_cgroup *mem_cgroup_alloc(void) | |||
4142 | #ifdef CONFIG_CGROUP_WRITEBACK | 4202 | #ifdef CONFIG_CGROUP_WRITEBACK |
4143 | INIT_LIST_HEAD(&memcg->cgwb_list); | 4203 | INIT_LIST_HEAD(&memcg->cgwb_list); |
4144 | #endif | 4204 | #endif |
4205 | idr_replace(&mem_cgroup_idr, memcg, memcg->id.id); | ||
4145 | return memcg; | 4206 | return memcg; |
4146 | fail: | 4207 | fail: |
4208 | if (memcg->id.id > 0) | ||
4209 | idr_remove(&mem_cgroup_idr, memcg->id.id); | ||
4147 | mem_cgroup_free(memcg); | 4210 | mem_cgroup_free(memcg); |
4148 | return NULL; | 4211 | return NULL; |
4149 | } | 4212 | } |
@@ -4206,12 +4269,11 @@ fail: | |||
4206 | return ERR_PTR(-ENOMEM); | 4269 | return ERR_PTR(-ENOMEM); |
4207 | } | 4270 | } |
4208 | 4271 | ||
4209 | static int | 4272 | static int mem_cgroup_css_online(struct cgroup_subsys_state *css) |
4210 | mem_cgroup_css_online(struct cgroup_subsys_state *css) | ||
4211 | { | 4273 | { |
4212 | if (css->id > MEM_CGROUP_ID_MAX) | 4274 | /* Online state pins memcg ID, memcg ID pins CSS */ |
4213 | return -ENOSPC; | 4275 | mem_cgroup_id_get(mem_cgroup_from_css(css)); |
4214 | 4276 | css_get(css); | |
4215 | return 0; | 4277 | return 0; |
4216 | } | 4278 | } |
4217 | 4279 | ||
@@ -4234,6 +4296,8 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) | |||
4234 | 4296 | ||
4235 | memcg_offline_kmem(memcg); | 4297 | memcg_offline_kmem(memcg); |
4236 | wb_memcg_offline(memcg); | 4298 | wb_memcg_offline(memcg); |
4299 | |||
4300 | mem_cgroup_id_put(memcg); | ||
4237 | } | 4301 | } |
4238 | 4302 | ||
4239 | static void mem_cgroup_css_released(struct cgroup_subsys_state *css) | 4303 | static void mem_cgroup_css_released(struct cgroup_subsys_state *css) |
@@ -5756,6 +5820,7 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry) | |||
5756 | if (!memcg) | 5820 | if (!memcg) |
5757 | return; | 5821 | return; |
5758 | 5822 | ||
5823 | mem_cgroup_id_get(memcg); | ||
5759 | oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg)); | 5824 | oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg)); |
5760 | VM_BUG_ON_PAGE(oldid, page); | 5825 | VM_BUG_ON_PAGE(oldid, page); |
5761 | mem_cgroup_swap_statistics(memcg, true); | 5826 | mem_cgroup_swap_statistics(memcg, true); |
@@ -5774,6 +5839,9 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry) | |||
5774 | VM_BUG_ON(!irqs_disabled()); | 5839 | VM_BUG_ON(!irqs_disabled()); |
5775 | mem_cgroup_charge_statistics(memcg, page, false, -1); | 5840 | mem_cgroup_charge_statistics(memcg, page, false, -1); |
5776 | memcg_check_events(memcg, page); | 5841 | memcg_check_events(memcg, page); |
5842 | |||
5843 | if (!mem_cgroup_is_root(memcg)) | ||
5844 | css_put(&memcg->css); | ||
5777 | } | 5845 | } |
5778 | 5846 | ||
5779 | /* | 5847 | /* |
@@ -5804,11 +5872,11 @@ int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry) | |||
5804 | !page_counter_try_charge(&memcg->swap, 1, &counter)) | 5872 | !page_counter_try_charge(&memcg->swap, 1, &counter)) |
5805 | return -ENOMEM; | 5873 | return -ENOMEM; |
5806 | 5874 | ||
5875 | mem_cgroup_id_get(memcg); | ||
5807 | oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg)); | 5876 | oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg)); |
5808 | VM_BUG_ON_PAGE(oldid, page); | 5877 | VM_BUG_ON_PAGE(oldid, page); |
5809 | mem_cgroup_swap_statistics(memcg, true); | 5878 | mem_cgroup_swap_statistics(memcg, true); |
5810 | 5879 | ||
5811 | css_get(&memcg->css); | ||
5812 | return 0; | 5880 | return 0; |
5813 | } | 5881 | } |
5814 | 5882 | ||
@@ -5837,7 +5905,7 @@ void mem_cgroup_uncharge_swap(swp_entry_t entry) | |||
5837 | page_counter_uncharge(&memcg->memsw, 1); | 5905 | page_counter_uncharge(&memcg->memsw, 1); |
5838 | } | 5906 | } |
5839 | mem_cgroup_swap_statistics(memcg, false); | 5907 | mem_cgroup_swap_statistics(memcg, false); |
5840 | css_put(&memcg->css); | 5908 | mem_cgroup_id_put(memcg); |
5841 | } | 5909 | } |
5842 | rcu_read_unlock(); | 5910 | rcu_read_unlock(); |
5843 | } | 5911 | } |
diff --git a/mm/slab_common.c b/mm/slab_common.c index a65dad7fdcd1..82317abb03ed 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c | |||
@@ -526,8 +526,8 @@ void memcg_create_kmem_cache(struct mem_cgroup *memcg, | |||
526 | goto out_unlock; | 526 | goto out_unlock; |
527 | 527 | ||
528 | cgroup_name(css->cgroup, memcg_name_buf, sizeof(memcg_name_buf)); | 528 | cgroup_name(css->cgroup, memcg_name_buf, sizeof(memcg_name_buf)); |
529 | cache_name = kasprintf(GFP_KERNEL, "%s(%d:%s)", root_cache->name, | 529 | cache_name = kasprintf(GFP_KERNEL, "%s(%llu:%s)", root_cache->name, |
530 | css->id, memcg_name_buf); | 530 | css->serial_nr, memcg_name_buf); |
531 | if (!cache_name) | 531 | if (!cache_name) |
532 | goto out_unlock; | 532 | goto out_unlock; |
533 | 533 | ||
diff --git a/tools/testing/radix-tree/tag_check.c b/tools/testing/radix-tree/tag_check.c index b7447ceb75e9..b0ac05741750 100644 --- a/tools/testing/radix-tree/tag_check.c +++ b/tools/testing/radix-tree/tag_check.c | |||
@@ -122,7 +122,7 @@ enum { | |||
122 | NODE_TAGGED = 2, | 122 | NODE_TAGGED = 2, |
123 | }; | 123 | }; |
124 | 124 | ||
125 | #define THRASH_SIZE 1000 * 1000 | 125 | #define THRASH_SIZE (1000 * 1000) |
126 | #define N 127 | 126 | #define N 127 |
127 | #define BATCH 33 | 127 | #define BATCH 33 |
128 | 128 | ||
diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c index 7cf6e1769903..b9d34b37c017 100644 --- a/tools/vm/slabinfo.c +++ b/tools/vm/slabinfo.c | |||
@@ -510,10 +510,11 @@ static void slab_stats(struct slabinfo *s) | |||
510 | s->alloc_node_mismatch, (s->alloc_node_mismatch * 100) / total); | 510 | s->alloc_node_mismatch, (s->alloc_node_mismatch * 100) / total); |
511 | } | 511 | } |
512 | 512 | ||
513 | if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail) | 513 | if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail) { |
514 | printf("\nCmpxchg_double Looping\n------------------------\n"); | 514 | printf("\nCmpxchg_double Looping\n------------------------\n"); |
515 | printf("Locked Cmpxchg Double redos %lu\nUnlocked Cmpxchg Double redos %lu\n", | 515 | printf("Locked Cmpxchg Double redos %lu\nUnlocked Cmpxchg Double redos %lu\n", |
516 | s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail); | 516 | s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail); |
517 | } | ||
517 | } | 518 | } |
518 | 519 | ||
519 | static void report(struct slabinfo *s) | 520 | static void report(struct slabinfo *s) |