|
@@ -74,9 +74,6 @@ void tcp_destroy_cgroup(struct mem_cgroup *memcg)
|
|
|
percpu_counter_destroy(&tcp->tcp_sockets_allocated);
|
|
|
|
|
|
val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
|
|
|
-
|
|
|
- if (val != RESOURCE_MAX)
|
|
|
- static_key_slow_dec(&memcg_socket_limit_enabled);
|
|
|
}
|
|
|
EXPORT_SYMBOL(tcp_destroy_cgroup);
|
|
|
|
|
@@ -107,10 +104,33 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val)
|
|
|
tcp->tcp_prot_mem[i] = min_t(long, val >> PAGE_SHIFT,
|
|
|
net->ipv4.sysctl_tcp_mem[i]);
|
|
|
|
|
|
- if (val == RESOURCE_MAX && old_lim != RESOURCE_MAX)
|
|
|
- static_key_slow_dec(&memcg_socket_limit_enabled);
|
|
|
- else if (old_lim == RESOURCE_MAX && val != RESOURCE_MAX)
|
|
|
- static_key_slow_inc(&memcg_socket_limit_enabled);
|
|
|
+ if (val == RESOURCE_MAX)
|
|
|
+ clear_bit(MEMCG_SOCK_ACTIVE, &cg_proto->flags);
|
|
|
+ else if (val != RESOURCE_MAX) {
|
|
|
+ /*
|
|
|
+ * The active bit needs to be written after the static_key
|
|
|
+ * update. This is what guarantees that the socket activation
|
|
|
+ * function is the last one to run. See sock_update_memcg() for
|
|
|
+ * details, and note that we don't mark any socket as belonging
|
|
|
+ * to this memcg until that flag is up.
|
|
|
+ *
|
|
|
+ * We need to do this, because static_keys will span multiple
|
|
|
+ * sites, but we can't control their order. If we mark a socket
|
|
|
+ * as accounted, but the accounting functions are not patched in
|
|
|
+ * yet, we'll lose accounting.
|
|
|
+ *
|
|
|
+ * We never race with the readers in sock_update_memcg(),
|
|
|
+ * because when this value change, the code to process it is not
|
|
|
+ * patched in yet.
|
|
|
+ *
|
|
|
+ * The activated bit is used to guarantee that no two writers
|
|
|
+ * will do the update in the same memcg. Without that, we can't
|
|
|
+ * properly shutdown the static key.
|
|
|
+ */
|
|
|
+ if (!test_and_set_bit(MEMCG_SOCK_ACTIVATED, &cg_proto->flags))
|
|
|
+ static_key_slow_inc(&memcg_socket_limit_enabled);
|
|
|
+ set_bit(MEMCG_SOCK_ACTIVE, &cg_proto->flags);
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
}
|