Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1276786 > unrolled thread
| Started by | Johannes Weiner <hannes@cmpxchg.org> |
|---|---|
| First post | 2015-11-24 23:00 +0100 |
| Last post | 2015-11-30 17:20 +0100 |
| Articles | 10 on this page of 30 — 4 participants |
Back to article view | Back to linux.kernel
[PATCH 00/13] mm: memcontrol: account socket memory in unified hierarchy v4 Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:00 +0100
[PATCH 12/13] mm: memcontrol: account socket memory in unified hierarchy memory controller Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:00 +0100
Re: [PATCH 12/13] mm: memcontrol: account socket memory in unified hierarchy memory controller David Miller <davem@davemloft.net> - 2015-11-25 17:40 +0100
Re: [PATCH 12/13] mm: memcontrol: account socket memory in unified hierarchy memory controller Vladimir Davydov <vdavydov@virtuozzo.com> - 2015-11-30 12:00 +0100
Re: [PATCH 12/13] mm: memcontrol: account socket memory in unified hierarchy memory controller Johannes Weiner <hannes@cmpxchg.org> - 2015-11-30 16:30 +0100
Re: [PATCH 12/13] mm: memcontrol: account socket memory in unified hierarchy memory controller Vladimir Davydov <vdavydov@virtuozzo.com> - 2015-11-30 18:10 +0100
[PATCH 01/13] mm: memcontrol: export root_mem_cgroup Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:00 +0100
[PATCH 04/13] net: tcp_memcontrol: protect all tcp_memcontrol calls by jump-label Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:00 +0100
[PATCH 02/13] net: tcp_memcontrol: properly detect ancestor socket pressure Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:00 +0100
[PATCH 06/13] net: tcp_memcontrol: simplify the per-memcg limit access Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:00 +0100
Re: [PATCH 06/13] net: tcp_memcontrol: simplify the per-memcg limit access David Miller <davem@davemloft.net> - 2015-11-25 17:30 +0100
[PATCH 07/13] net: tcp_memcontrol: sanitize tcp memory accounting callbacks Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:00 +0100
Re: [PATCH 07/13] net: tcp_memcontrol: sanitize tcp memory accounting callbacks David Miller <davem@davemloft.net> - 2015-11-25 17:30 +0100
[PATCH 03/13] net: tcp_memcontrol: remove bogus hierarchy pressure propagation Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:00 +0100
[PATCH 11/13] mm: memcontrol: move socket code for unified hierarchy accounting Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:00 +0100
Re: [PATCH 11/13] mm: memcontrol: move socket code for unified hierarchy accounting David Miller <davem@davemloft.net> - 2015-11-25 17:40 +0100
[PATCH 09/13] mm: memcontrol: generalize the socket accounting jump label Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:00 +0100
Re: [PATCH 09/13] mm: memcontrol: generalize the socket accounting jump label David Miller <davem@davemloft.net> - 2015-11-25 17:30 +0100
Re: [PATCH 09/13] mm: memcontrol: generalize the socket accounting jump label Jason Baron <jbaron@akamai.com> - 2015-11-30 22:10 +0100
Re: [PATCH 09/13] mm: memcontrol: generalize the socket accounting jump label Johannes Weiner <hannes@cmpxchg.org> - 2015-11-30 23:00 +0100
Re: [PATCH 09/13] mm: memcontrol: generalize the socket accounting jump label Jason Baron <jbaron@akamai.com> - 2015-11-30 23:30 +0100
Re: [PATCH 09/13] mm: memcontrol: generalize the socket accounting jump label Johannes Weiner <hannes@cmpxchg.org> - 2015-11-30 23:50 +0100
[PATCH 08/13] net: tcp_memcontrol: simplify linkage between socket and page counter Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:00 +0100
Re: [PATCH 08/13] net: tcp_memcontrol: simplify linkage between socket and page counter David Miller <davem@davemloft.net> - 2015-11-25 17:30 +0100
[PATCH 05/13] net: tcp_memcontrol: remove dead per-memcg count of allocated sockets Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:00 +0100
[PATCH 13/13] mm: memcontrol: hook up vmpressure to socket pressure Johannes Weiner <hannes@cmpxchg.org> - 2015-11-24 23:10 +0100
Re: [PATCH 13/13] mm: memcontrol: hook up vmpressure to socket pressure David Miller <davem@davemloft.net> - 2015-11-25 17:40 +0100
Re: [PATCH 13/13] mm: memcontrol: hook up vmpressure to socket pressure Vladimir Davydov <vdavydov@virtuozzo.com> - 2015-11-30 12:40 +0100
Re: [PATCH 13/13] mm: memcontrol: hook up vmpressure to socket pressure Johannes Weiner <hannes@cmpxchg.org> - 2015-11-30 17:00 +0100
Re: [PATCH 13/13] mm: memcontrol: hook up vmpressure to socket pressure Vladimir Davydov <vdavydov@virtuozzo.com> - 2015-11-30 17:20 +0100
Page 2 of 2 — ← Prev page 1 [2]
| From | Jason Baron <jbaron@akamai.com> |
|---|---|
| Date | 2015-11-30 23:30 +0100 |
| Subject | Re: [PATCH 09/13] mm: memcontrol: generalize the socket accounting jump label |
| Message-ID | <qAF7j-15b-1@gated-at.bofh.it> |
| In reply to | #1280330 |
On 11/30/2015 04:50 PM, Johannes Weiner wrote:
> On Mon, Nov 30, 2015 at 04:08:18PM -0500, Jason Baron wrote:
>> We're trying to move to the updated API, so this should be:
>> static_branch_unlikely(&memcg_sockets_enabled_key)
>>
>> see: include/linux/jump_label.h for details.
>
> Good point. There is another struct static_key in there as well. How
> about the following on top of this series?
>
Looks fine - you may be able to make use of
'static_branch_enable()/disable()' instead of the inc()/dec() to simply
set the branch direction, if you think its more readable. Although I
didn't look to see if it would be racy here.
Thanks,
-Jason
> ---
> From b784aa0323628d43272e13a67ead2a2ce0e93ea6 Mon Sep 17 00:00:00 2001
> From: Johannes Weiner <hannes@cmpxchg.org>
> Date: Mon, 30 Nov 2015 16:41:38 -0500
> Subject: [PATCH] mm: memcontrol: switch to the updated jump-label API
>
> According to <linux/jump_label.h> the direct use of struct static_key
> is deprecated. Update the socket and slab accounting code accordingly.
>
> Reported-by: Jason Baron <jbaron@akamai.com>
> Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
> ---
> include/linux/memcontrol.h | 8 ++++----
> mm/memcontrol.c | 12 ++++++------
> net/ipv4/tcp_memcontrol.c | 4 ++--
> 3 files changed, 12 insertions(+), 12 deletions(-)
>
> diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
> index a8df46c..9a19590 100644
> --- a/include/linux/memcontrol.h
> +++ b/include/linux/memcontrol.h
> @@ -704,8 +704,8 @@ static inline void mem_cgroup_wb_stats(struct bdi_writeback *wb,
>
> #ifdef CONFIG_INET
> struct sock;
> -extern struct static_key memcg_sockets_enabled_key;
> -#define mem_cgroup_sockets_enabled static_key_false(&memcg_sockets_enabled_key)
> +extern struct static_key_false memcg_sockets_enabled_key;
> +#define mem_cgroup_sockets_enabled static_branch_unlikely(&memcg_sockets_enabled_key)
> void sock_update_memcg(struct sock *sk);
> void sock_release_memcg(struct sock *sk);
> bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages);
> @@ -727,7 +727,7 @@ static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg)
> #endif /* CONFIG_INET */
>
> #ifdef CONFIG_MEMCG_KMEM
> -extern struct static_key memcg_kmem_enabled_key;
> +extern struct static_key_false memcg_kmem_enabled_key;
>
> extern int memcg_nr_cache_ids;
> void memcg_get_cache_ids(void);
> @@ -743,7 +743,7 @@ void memcg_put_cache_ids(void);
>
> static inline bool memcg_kmem_enabled(void)
> {
> - return static_key_false(&memcg_kmem_enabled_key);
> + return static_branch_unlikely(&memcg_kmem_enabled_key);
> }
>
> static inline bool memcg_kmem_is_active(struct mem_cgroup *memcg)
> diff --git a/mm/memcontrol.c b/mm/memcontrol.c
> index a0da91f..5fe45d68 100644
> --- a/mm/memcontrol.c
> +++ b/mm/memcontrol.c
> @@ -346,7 +346,7 @@ void memcg_put_cache_ids(void)
> * conditional to this static branch, we'll have to allow modules that does
> * kmem_cache_alloc and the such to see this symbol as well
> */
> -struct static_key memcg_kmem_enabled_key;
> +DEFINE_STATIC_KEY_FALSE(memcg_kmem_enabled_key);
> EXPORT_SYMBOL(memcg_kmem_enabled_key);
>
> #endif /* CONFIG_MEMCG_KMEM */
> @@ -2883,7 +2883,7 @@ static int memcg_activate_kmem(struct mem_cgroup *memcg,
> err = page_counter_limit(&memcg->kmem, nr_pages);
> VM_BUG_ON(err);
>
> - static_key_slow_inc(&memcg_kmem_enabled_key);
> + static_branch_inc(&memcg_kmem_enabled_key);
> /*
> * A memory cgroup is considered kmem-active as soon as it gets
> * kmemcg_id. Setting the id after enabling static branching will
> @@ -3622,7 +3622,7 @@ static void memcg_destroy_kmem(struct mem_cgroup *memcg)
> {
> if (memcg->kmem_acct_activated) {
> memcg_destroy_kmem_caches(memcg);
> - static_key_slow_dec(&memcg_kmem_enabled_key);
> + static_branch_dec(&memcg_kmem_enabled_key);
> WARN_ON(page_counter_read(&memcg->kmem));
> }
> tcp_destroy_cgroup(memcg);
> @@ -4258,7 +4258,7 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css)
>
> #ifdef CONFIG_INET
> if (cgroup_subsys_on_dfl(memory_cgrp_subsys) && !cgroup_memory_nosocket)
> - static_key_slow_inc(&memcg_sockets_enabled_key);
> + static_branch_inc(&memcg_sockets_enabled_key);
> #endif
>
> /*
> @@ -4302,7 +4302,7 @@ static void mem_cgroup_css_free(struct cgroup_subsys_state *css)
> memcg_destroy_kmem(memcg);
> #ifdef CONFIG_INET
> if (cgroup_subsys_on_dfl(memory_cgrp_subsys) && !cgroup_memory_nosocket)
> - static_key_slow_dec(&memcg_sockets_enabled_key);
> + static_branch_dec(&memcg_sockets_enabled_key);
> #endif
> __mem_cgroup_free(memcg);
> }
> @@ -5494,7 +5494,7 @@ void mem_cgroup_replace_page(struct page *oldpage, struct page *newpage)
>
> #ifdef CONFIG_INET
>
> -struct static_key memcg_sockets_enabled_key;
> +DEFINE_STATIC_KEY_FALSE(memcg_sockets_enabled_key);
> EXPORT_SYMBOL(memcg_sockets_enabled_key);
>
> void sock_update_memcg(struct sock *sk)
> diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c
> index 9a22e2d..18bc7f7 100644
> --- a/net/ipv4/tcp_memcontrol.c
> +++ b/net/ipv4/tcp_memcontrol.c
> @@ -34,7 +34,7 @@ void tcp_destroy_cgroup(struct mem_cgroup *memcg)
> return;
>
> if (memcg->tcp_mem.active)
> - static_key_slow_dec(&memcg_sockets_enabled_key);
> + static_branch_dec(&memcg_sockets_enabled_key);
> }
>
> static int tcp_update_limit(struct mem_cgroup *memcg, unsigned long nr_pages)
> @@ -65,7 +65,7 @@ static int tcp_update_limit(struct mem_cgroup *memcg, unsigned long nr_pages)
> * because when this value change, the code to process it is not
> * patched in yet.
> */
> - static_key_slow_inc(&memcg_sockets_enabled_key);
> + static_branch_inc(&memcg_sockets_enabled_key);
> memcg->tcp_mem.active = true;
> }
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Johannes Weiner <hannes@cmpxchg.org> |
|---|---|
| Date | 2015-11-30 23:50 +0100 |
| Subject | Re: [PATCH 09/13] mm: memcontrol: generalize the socket accounting jump label |
| Message-ID | <qAFqG-1ch-11@gated-at.bofh.it> |
| In reply to | #1280362 |
On Mon, Nov 30, 2015 at 05:28:49PM -0500, Jason Baron wrote: > On 11/30/2015 04:50 PM, Johannes Weiner wrote: > > On Mon, Nov 30, 2015 at 04:08:18PM -0500, Jason Baron wrote: > >> We're trying to move to the updated API, so this should be: > >> static_branch_unlikely(&memcg_sockets_enabled_key) > >> > >> see: include/linux/jump_label.h for details. > > > > Good point. There is another struct static_key in there as well. How > > about the following on top of this series? > > > > Looks fine - you may be able to make use of > 'static_branch_enable()/disable()' instead of the inc()/dec() to simply > set the branch direction, if you think its more readable. Although I > didn't look to see if it would be racy here. Thanks! We actually need the reference counting semantics for both these keys. It counts the number of active cgroups in existence that require the code behind those static branches. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Johannes Weiner <hannes@cmpxchg.org> |
|---|---|
| Date | 2015-11-24 23:00 +0100 |
| Subject | [PATCH 08/13] net: tcp_memcontrol: simplify linkage between socket and page counter |
| Message-ID | <qytN2-5hB-55@gated-at.bofh.it> |
| In reply to | #1276786 |
There won't be any separate counters for socket memory consumed by
protocols other than TCP in the future. Remove the indirection and
link sockets directly to their owning memory cgroup.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Vladimir Davydov <vdavydov@virtuozzo.com>
---
include/linux/memcontrol.h | 18 +++---------
include/net/sock.h | 36 +++---------------------
include/net/tcp.h | 4 +--
include/net/tcp_memcontrol.h | 1 -
mm/memcontrol.c | 57 +++++++++++++++----------------------
net/core/sock.c | 52 +++++-----------------------------
net/ipv4/tcp_ipv4.c | 7 +----
net/ipv4/tcp_memcontrol.c | 67 +++++++++++++++++---------------------------
net/ipv4/tcp_output.c | 4 +--
net/ipv6/tcp_ipv6.c | 3 --
10 files changed, 68 insertions(+), 181 deletions(-)
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 4d80021..d99fefe 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -89,16 +89,6 @@ struct cg_proto {
struct page_counter memory_allocated; /* Current allocated memory. */
int memory_pressure;
bool active;
- /*
- * memcg field is used to find which memcg we belong directly
- * Each memcg struct can hold more than one cg_proto, so container_of
- * won't really cut.
- *
- * The elegant solution would be having an inverse function to
- * proto_cgroup in struct proto, but that means polluting the structure
- * for everybody, instead of just for memcg users.
- */
- struct mem_cgroup *memcg;
};
#ifdef CONFIG_MEMCG
@@ -693,11 +683,11 @@ static inline void mem_cgroup_wb_stats(struct bdi_writeback *wb,
struct sock;
void sock_update_memcg(struct sock *sk);
void sock_release_memcg(struct sock *sk);
-bool mem_cgroup_charge_skmem(struct cg_proto *proto, unsigned int nr_pages);
-void mem_cgroup_uncharge_skmem(struct cg_proto *proto, unsigned int nr_pages);
-static inline bool mem_cgroup_under_socket_pressure(struct cg_proto *proto)
+bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages);
+void mem_cgroup_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages);
+static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg)
{
- return proto->memory_pressure;
+ return memcg->tcp_mem.memory_pressure;
}
#endif /* CONFIG_INET && CONFIG_MEMCG_KMEM */
diff --git a/include/net/sock.h b/include/net/sock.h
index 888aa3f..1a94b85 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -69,22 +69,6 @@
#include <net/tcp_states.h>
#include <linux/net_tstamp.h>
-struct cgroup;
-struct cgroup_subsys;
-#ifdef CONFIG_NET
-int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss);
-void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg);
-#else
-static inline
-int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
-{
- return 0;
-}
-static inline
-void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg)
-{
-}
-#endif
/*
* This structure really needs to be cleaned up.
* Most of it is for TCP, and not used by any of
@@ -310,7 +294,7 @@ struct cg_proto;
* @sk_security: used by security modules
* @sk_mark: generic packet mark
* @sk_classid: this socket's cgroup classid
- * @sk_cgrp: this socket's cgroup-specific proto data
+ * @sk_memcg: this socket's memory cgroup association
* @sk_write_pending: a write to stream socket waits to start
* @sk_state_change: callback to indicate change in the state of the sock
* @sk_data_ready: callback to indicate there is data to be processed
@@ -447,7 +431,7 @@ struct sock {
#ifdef CONFIG_CGROUP_NET_CLASSID
u32 sk_classid;
#endif
- struct cg_proto *sk_cgrp;
+ struct mem_cgroup *sk_memcg;
void (*sk_state_change)(struct sock *sk);
void (*sk_data_ready)(struct sock *sk);
void (*sk_write_space)(struct sock *sk);
@@ -1051,18 +1035,6 @@ struct proto {
#ifdef SOCK_REFCNT_DEBUG
atomic_t socks;
#endif
-#ifdef CONFIG_MEMCG_KMEM
- /*
- * cgroup specific init/deinit functions. Called once for all
- * protocols that implement it, from cgroups populate function.
- * This function has to setup any files the protocol want to
- * appear in the kmem cgroup filesystem.
- */
- int (*init_cgroup)(struct mem_cgroup *memcg,
- struct cgroup_subsys *ss);
- void (*destroy_cgroup)(struct mem_cgroup *memcg);
- struct cg_proto *(*proto_cgroup)(struct mem_cgroup *memcg);
-#endif
};
int proto_register(struct proto *prot, int alloc_slab);
@@ -1126,8 +1098,8 @@ static inline bool sk_under_memory_pressure(const struct sock *sk)
if (!sk->sk_prot->memory_pressure)
return false;
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp &&
- mem_cgroup_under_socket_pressure(sk->sk_cgrp))
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg &&
+ mem_cgroup_under_socket_pressure(sk->sk_memcg))
return true;
return !!*sk->sk_prot->memory_pressure;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 04517d6..c008535 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -292,8 +292,8 @@ extern int tcp_memory_pressure;
/* optimized version of sk_under_memory_pressure() for TCP sockets */
static inline bool tcp_under_memory_pressure(const struct sock *sk)
{
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp &&
- mem_cgroup_under_socket_pressure(sk->sk_cgrp))
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg &&
+ mem_cgroup_under_socket_pressure(sk->sk_memcg))
return true;
return tcp_memory_pressure;
diff --git a/include/net/tcp_memcontrol.h b/include/net/tcp_memcontrol.h
index 05b94d9..3a17b16 100644
--- a/include/net/tcp_memcontrol.h
+++ b/include/net/tcp_memcontrol.h
@@ -1,7 +1,6 @@
#ifndef _TCP_MEMCG_H
#define _TCP_MEMCG_H
-struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg);
int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss);
void tcp_destroy_cgroup(struct mem_cgroup *memcg);
#endif /* _TCP_MEMCG_H */
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 4b586ea..68d67fc 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -294,9 +294,6 @@ static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
void sock_update_memcg(struct sock *sk)
{
struct mem_cgroup *memcg;
- struct cg_proto *cg_proto;
-
- BUG_ON(!sk->sk_prot->proto_cgroup);
/* Socket cloning can throw us here with sk_cgrp already
* filled. It won't however, necessarily happen from
@@ -306,68 +303,58 @@ void sock_update_memcg(struct sock *sk)
* Respecting the original socket's memcg is a better
* decision in this case.
*/
- if (sk->sk_cgrp) {
- BUG_ON(mem_cgroup_is_root(sk->sk_cgrp->memcg));
- css_get(&sk->sk_cgrp->memcg->css);
+ if (sk->sk_memcg) {
+ BUG_ON(mem_cgroup_is_root(sk->sk_memcg));
+ css_get(&sk->sk_memcg->css);
return;
}
rcu_read_lock();
memcg = mem_cgroup_from_task(current);
- cg_proto = sk->sk_prot->proto_cgroup(memcg);
- if (cg_proto && cg_proto->active &&
- css_tryget_online(&memcg->css)) {
- sk->sk_cgrp = cg_proto;
- }
+ if (memcg != root_mem_cgroup &&
+ memcg->tcp_mem.active &&
+ css_tryget_online(&memcg->css))
+ sk->sk_memcg = memcg;
rcu_read_unlock();
}
EXPORT_SYMBOL(sock_update_memcg);
void sock_release_memcg(struct sock *sk)
{
- WARN_ON(!sk->sk_cgrp->memcg);
- css_put(&sk->sk_cgrp->memcg->css);
-}
-
-struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg)
-{
- if (!memcg || mem_cgroup_is_root(memcg))
- return NULL;
-
- return &memcg->tcp_mem;
+ WARN_ON(!sk->sk_memcg);
+ css_put(&sk->sk_memcg->css);
}
-EXPORT_SYMBOL(tcp_proto_cgroup);
/**
* mem_cgroup_charge_skmem - charge socket memory
- * @proto: proto to charge
+ * @memcg: memcg to charge
* @nr_pages: number of pages to charge
*
- * Charges @nr_pages to @proto. Returns %true if the charge fit within
- * @proto's configured limit, %false if the charge had to be forced.
+ * Charges @nr_pages to @memcg. Returns %true if the charge fit within
+ * @memcg's configured limit, %false if the charge had to be forced.
*/
-bool mem_cgroup_charge_skmem(struct cg_proto *proto, unsigned int nr_pages)
+bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages)
{
struct page_counter *counter;
- if (page_counter_try_charge(&proto->memory_allocated,
+ if (page_counter_try_charge(&memcg->tcp_mem.memory_allocated,
nr_pages, &counter)) {
- proto->memory_pressure = 0;
+ memcg->tcp_mem.memory_pressure = 0;
return true;
}
- page_counter_charge(&proto->memory_allocated, nr_pages);
- proto->memory_pressure = 1;
+ page_counter_charge(&memcg->tcp_mem.memory_allocated, nr_pages);
+ memcg->tcp_mem.memory_pressure = 1;
return false;
}
/**
* mem_cgroup_uncharge_skmem - uncharge socket memory
- * @proto - proto to uncharge
+ * @memcg - memcg to uncharge
* @nr_pages - number of pages to uncharge
*/
-void mem_cgroup_uncharge_skmem(struct cg_proto *proto, unsigned int nr_pages)
+void mem_cgroup_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages)
{
- page_counter_uncharge(&proto->memory_allocated, nr_pages);
+ page_counter_uncharge(&memcg->tcp_mem.memory_allocated, nr_pages);
}
#endif
@@ -3629,7 +3616,7 @@ static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
if (ret)
return ret;
- return mem_cgroup_sockets_init(memcg, ss);
+ return tcp_init_cgroup(memcg, ss);
}
static void memcg_deactivate_kmem(struct mem_cgroup *memcg)
@@ -3685,7 +3672,7 @@ static void memcg_destroy_kmem(struct mem_cgroup *memcg)
static_key_slow_dec(&memcg_kmem_enabled_key);
WARN_ON(page_counter_read(&memcg->kmem));
}
- mem_cgroup_sockets_destroy(memcg);
+ tcp_destroy_cgroup(memcg);
}
#else
static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
diff --git a/net/core/sock.c b/net/core/sock.c
index 5b1b96f..6486b0d 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -194,44 +194,6 @@ bool sk_net_capable(const struct sock *sk, int cap)
}
EXPORT_SYMBOL(sk_net_capable);
-
-#ifdef CONFIG_MEMCG_KMEM
-int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
-{
- struct proto *proto;
- int ret = 0;
-
- mutex_lock(&proto_list_mutex);
- list_for_each_entry(proto, &proto_list, node) {
- if (proto->init_cgroup) {
- ret = proto->init_cgroup(memcg, ss);
- if (ret)
- goto out;
- }
- }
-
- mutex_unlock(&proto_list_mutex);
- return ret;
-out:
- list_for_each_entry_continue_reverse(proto, &proto_list, node)
- if (proto->destroy_cgroup)
- proto->destroy_cgroup(memcg);
- mutex_unlock(&proto_list_mutex);
- return ret;
-}
-
-void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg)
-{
- struct proto *proto;
-
- mutex_lock(&proto_list_mutex);
- list_for_each_entry_reverse(proto, &proto_list, node)
- if (proto->destroy_cgroup)
- proto->destroy_cgroup(memcg);
- mutex_unlock(&proto_list_mutex);
-}
-#endif
-
/*
* Each address family might have different locking rules, so we have
* one slock key per address family:
@@ -1583,7 +1545,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
sk_set_socket(newsk, NULL);
newsk->sk_wq = NULL;
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg)
sock_update_memcg(newsk);
if (newsk->sk_prot->sockets_allocated)
@@ -2071,8 +2033,8 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind)
allocated = sk_memory_allocated_add(sk, amt);
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp &&
- !mem_cgroup_charge_skmem(sk->sk_cgrp, amt))
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg &&
+ !mem_cgroup_charge_skmem(sk->sk_memcg, amt))
goto suppress_allocation;
/* Under limit. */
@@ -2135,8 +2097,8 @@ suppress_allocation:
sk_memory_allocated_sub(sk, amt);
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
- mem_cgroup_uncharge_skmem(sk->sk_cgrp, amt);
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg)
+ mem_cgroup_uncharge_skmem(sk->sk_memcg, amt);
return 0;
}
@@ -2153,8 +2115,8 @@ void __sk_mem_reclaim(struct sock *sk, int amount)
sk_memory_allocated_sub(sk, amount);
sk->sk_forward_alloc -= amount << SK_MEM_QUANTUM_SHIFT;
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
- mem_cgroup_uncharge_skmem(sk->sk_cgrp, amount);
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg)
+ mem_cgroup_uncharge_skmem(sk->sk_memcg, amount);
if (sk_under_memory_pressure(sk) &&
(sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0)))
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 4027e02..34c2678 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1814,7 +1814,7 @@ void tcp_v4_destroy_sock(struct sock *sk)
sk_sockets_allocated_dec(sk);
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg)
sock_release_memcg(sk);
}
EXPORT_SYMBOL(tcp_v4_destroy_sock);
@@ -2339,11 +2339,6 @@ struct proto tcp_prot = {
.compat_setsockopt = compat_tcp_setsockopt,
.compat_getsockopt = compat_tcp_getsockopt,
#endif
-#ifdef CONFIG_MEMCG_KMEM
- .init_cgroup = tcp_init_cgroup,
- .destroy_cgroup = tcp_destroy_cgroup,
- .proto_cgroup = tcp_proto_cgroup,
-#endif
};
EXPORT_SYMBOL(tcp_prot);
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c
index ef4268d..e507825 100644
--- a/net/ipv4/tcp_memcontrol.c
+++ b/net/ipv4/tcp_memcontrol.c
@@ -8,60 +8,47 @@
int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{
+ struct mem_cgroup *parent = parent_mem_cgroup(memcg);
+ struct page_counter *counter_parent = NULL;
/*
* The root cgroup does not use page_counters, but rather,
* rely on the data already collected by the network
* subsystem
*/
- struct mem_cgroup *parent = parent_mem_cgroup(memcg);
- struct page_counter *counter_parent = NULL;
- struct cg_proto *cg_proto, *parent_cg;
-
- cg_proto = tcp_prot.proto_cgroup(memcg);
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
return 0;
- cg_proto->memory_pressure = 0;
- cg_proto->memcg = memcg;
+ memcg->tcp_mem.memory_pressure = 0;
- parent_cg = tcp_prot.proto_cgroup(parent);
- if (parent_cg)
- counter_parent = &parent_cg->memory_allocated;
+ if (parent)
+ counter_parent = &parent->tcp_mem.memory_allocated;
- page_counter_init(&cg_proto->memory_allocated, counter_parent);
+ page_counter_init(&memcg->tcp_mem.memory_allocated, counter_parent);
return 0;
}
-EXPORT_SYMBOL(tcp_init_cgroup);
void tcp_destroy_cgroup(struct mem_cgroup *memcg)
{
- struct cg_proto *cg_proto;
-
- cg_proto = tcp_prot.proto_cgroup(memcg);
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
return;
- if (cg_proto->active)
+ if (memcg->tcp_mem.active)
static_key_slow_dec(&memcg_socket_limit_enabled);
-
}
-EXPORT_SYMBOL(tcp_destroy_cgroup);
static int tcp_update_limit(struct mem_cgroup *memcg, unsigned long nr_pages)
{
- struct cg_proto *cg_proto;
int ret;
- cg_proto = tcp_prot.proto_cgroup(memcg);
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
return -EINVAL;
- ret = page_counter_limit(&cg_proto->memory_allocated, nr_pages);
+ ret = page_counter_limit(&memcg->tcp_mem.memory_allocated, nr_pages);
if (ret)
return ret;
- if (!cg_proto->active) {
+ if (!memcg->tcp_mem.active) {
/*
* The active flag needs to be written after the static_key
* update. This is what guarantees that the socket activation
@@ -79,7 +66,7 @@ static int tcp_update_limit(struct mem_cgroup *memcg, unsigned long nr_pages)
* patched in yet.
*/
static_key_slow_inc(&memcg_socket_limit_enabled);
- cg_proto->active = true;
+ memcg->tcp_mem.active = true;
}
return 0;
@@ -123,32 +110,32 @@ static ssize_t tcp_cgroup_write(struct kernfs_open_file *of,
static u64 tcp_cgroup_read(struct cgroup_subsys_state *css, struct cftype *cft)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
- struct cg_proto *cg_proto = tcp_prot.proto_cgroup(memcg);
u64 val;
switch (cft->private) {
case RES_LIMIT:
- if (!cg_proto)
- return PAGE_COUNTER_MAX;
- val = cg_proto->memory_allocated.limit;
+ if (memcg == root_mem_cgroup)
+ val = PAGE_COUNTER_MAX;
+ else
+ val = memcg->tcp_mem.memory_allocated.limit;
val *= PAGE_SIZE;
break;
case RES_USAGE:
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
val = atomic_long_read(&tcp_memory_allocated);
else
- val = page_counter_read(&cg_proto->memory_allocated);
+ val = page_counter_read(&memcg->tcp_mem.memory_allocated);
val *= PAGE_SIZE;
break;
case RES_FAILCNT:
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
return 0;
- val = cg_proto->memory_allocated.failcnt;
+ val = memcg->tcp_mem.memory_allocated.failcnt;
break;
case RES_MAX_USAGE:
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
return 0;
- val = cg_proto->memory_allocated.watermark;
+ val = memcg->tcp_mem.memory_allocated.watermark;
val *= PAGE_SIZE;
break;
default:
@@ -161,19 +148,17 @@ static ssize_t tcp_cgroup_reset(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off)
{
struct mem_cgroup *memcg;
- struct cg_proto *cg_proto;
memcg = mem_cgroup_from_css(of_css(of));
- cg_proto = tcp_prot.proto_cgroup(memcg);
- if (!cg_proto)
+ if (memcg == root_mem_cgroup)
return nbytes;
switch (of_cft(of)->private) {
case RES_MAX_USAGE:
- page_counter_reset_watermark(&cg_proto->memory_allocated);
+ page_counter_reset_watermark(&memcg->tcp_mem.memory_allocated);
break;
case RES_FAILCNT:
- cg_proto->memory_allocated.failcnt = 0;
+ memcg->tcp_mem.memory_allocated.failcnt = 0;
break;
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 7aa168a..7b83a65 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2821,8 +2821,8 @@ void sk_forced_mem_schedule(struct sock *sk, int size)
sk->sk_forward_alloc += amt * SK_MEM_QUANTUM;
sk_memory_allocated_add(sk, amt);
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
- mem_cgroup_charge_skmem(sk->sk_cgrp, amt);
+ if (mem_cgroup_sockets_enabled && sk->sk_memcg)
+ mem_cgroup_charge_skmem(sk->sk_memcg, amt);
}
/* Send a FIN. The caller locks the socket for us.
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index c5429a6..1bfb682 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1880,9 +1880,6 @@ struct proto tcpv6_prot = {
.compat_setsockopt = compat_tcp_setsockopt,
.compat_getsockopt = compat_tcp_getsockopt,
#endif
-#ifdef CONFIG_MEMCG_KMEM
- .proto_cgroup = tcp_proto_cgroup,
-#endif
.clear_sk = tcp_v6_clear_sk,
};
--
2.6.2
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | David Miller <davem@davemloft.net> |
|---|---|
| Date | 2015-11-25 17:30 +0100 |
| Subject | Re: [PATCH 08/13] net: tcp_memcontrol: simplify linkage between socket and page counter |
| Message-ID | <qyL7d-gt-35@gated-at.bofh.it> |
| In reply to | #1276803 |
From: Johannes Weiner <hannes@cmpxchg.org> Date: Tue, 24 Nov 2015 16:52:00 -0500 > There won't be any separate counters for socket memory consumed by > protocols other than TCP in the future. Remove the indirection and > link sockets directly to their owning memory cgroup. > > Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> > Reviewed-by: Vladimir Davydov <vdavydov@virtuozzo.com> Acked-by: David S. Miller <davem@davemloft.net> -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Johannes Weiner <hannes@cmpxchg.org> |
|---|---|
| Date | 2015-11-24 23:00 +0100 |
| Subject | [PATCH 05/13] net: tcp_memcontrol: remove dead per-memcg count of allocated sockets |
| Message-ID | <qytN2-5hB-51@gated-at.bofh.it> |
| In reply to | #1276786 |
The number of allocated sockets is used for calculations in the soft
limit phase, where packets are accepted but the socket is under memory
pressure. Since there is no soft limit phase in tcp_memcontrol, and
memory pressure is only entered when packets are already dropped, this
is actually dead code. Remove it.
As this is the last user of parent_cg_proto(), remove that too.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: David S. Miller <davem@davemloft.net>
Reviewed-by: Vladimir Davydov <vdavydov@virtuozzo.com>
---
include/linux/memcontrol.h | 1 -
include/net/sock.h | 39 +++------------------------------------
net/ipv4/tcp_memcontrol.c | 3 ---
3 files changed, 3 insertions(+), 40 deletions(-)
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 724b76a..cc45407 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -87,7 +87,6 @@ enum mem_cgroup_events_target {
struct cg_proto {
struct page_counter memory_allocated; /* Current allocated memory. */
- struct percpu_counter sockets_allocated; /* Current number of sockets. */
int memory_pressure;
bool active;
long sysctl_mem[3];
diff --git a/include/net/sock.h b/include/net/sock.h
index e27a8bb..7afbdab 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1095,19 +1095,9 @@ static inline void sk_refcnt_debug_release(const struct sock *sk)
#if defined(CONFIG_MEMCG_KMEM) && defined(CONFIG_NET)
extern struct static_key memcg_socket_limit_enabled;
-static inline struct cg_proto *parent_cg_proto(struct proto *proto,
- struct cg_proto *cg_proto)
-{
- return proto->proto_cgroup(parent_mem_cgroup(cg_proto->memcg));
-}
#define mem_cgroup_sockets_enabled static_key_false(&memcg_socket_limit_enabled)
#else
#define mem_cgroup_sockets_enabled 0
-static inline struct cg_proto *parent_cg_proto(struct proto *proto,
- struct cg_proto *cg_proto)
-{
- return NULL;
-}
#endif
static inline bool sk_stream_memory_free(const struct sock *sk)
@@ -1233,41 +1223,18 @@ sk_memory_allocated_sub(struct sock *sk, int amt)
static inline void sk_sockets_allocated_dec(struct sock *sk)
{
- struct proto *prot = sk->sk_prot;
-
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp) {
- struct cg_proto *cg_proto = sk->sk_cgrp;
-
- for (; cg_proto; cg_proto = parent_cg_proto(prot, cg_proto))
- percpu_counter_dec(&cg_proto->sockets_allocated);
- }
-
- percpu_counter_dec(prot->sockets_allocated);
+ percpu_counter_dec(sk->sk_prot->sockets_allocated);
}
static inline void sk_sockets_allocated_inc(struct sock *sk)
{
- struct proto *prot = sk->sk_prot;
-
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp) {
- struct cg_proto *cg_proto = sk->sk_cgrp;
-
- for (; cg_proto; cg_proto = parent_cg_proto(prot, cg_proto))
- percpu_counter_inc(&cg_proto->sockets_allocated);
- }
-
- percpu_counter_inc(prot->sockets_allocated);
+ percpu_counter_inc(sk->sk_prot->sockets_allocated);
}
static inline int
sk_sockets_allocated_read_positive(struct sock *sk)
{
- struct proto *prot = sk->sk_prot;
-
- if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
- return percpu_counter_read_positive(&sk->sk_cgrp->sockets_allocated);
-
- return percpu_counter_read_positive(prot->sockets_allocated);
+ return percpu_counter_read_positive(sk->sk_prot->sockets_allocated);
}
static inline int
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c
index d07579a..6759e0d 100644
--- a/net/ipv4/tcp_memcontrol.c
+++ b/net/ipv4/tcp_memcontrol.c
@@ -32,7 +32,6 @@ int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
counter_parent = &parent_cg->memory_allocated;
page_counter_init(&cg_proto->memory_allocated, counter_parent);
- percpu_counter_init(&cg_proto->sockets_allocated, 0, GFP_KERNEL);
return 0;
}
@@ -46,8 +45,6 @@ void tcp_destroy_cgroup(struct mem_cgroup *memcg)
if (!cg_proto)
return;
- percpu_counter_destroy(&cg_proto->sockets_allocated);
-
if (cg_proto->active)
static_key_slow_dec(&memcg_socket_limit_enabled);
--
2.6.2
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Johannes Weiner <hannes@cmpxchg.org> |
|---|---|
| Date | 2015-11-24 23:10 +0100 |
| Subject | [PATCH 13/13] mm: memcontrol: hook up vmpressure to socket pressure |
| Message-ID | <qytWH-5Av-29@gated-at.bofh.it> |
| In reply to | #1276786 |
Let the networking stack know when a memcg is under reclaim pressure
so that it can clamp its transmit windows accordingly.
Whenever the reclaim efficiency of a cgroup's LRU lists drops low
enough for a MEDIUM or HIGH vmpressure event to occur, assert a
pressure state in the socket and tcp memory code that tells it to curb
consumption growth from sockets associated with said control group.
Traditionally, vmpressure reports for the entire subtree of a memcg
under pressure, which drops useful information on the individual
groups reclaimed. However, it's too late to change the userinterface,
so add a second reporting mode that reports on the level of reclaim
instead of at the level of pressure, and use that report for sockets.
vmpressure events are naturally edge triggered, so for hysteresis
assert socket pressure for a second to allow for subsequent vmpressure
events to occur before letting the socket code return to normal.
This will likely need finetuning for a wider variety of workloads, but
for now stick to the vmpressure presets and keep hysteresis simple.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
include/linux/memcontrol.h | 32 ++++++++++++++++---
include/linux/vmpressure.h | 5 ++-
mm/memcontrol.c | 17 ++--------
mm/vmpressure.c | 78 +++++++++++++++++++++++++++++++++++-----------
mm/vmscan.c | 10 +++++-
5 files changed, 103 insertions(+), 39 deletions(-)
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index fae0aaf..a8df46c 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -249,6 +249,10 @@ struct mem_cgroup {
struct wb_domain cgwb_domain;
#endif
+#ifdef CONFIG_INET
+ unsigned long socket_pressure;
+#endif
+
/* List of events which userspace want to receive */
struct list_head event_list;
spinlock_t event_list_lock;
@@ -292,18 +296,34 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *, struct zone *);
bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg);
struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
-struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg);
static inline
struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){
return css ? container_of(css, struct mem_cgroup, css) : NULL;
}
+#define mem_cgroup_from_counter(counter, member) \
+ container_of(counter, struct mem_cgroup, member)
+
struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *,
struct mem_cgroup *,
struct mem_cgroup_reclaim_cookie *);
void mem_cgroup_iter_break(struct mem_cgroup *, struct mem_cgroup *);
+/**
+ * parent_mem_cgroup - find the accounting parent of a memcg
+ * @memcg: memcg whose parent to find
+ *
+ * Returns the parent memcg, or NULL if this is the root or the memory
+ * controller is in legacy no-hierarchy mode.
+ */
+static inline struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg)
+{
+ if (!memcg->memory.parent)
+ return NULL;
+ return mem_cgroup_from_counter(memcg->memory.parent, memory);
+}
+
static inline bool mem_cgroup_is_descendant(struct mem_cgroup *memcg,
struct mem_cgroup *root)
{
@@ -693,10 +713,14 @@ void mem_cgroup_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages);
static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg)
{
#ifdef CONFIG_MEMCG_KMEM
- return memcg->tcp_mem.memory_pressure;
-#else
- return false;
+ if (memcg->tcp_mem.memory_pressure)
+ return true;
#endif
+ do {
+ if (time_before(jiffies, memcg->socket_pressure))
+ return true;
+ } while ((memcg = parent_mem_cgroup(memcg)));
+ return false;
}
#else
#define mem_cgroup_sockets_enabled 0
diff --git a/include/linux/vmpressure.h b/include/linux/vmpressure.h
index 3e45358..a77b142 100644
--- a/include/linux/vmpressure.h
+++ b/include/linux/vmpressure.h
@@ -12,6 +12,9 @@
struct vmpressure {
unsigned long scanned;
unsigned long reclaimed;
+
+ unsigned long tree_scanned;
+ unsigned long tree_reclaimed;
/* The lock is used to keep the scanned/reclaimed above in sync. */
struct spinlock sr_lock;
@@ -26,7 +29,7 @@ struct vmpressure {
struct mem_cgroup;
#ifdef CONFIG_MEMCG
-extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
+extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
unsigned long scanned, unsigned long reclaimed);
extern void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 59555b0..a0da91f 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1091,9 +1091,6 @@ bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg)
return ret;
}
-#define mem_cgroup_from_counter(counter, member) \
- container_of(counter, struct mem_cgroup, member)
-
/**
* mem_cgroup_margin - calculate chargeable space of a memory cgroup
* @memcg: the memory cgroup
@@ -4159,17 +4156,6 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
kfree(memcg);
}
-/*
- * Returns the parent mem_cgroup in memcgroup hierarchy with hierarchy enabled.
- */
-struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg)
-{
- if (!memcg->memory.parent)
- return NULL;
- return mem_cgroup_from_counter(memcg->memory.parent, memory);
-}
-EXPORT_SYMBOL(parent_mem_cgroup);
-
static struct cgroup_subsys_state * __ref
mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
{
@@ -4210,6 +4196,9 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
#ifdef CONFIG_CGROUP_WRITEBACK
INIT_LIST_HEAD(&memcg->cgwb_list);
#endif
+#ifdef CONFIG_INET
+ memcg->socket_pressure = jiffies;
+#endif
return &memcg->css;
free_out:
diff --git a/mm/vmpressure.c b/mm/vmpressure.c
index 4c25e62..af262bb 100644
--- a/mm/vmpressure.c
+++ b/mm/vmpressure.c
@@ -137,14 +137,11 @@ struct vmpressure_event {
};
static bool vmpressure_event(struct vmpressure *vmpr,
- unsigned long scanned, unsigned long reclaimed)
+ enum vmpressure_levels level)
{
struct vmpressure_event *ev;
- enum vmpressure_levels level;
bool signalled = false;
- level = vmpressure_calc_level(scanned, reclaimed);
-
mutex_lock(&vmpr->events_lock);
list_for_each_entry(ev, &vmpr->events, node) {
@@ -164,6 +161,7 @@ static void vmpressure_work_fn(struct work_struct *work)
struct vmpressure *vmpr = work_to_vmpressure(work);
unsigned long scanned;
unsigned long reclaimed;
+ enum vmpressure_levels level;
spin_lock(&vmpr->sr_lock);
/*
@@ -174,19 +172,21 @@ static void vmpressure_work_fn(struct work_struct *work)
* here. No need for any locks here since we don't care if
* vmpr->reclaimed is in sync.
*/
- scanned = vmpr->scanned;
+ scanned = vmpr->tree_scanned;
if (!scanned) {
spin_unlock(&vmpr->sr_lock);
return;
}
- reclaimed = vmpr->reclaimed;
- vmpr->scanned = 0;
- vmpr->reclaimed = 0;
+ reclaimed = vmpr->tree_reclaimed;
+ vmpr->tree_scanned = 0;
+ vmpr->tree_reclaimed = 0;
spin_unlock(&vmpr->sr_lock);
+ level = vmpressure_calc_level(scanned, reclaimed);
+
do {
- if (vmpressure_event(vmpr, scanned, reclaimed))
+ if (vmpressure_event(vmpr, level))
break;
/*
* If not handled, propagate the event upward into the
@@ -199,6 +199,7 @@ static void vmpressure_work_fn(struct work_struct *work)
* vmpressure() - Account memory pressure through scanned/reclaimed ratio
* @gfp: reclaimer's gfp mask
* @memcg: cgroup memory controller handle
+ * @tree: legacy subtree mode
* @scanned: number of pages scanned
* @reclaimed: number of pages reclaimed
*
@@ -206,9 +207,16 @@ static void vmpressure_work_fn(struct work_struct *work)
* "instantaneous" memory pressure (scanned/reclaimed ratio). The raw
* pressure index is then further refined and averaged over time.
*
+ * If @tree is set, vmpressure is in traditional userspace reporting
+ * mode: @memcg is considered the pressure root and userspace is
+ * notified of the entire subtree's reclaim efficiency.
+ *
+ * If @tree is not set, reclaim efficiency is recorded for @memcg, and
+ * only in-kernel users are notified.
+ *
* This function does not return any value.
*/
-void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
+void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
unsigned long scanned, unsigned long reclaimed)
{
struct vmpressure *vmpr = memcg_to_vmpressure(memcg);
@@ -238,15 +246,47 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
if (!scanned)
return;
- spin_lock(&vmpr->sr_lock);
- vmpr->scanned += scanned;
- vmpr->reclaimed += reclaimed;
- scanned = vmpr->scanned;
- spin_unlock(&vmpr->sr_lock);
+ if (tree) {
+ spin_lock(&vmpr->sr_lock);
+ vmpr->tree_scanned += scanned;
+ vmpr->tree_reclaimed += reclaimed;
+ scanned = vmpr->scanned;
+ spin_unlock(&vmpr->sr_lock);
- if (scanned < vmpressure_win)
- return;
- schedule_work(&vmpr->work);
+ if (scanned < vmpressure_win)
+ return;
+ schedule_work(&vmpr->work);
+ } else {
+ enum vmpressure_levels level;
+
+ /* For now, no users for root-level efficiency */
+ if (memcg == root_mem_cgroup)
+ return;
+
+ spin_lock(&vmpr->sr_lock);
+ scanned = vmpr->scanned += scanned;
+ reclaimed = vmpr->reclaimed += reclaimed;
+ if (scanned < vmpressure_win) {
+ spin_unlock(&vmpr->sr_lock);
+ return;
+ }
+ vmpr->scanned = vmpr->reclaimed = 0;
+ spin_unlock(&vmpr->sr_lock);
+
+ level = vmpressure_calc_level(scanned, reclaimed);
+
+ if (level > VMPRESSURE_LOW) {
+ /*
+ * Let the socket buffer allocator know that
+ * we are having trouble reclaiming LRU pages.
+ *
+ * For hysteresis keep the pressure state
+ * asserted for a second in which subsequent
+ * pressure events can occur.
+ */
+ memcg->socket_pressure = jiffies + HZ;
+ }
+ }
}
/**
@@ -276,7 +316,7 @@ void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio)
* to the vmpressure() basically means that we signal 'critical'
* level.
*/
- vmpressure(gfp, memcg, vmpressure_win, 0);
+ vmpressure(gfp, memcg, true, vmpressure_win, 0);
}
/**
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 97ba9e1..50e54c0 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2396,6 +2396,7 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
memcg = mem_cgroup_iter(root, NULL, &reclaim);
do {
unsigned long lru_pages;
+ unsigned long reclaimed;
unsigned long scanned;
struct lruvec *lruvec;
int swappiness;
@@ -2408,6 +2409,7 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
lruvec = mem_cgroup_zone_lruvec(zone, memcg);
swappiness = mem_cgroup_swappiness(memcg);
+ reclaimed = sc->nr_reclaimed;
scanned = sc->nr_scanned;
shrink_lruvec(lruvec, swappiness, sc, &lru_pages);
@@ -2418,6 +2420,11 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
memcg, sc->nr_scanned - scanned,
lru_pages);
+ /* Record the group's reclaim efficiency */
+ vmpressure(sc->gfp_mask, memcg, false,
+ sc->nr_scanned - scanned,
+ sc->nr_reclaimed - reclaimed);
+
/*
* Direct reclaim and kswapd have to scan all memory
* cgroups to fulfill the overall scan target for the
@@ -2449,7 +2456,8 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
reclaim_state->reclaimed_slab = 0;
}
- vmpressure(sc->gfp_mask, sc->target_mem_cgroup,
+ /* Record the subtree's reclaim efficiency */
+ vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true,
sc->nr_scanned - nr_scanned,
sc->nr_reclaimed - nr_reclaimed);
--
2.6.2
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | David Miller <davem@davemloft.net> |
|---|---|
| Date | 2015-11-25 17:40 +0100 |
| Subject | Re: [PATCH 13/13] mm: memcontrol: hook up vmpressure to socket pressure |
| Message-ID | <qyLgS-jU-35@gated-at.bofh.it> |
| In reply to | #1276808 |
From: Johannes Weiner <hannes@cmpxchg.org> Date: Tue, 24 Nov 2015 16:59:40 -0500 > Let the networking stack know when a memcg is under reclaim pressure > so that it can clamp its transmit windows accordingly. > > Whenever the reclaim efficiency of a cgroup's LRU lists drops low > enough for a MEDIUM or HIGH vmpressure event to occur, assert a > pressure state in the socket and tcp memory code that tells it to curb > consumption growth from sockets associated with said control group. > > Traditionally, vmpressure reports for the entire subtree of a memcg > under pressure, which drops useful information on the individual > groups reclaimed. However, it's too late to change the userinterface, > so add a second reporting mode that reports on the level of reclaim > instead of at the level of pressure, and use that report for sockets. > > vmpressure events are naturally edge triggered, so for hysteresis > assert socket pressure for a second to allow for subsequent vmpressure > events to occur before letting the socket code return to normal. > > This will likely need finetuning for a wider variety of workloads, but > for now stick to the vmpressure presets and keep hysteresis simple. > > Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> Acked-by: David S. Miller <davem@davemloft.net> -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Vladimir Davydov <vdavydov@virtuozzo.com> |
|---|---|
| Date | 2015-11-30 12:40 +0100 |
| Subject | Re: [PATCH 13/13] mm: memcontrol: hook up vmpressure to socket pressure |
| Message-ID | <qAuYi-2X2-31@gated-at.bofh.it> |
| In reply to | #1276808 |
On Tue, Nov 24, 2015 at 04:59:40PM -0500, Johannes Weiner wrote:
...
> @@ -2396,6 +2396,7 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
> memcg = mem_cgroup_iter(root, NULL, &reclaim);
> do {
> unsigned long lru_pages;
> + unsigned long reclaimed;
> unsigned long scanned;
> struct lruvec *lruvec;
> int swappiness;
> @@ -2408,6 +2409,7 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
>
> lruvec = mem_cgroup_zone_lruvec(zone, memcg);
> swappiness = mem_cgroup_swappiness(memcg);
> + reclaimed = sc->nr_reclaimed;
> scanned = sc->nr_scanned;
>
> shrink_lruvec(lruvec, swappiness, sc, &lru_pages);
> @@ -2418,6 +2420,11 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
> memcg, sc->nr_scanned - scanned,
> lru_pages);
>
> + /* Record the group's reclaim efficiency */
> + vmpressure(sc->gfp_mask, memcg, false,
> + sc->nr_scanned - scanned,
> + sc->nr_reclaimed - reclaimed);
> +
Suppose we have the following cgroup configuration.
A __ B
\_ C
A is empty (which is natural for the unified hierarchy AFAIU). B has
some workload running in it, and C generates socket pressure. Due to the
socket pressure coming from C we start reclaim in A, which results in
thrashing of B, but we might not put sockets under pressure in A or C,
because vmpressure does not account pages scanned/reclaimed in B when
generating a vmpressure event for A or C. This might result in
aggressive reclaim and thrashing in B w/o generating a signal for C to
stop growing socket buffers.
Do you think such a situation is possible? If so, would it make sense to
switch to post-order walk in shrink_zone and pass sub-tree
scanned/reclaimed stats to vmpressure for each scanned memcg?
Thanks,
Vladimir
> /*
> * Direct reclaim and kswapd have to scan all memory
> * cgroups to fulfill the overall scan target for the
> @@ -2449,7 +2456,8 @@ static bool shrink_zone(struct zone *zone, struct scan_control *sc,
> reclaim_state->reclaimed_slab = 0;
> }
>
> - vmpressure(sc->gfp_mask, sc->target_mem_cgroup,
> + /* Record the subtree's reclaim efficiency */
> + vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true,
> sc->nr_scanned - nr_scanned,
> sc->nr_reclaimed - nr_reclaimed);
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Johannes Weiner <hannes@cmpxchg.org> |
|---|---|
| Date | 2015-11-30 17:00 +0100 |
| Subject | Re: [PATCH 13/13] mm: memcontrol: hook up vmpressure to socket pressure |
| Message-ID | <qAz1U-5xV-23@gated-at.bofh.it> |
| In reply to | #1279787 |
On Mon, Nov 30, 2015 at 02:36:28PM +0300, Vladimir Davydov wrote: > Suppose we have the following cgroup configuration. > > A __ B > \_ C > > A is empty (which is natural for the unified hierarchy AFAIU). B has > some workload running in it, and C generates socket pressure. Due to the > socket pressure coming from C we start reclaim in A, which results in > thrashing of B, but we might not put sockets under pressure in A or C, > because vmpressure does not account pages scanned/reclaimed in B when > generating a vmpressure event for A or C. This might result in > aggressive reclaim and thrashing in B w/o generating a signal for C to > stop growing socket buffers. > > Do you think such a situation is possible? If so, would it make sense to > switch to post-order walk in shrink_zone and pass sub-tree > scanned/reclaimed stats to vmpressure for each scanned memcg? In that case the LRU pages in C would experience pressure as well, which would then reign in the sockets in C. There must be some LRU pages in there, otherwise who is creating socket pressure? The same applies to shrinkers. All secondary reclaim is driven by LRU reclaim results. I can see that there is some unfairness in distributing memcg reclaim pressure purely based on LRU size, because there are scenarios where the auxiliary objects (incl. sockets, but mostly shrinker pools) amount to a significant portion of the group's memory footprint. But substitute group for NUMA node and we've had this behavior for years. I'm not sure it's actually a problem in practice. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Vladimir Davydov <vdavydov@virtuozzo.com> |
|---|---|
| Date | 2015-11-30 17:20 +0100 |
| Subject | Re: [PATCH 13/13] mm: memcontrol: hook up vmpressure to socket pressure |
| Message-ID | <qAzlf-5Uw-1@gated-at.bofh.it> |
| In reply to | #1280027 |
On Mon, Nov 30, 2015 at 10:58:38AM -0500, Johannes Weiner wrote: > On Mon, Nov 30, 2015 at 02:36:28PM +0300, Vladimir Davydov wrote: > > Suppose we have the following cgroup configuration. > > > > A __ B > > \_ C > > > > A is empty (which is natural for the unified hierarchy AFAIU). B has > > some workload running in it, and C generates socket pressure. Due to the > > socket pressure coming from C we start reclaim in A, which results in > > thrashing of B, but we might not put sockets under pressure in A or C, > > because vmpressure does not account pages scanned/reclaimed in B when > > generating a vmpressure event for A or C. This might result in > > aggressive reclaim and thrashing in B w/o generating a signal for C to > > stop growing socket buffers. > > > > Do you think such a situation is possible? If so, would it make sense to > > switch to post-order walk in shrink_zone and pass sub-tree > > scanned/reclaimed stats to vmpressure for each scanned memcg? > > In that case the LRU pages in C would experience pressure as well, > which would then reign in the sockets in C. There must be some LRU > pages in there, otherwise who is creating socket pressure? > > The same applies to shrinkers. All secondary reclaim is driven by LRU > reclaim results. > > I can see that there is some unfairness in distributing memcg reclaim > pressure purely based on LRU size, because there are scenarios where > the auxiliary objects (incl. sockets, but mostly shrinker pools) > amount to a significant portion of the group's memory footprint. But > substitute group for NUMA node and we've had this behavior for > years. I'm not sure it's actually a problem in practice. > Fiar enough. Let's wait until we hit this problem in real world then. The patch looks good to me. Reviewed-by: Vladimir Davydov <vdavydov@virtuozzo.com> Thanks, Vladimir -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | linux.kernel
csiph-web