diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/memcontrol.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 6fbf50977f77..ac35bccadb7b 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -417,6 +417,7 @@ void sock_update_memcg(struct sock *sk) | |||
417 | { | 417 | { |
418 | if (mem_cgroup_sockets_enabled) { | 418 | if (mem_cgroup_sockets_enabled) { |
419 | struct mem_cgroup *memcg; | 419 | struct mem_cgroup *memcg; |
420 | struct cg_proto *cg_proto; | ||
420 | 421 | ||
421 | BUG_ON(!sk->sk_prot->proto_cgroup); | 422 | BUG_ON(!sk->sk_prot->proto_cgroup); |
422 | 423 | ||
@@ -436,9 +437,10 @@ void sock_update_memcg(struct sock *sk) | |||
436 | 437 | ||
437 | rcu_read_lock(); | 438 | rcu_read_lock(); |
438 | memcg = mem_cgroup_from_task(current); | 439 | memcg = mem_cgroup_from_task(current); |
439 | if (!mem_cgroup_is_root(memcg)) { | 440 | cg_proto = sk->sk_prot->proto_cgroup(memcg); |
441 | if (!mem_cgroup_is_root(memcg) && memcg_proto_active(cg_proto)) { | ||
440 | mem_cgroup_get(memcg); | 442 | mem_cgroup_get(memcg); |
441 | sk->sk_cgrp = sk->sk_prot->proto_cgroup(memcg); | 443 | sk->sk_cgrp = cg_proto; |
442 | } | 444 | } |
443 | rcu_read_unlock(); | 445 | rcu_read_unlock(); |
444 | } | 446 | } |
@@ -467,6 +469,19 @@ EXPORT_SYMBOL(tcp_proto_cgroup); | |||
467 | #endif /* CONFIG_INET */ | 469 | #endif /* CONFIG_INET */ |
468 | #endif /* CONFIG_CGROUP_MEM_RES_CTLR_KMEM */ | 470 | #endif /* CONFIG_CGROUP_MEM_RES_CTLR_KMEM */ |
469 | 471 | ||
472 | #if defined(CONFIG_INET) && defined(CONFIG_CGROUP_MEM_RES_CTLR_KMEM) | ||
473 | static void disarm_sock_keys(struct mem_cgroup *memcg) | ||
474 | { | ||
475 | if (!memcg_proto_activated(&memcg->tcp_mem.cg_proto)) | ||
476 | return; | ||
477 | static_key_slow_dec(&memcg_socket_limit_enabled); | ||
478 | } | ||
479 | #else | ||
480 | static void disarm_sock_keys(struct mem_cgroup *memcg) | ||
481 | { | ||
482 | } | ||
483 | #endif | ||
484 | |||
470 | static void drain_all_stock_async(struct mem_cgroup *memcg); | 485 | static void drain_all_stock_async(struct mem_cgroup *memcg); |
471 | 486 | ||
472 | static struct mem_cgroup_per_zone * | 487 | static struct mem_cgroup_per_zone * |
@@ -4712,6 +4727,18 @@ static void free_work(struct work_struct *work) | |||
4712 | int size = sizeof(struct mem_cgroup); | 4727 | int size = sizeof(struct mem_cgroup); |
4713 | 4728 | ||
4714 | memcg = container_of(work, struct mem_cgroup, work_freeing); | 4729 | memcg = container_of(work, struct mem_cgroup, work_freeing); |
4730 | /* | ||
4731 | * We need to make sure that (at least for now), the jump label | ||
4732 | * destruction code runs outside of the cgroup lock. This is because | ||
4733 | * get_online_cpus(), which is called from the static_branch update, | ||
4734 | * can't be called inside the cgroup_lock. cpusets are the ones | ||
4735 | * enforcing this dependency, so if they ever change, we might as well. | ||
4736 | * | ||
4737 | * schedule_work() will guarantee this happens. Be careful if you need | ||
4738 | * to move this code around, and make sure it is outside | ||
4739 | * the cgroup_lock. | ||
4740 | */ | ||
4741 | disarm_sock_keys(memcg); | ||
4715 | if (size < PAGE_SIZE) | 4742 | if (size < PAGE_SIZE) |
4716 | kfree(memcg); | 4743 | kfree(memcg); |
4717 | else | 4744 | else |