linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] mm: Move maxable seq_file logic into a single place
@ 2019-01-24  6:17 Chris Down
  2019-01-24  8:58 ` Michal Hocko
  2019-01-24 16:09 ` Johannes Weiner
  0 siblings, 2 replies; 5+ messages in thread
From: Chris Down @ 2019-01-24  6:17 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Johannes Weiner, Tejun Heo, Roman Gushchin, linux-kernel,
	cgroups, linux-mm, kernel-team

memcg has a significant number of files exposed to kernfs where their
value is either exposed directly or is "max" in the case of
PAGE_COUNTER_MAX.

There's a fair amount of duplicated code here, since each file involves
turning a seq_file to a css, getting the memcg from the css, safely
reading the counter value, and then doing the right thing depending on
whether the value is PAGE_COUNTER_MAX or not.

This patch adds the macro DEFINE_MEMCG_MAX_OR_VAL, which defines and
implements a generic way to do this work, avoiding fragmenting logic.

Signed-off-by: Chris Down <chris@chrisdown.name>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: Roman Gushchin <guro@fb.com>
Cc: linux-kernel@vger.kernel.org
Cc: cgroups@vger.kernel.org
Cc: linux-mm@kvack.org
Cc: kernel-team@fb.com
---
 mm/memcontrol.c | 78 ++++++++++++-------------------------------------
 1 file changed, 18 insertions(+), 60 deletions(-)

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 18f4aefbe0bf..90e2e0ff5ed9 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -261,6 +261,19 @@ struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr)
 	return &container_of(vmpr, struct mem_cgroup, vmpressure)->css;
 }
 
+/* Convenience macro to define seq_file mutators that can return "max" */
+#define DEFINE_MEMCG_MAX_OR_VAL(name, key)				    \
+	static int name(struct seq_file *m, void *v)			    \
+	{								    \
+		struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); \
+		unsigned long val = READ_ONCE(memcg->key);		    \
+		if (val == PAGE_COUNTER_MAX)				    \
+			seq_puts(m, "max\n");				    \
+		else							    \
+			seq_printf(m, "%llu\n", (u64)val * PAGE_SIZE);	    \
+		return 0;						    \
+	}
+
 #ifdef CONFIG_MEMCG_KMEM
 /*
  * This will be the memcg's index in each cache's ->memcg_params.memcg_caches.
@@ -5383,18 +5396,7 @@ static u64 memory_current_read(struct cgroup_subsys_state *css,
 	return (u64)page_counter_read(&memcg->memory) * PAGE_SIZE;
 }
 
-static int memory_min_show(struct seq_file *m, void *v)
-{
-	struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
-	unsigned long min = READ_ONCE(memcg->memory.min);
-
-	if (min == PAGE_COUNTER_MAX)
-		seq_puts(m, "max\n");
-	else
-		seq_printf(m, "%llu\n", (u64)min * PAGE_SIZE);
-
-	return 0;
-}
+DEFINE_MEMCG_MAX_OR_VAL(memory_min_show, memory.min)
 
 static ssize_t memory_min_write(struct kernfs_open_file *of,
 				char *buf, size_t nbytes, loff_t off)
@@ -5413,18 +5415,7 @@ static ssize_t memory_min_write(struct kernfs_open_file *of,
 	return nbytes;
 }
 
-static int memory_low_show(struct seq_file *m, void *v)
-{
-	struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
-	unsigned long low = READ_ONCE(memcg->memory.low);
-
-	if (low == PAGE_COUNTER_MAX)
-		seq_puts(m, "max\n");
-	else
-		seq_printf(m, "%llu\n", (u64)low * PAGE_SIZE);
-
-	return 0;
-}
+DEFINE_MEMCG_MAX_OR_VAL(memory_low_show, memory.low)
 
 static ssize_t memory_low_write(struct kernfs_open_file *of,
 				char *buf, size_t nbytes, loff_t off)
@@ -5443,18 +5434,7 @@ static ssize_t memory_low_write(struct kernfs_open_file *of,
 	return nbytes;
 }
 
-static int memory_high_show(struct seq_file *m, void *v)
-{
-	struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
-	unsigned long high = READ_ONCE(memcg->high);
-
-	if (high == PAGE_COUNTER_MAX)
-		seq_puts(m, "max\n");
-	else
-		seq_printf(m, "%llu\n", (u64)high * PAGE_SIZE);
-
-	return 0;
-}
+DEFINE_MEMCG_MAX_OR_VAL(memory_high_show, high)
 
 static ssize_t memory_high_write(struct kernfs_open_file *of,
 				 char *buf, size_t nbytes, loff_t off)
@@ -5480,18 +5460,7 @@ static ssize_t memory_high_write(struct kernfs_open_file *of,
 	return nbytes;
 }
 
-static int memory_max_show(struct seq_file *m, void *v)
-{
-	struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
-	unsigned long max = READ_ONCE(memcg->memory.max);
-
-	if (max == PAGE_COUNTER_MAX)
-		seq_puts(m, "max\n");
-	else
-		seq_printf(m, "%llu\n", (u64)max * PAGE_SIZE);
-
-	return 0;
-}
+DEFINE_MEMCG_MAX_OR_VAL(memory_max_show, memory.max)
 
 static ssize_t memory_max_write(struct kernfs_open_file *of,
 				char *buf, size_t nbytes, loff_t off)
@@ -6620,18 +6589,7 @@ static u64 swap_current_read(struct cgroup_subsys_state *css,
 	return (u64)page_counter_read(&memcg->swap) * PAGE_SIZE;
 }
 
-static int swap_max_show(struct seq_file *m, void *v)
-{
-	struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
-	unsigned long max = READ_ONCE(memcg->swap.max);
-
-	if (max == PAGE_COUNTER_MAX)
-		seq_puts(m, "max\n");
-	else
-		seq_printf(m, "%llu\n", (u64)max * PAGE_SIZE);
-
-	return 0;
-}
+DEFINE_MEMCG_MAX_OR_VAL(swap_max_show, swap.max)
 
 static ssize_t swap_max_write(struct kernfs_open_file *of,
 			      char *buf, size_t nbytes, loff_t off)
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] mm: Move maxable seq_file logic into a single place
  2019-01-24  6:17 [PATCH] mm: Move maxable seq_file logic into a single place Chris Down
@ 2019-01-24  8:58 ` Michal Hocko
  2019-01-24 16:09 ` Johannes Weiner
  1 sibling, 0 replies; 5+ messages in thread
From: Michal Hocko @ 2019-01-24  8:58 UTC (permalink / raw)
  To: Chris Down
  Cc: Andrew Morton, Johannes Weiner, Tejun Heo, Roman Gushchin,
	linux-kernel, cgroups, linux-mm, kernel-team

On Thu 24-01-19 01:17:18, Chris Down wrote:
> memcg has a significant number of files exposed to kernfs where their
> value is either exposed directly or is "max" in the case of
> PAGE_COUNTER_MAX.
> 
> There's a fair amount of duplicated code here, since each file involves
> turning a seq_file to a css, getting the memcg from the css, safely
> reading the counter value, and then doing the right thing depending on
> whether the value is PAGE_COUNTER_MAX or not.
> 
> This patch adds the macro DEFINE_MEMCG_MAX_OR_VAL, which defines and
> implements a generic way to do this work, avoiding fragmenting logic.

I am not a huge fan of macro defined functions but it is true this will
save more LOC than a simple helper used by each $foo_show function.

> Signed-off-by: Chris Down <chris@chrisdown.name>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Johannes Weiner <hannes@cmpxchg.org>
> Cc: Tejun Heo <tj@kernel.org>
> Cc: Roman Gushchin <guro@fb.com>
> Cc: linux-kernel@vger.kernel.org
> Cc: cgroups@vger.kernel.org
> Cc: linux-mm@kvack.org
> Cc: kernel-team@fb.com

Acked-by: Michal Hocko <mhocko@suse.com>

Thanks!
> ---
> mm/memcontrol.c | 78 ++++++++++++-------------------------------------
> 1 file changed, 18 insertions(+), 60 deletions(-)
> 
> diff --git a/mm/memcontrol.c b/mm/memcontrol.c
> index 18f4aefbe0bf..90e2e0ff5ed9 100644
> --- a/mm/memcontrol.c
> +++ b/mm/memcontrol.c
> @@ -261,6 +261,19 @@ struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr)
> 	return &container_of(vmpr, struct mem_cgroup, vmpressure)->css;
> }
> 
> +/* Convenience macro to define seq_file mutators that can return "max" */
> +#define DEFINE_MEMCG_MAX_OR_VAL(name, key)				    \
> +	static int name(struct seq_file *m, void *v)			    \
> +	{								    \
> +		struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); \
> +		unsigned long val = READ_ONCE(memcg->key);		    \
> +		if (val == PAGE_COUNTER_MAX)				    \
> +			seq_puts(m, "max\n");				    \
> +		else							    \
> +			seq_printf(m, "%llu\n", (u64)val * PAGE_SIZE);	    \
> +		return 0;						    \
> +	}
> +
> #ifdef CONFIG_MEMCG_KMEM
> /*
>  * This will be the memcg's index in each cache's ->memcg_params.memcg_caches.
> @@ -5383,18 +5396,7 @@ static u64 memory_current_read(struct cgroup_subsys_state *css,
> 	return (u64)page_counter_read(&memcg->memory) * PAGE_SIZE;
> }
> 
> -static int memory_min_show(struct seq_file *m, void *v)
> -{
> -	struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
> -	unsigned long min = READ_ONCE(memcg->memory.min);
> -
> -	if (min == PAGE_COUNTER_MAX)
> -		seq_puts(m, "max\n");
> -	else
> -		seq_printf(m, "%llu\n", (u64)min * PAGE_SIZE);
> -
> -	return 0;
> -}
> +DEFINE_MEMCG_MAX_OR_VAL(memory_min_show, memory.min)
> 
> static ssize_t memory_min_write(struct kernfs_open_file *of,
> 				char *buf, size_t nbytes, loff_t off)
> @@ -5413,18 +5415,7 @@ static ssize_t memory_min_write(struct kernfs_open_file *of,
> 	return nbytes;
> }
> 
> -static int memory_low_show(struct seq_file *m, void *v)
> -{
> -	struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
> -	unsigned long low = READ_ONCE(memcg->memory.low);
> -
> -	if (low == PAGE_COUNTER_MAX)
> -		seq_puts(m, "max\n");
> -	else
> -		seq_printf(m, "%llu\n", (u64)low * PAGE_SIZE);
> -
> -	return 0;
> -}
> +DEFINE_MEMCG_MAX_OR_VAL(memory_low_show, memory.low)
> 
> static ssize_t memory_low_write(struct kernfs_open_file *of,
> 				char *buf, size_t nbytes, loff_t off)
> @@ -5443,18 +5434,7 @@ static ssize_t memory_low_write(struct kernfs_open_file *of,
> 	return nbytes;
> }
> 
> -static int memory_high_show(struct seq_file *m, void *v)
> -{
> -	struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
> -	unsigned long high = READ_ONCE(memcg->high);
> -
> -	if (high == PAGE_COUNTER_MAX)
> -		seq_puts(m, "max\n");
> -	else
> -		seq_printf(m, "%llu\n", (u64)high * PAGE_SIZE);
> -
> -	return 0;
> -}
> +DEFINE_MEMCG_MAX_OR_VAL(memory_high_show, high)
> 
> static ssize_t memory_high_write(struct kernfs_open_file *of,
> 				 char *buf, size_t nbytes, loff_t off)
> @@ -5480,18 +5460,7 @@ static ssize_t memory_high_write(struct kernfs_open_file *of,
> 	return nbytes;
> }
> 
> -static int memory_max_show(struct seq_file *m, void *v)
> -{
> -	struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
> -	unsigned long max = READ_ONCE(memcg->memory.max);
> -
> -	if (max == PAGE_COUNTER_MAX)
> -		seq_puts(m, "max\n");
> -	else
> -		seq_printf(m, "%llu\n", (u64)max * PAGE_SIZE);
> -
> -	return 0;
> -}
> +DEFINE_MEMCG_MAX_OR_VAL(memory_max_show, memory.max)
> 
> static ssize_t memory_max_write(struct kernfs_open_file *of,
> 				char *buf, size_t nbytes, loff_t off)
> @@ -6620,18 +6589,7 @@ static u64 swap_current_read(struct cgroup_subsys_state *css,
> 	return (u64)page_counter_read(&memcg->swap) * PAGE_SIZE;
> }
> 
> -static int swap_max_show(struct seq_file *m, void *v)
> -{
> -	struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
> -	unsigned long max = READ_ONCE(memcg->swap.max);
> -
> -	if (max == PAGE_COUNTER_MAX)
> -		seq_puts(m, "max\n");
> -	else
> -		seq_printf(m, "%llu\n", (u64)max * PAGE_SIZE);
> -
> -	return 0;
> -}
> +DEFINE_MEMCG_MAX_OR_VAL(swap_max_show, swap.max)
> 
> static ssize_t swap_max_write(struct kernfs_open_file *of,
> 			      char *buf, size_t nbytes, loff_t off)
> -- 
> 2.20.1

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] mm: Move maxable seq_file logic into a single place
  2019-01-24  6:17 [PATCH] mm: Move maxable seq_file logic into a single place Chris Down
  2019-01-24  8:58 ` Michal Hocko
@ 2019-01-24 16:09 ` Johannes Weiner
  2019-01-24 16:56   ` Chris Down
  1 sibling, 1 reply; 5+ messages in thread
From: Johannes Weiner @ 2019-01-24 16:09 UTC (permalink / raw)
  To: Chris Down
  Cc: Andrew Morton, Tejun Heo, Roman Gushchin, linux-kernel, cgroups,
	linux-mm, kernel-team

On Thu, Jan 24, 2019 at 01:17:18AM -0500, Chris Down wrote:
> memcg has a significant number of files exposed to kernfs where their
> value is either exposed directly or is "max" in the case of
> PAGE_COUNTER_MAX.
> 
> There's a fair amount of duplicated code here, since each file involves
> turning a seq_file to a css, getting the memcg from the css, safely
> reading the counter value, and then doing the right thing depending on
> whether the value is PAGE_COUNTER_MAX or not.
> 
> This patch adds the macro DEFINE_MEMCG_MAX_OR_VAL, which defines and
> implements a generic way to do this work, avoiding fragmenting logic.
> 
> Signed-off-by: Chris Down <chris@chrisdown.name>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Johannes Weiner <hannes@cmpxchg.org>
> Cc: Tejun Heo <tj@kernel.org>
> Cc: Roman Gushchin <guro@fb.com>
> Cc: linux-kernel@vger.kernel.org
> Cc: cgroups@vger.kernel.org
> Cc: linux-mm@kvack.org
> Cc: kernel-team@fb.com
> ---
> mm/memcontrol.c | 78 ++++++++++++-------------------------------------
> 1 file changed, 18 insertions(+), 60 deletions(-)

I think this increases complexity more than it saves LOC,
unfortunately.

The current situation is a bit repetitive, but much more obviously
correct. And we're not planning on adding many more of those memcg
interface files, so I this doesn't seem to be an improvement re:
maintainability and future extensibility of the code.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] mm: Move maxable seq_file logic into a single place
  2019-01-24 16:09 ` Johannes Weiner
@ 2019-01-24 16:56   ` Chris Down
  2019-01-24 19:25     ` Chris Down
  0 siblings, 1 reply; 5+ messages in thread
From: Chris Down @ 2019-01-24 16:56 UTC (permalink / raw)
  To: Johannes Weiner
  Cc: Andrew Morton, Tejun Heo, Roman Gushchin, linux-kernel, cgroups,
	linux-mm, kernel-team

Johannes Weiner writes:
>I think this increases complexity more than it saves LOC,
>unfortunately.
>
>The current situation is a bit repetitive, but much more obviously
>correct. And we're not planning on adding many more of those memcg
>interface files, so I this doesn't seem to be an improvement re:
>maintainability and future extensibility of the code.

Hmm, my main goal in the patch was not really reduction of LOC, but more around 
centralising logic so that it's clear where these functions are unique and 
where they are completely the same. My initial reaction upon reading these was 
mostly to feel like I'm missing something due to the large amount of similarity 
between them, wondering if the change in mem_cgroup/page_counter access is 
really the only thing to look at, so my goal was primarily to reduce confusion 
(although of course this is subjective, I can also see your point about how 
having "memory.low" and the like without context can also be confusing).

I think using a macro is not ideal, but unfortunately without it a lot of the 
complexity can't really be abstracted easily.

If not this, what would you think about a patch that adds two new functions:

1. mem_cgroup_from_seq
2. mem_cgroup_write_max_or_val

This won't be able to reduce as much of the overlap as the macro, but it still 
will centralise a lot of the logic.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] mm: Move maxable seq_file logic into a single place
  2019-01-24 16:56   ` Chris Down
@ 2019-01-24 19:25     ` Chris Down
  0 siblings, 0 replies; 5+ messages in thread
From: Chris Down @ 2019-01-24 19:25 UTC (permalink / raw)
  To: Johannes Weiner
  Cc: Andrew Morton, Tejun Heo, Roman Gushchin, linux-kernel, cgroups,
	linux-mm, kernel-team

I'm going to abandon this patch in favour of a patch series which does it 
without macros, but still reduces code duplication fairly significantly. I'll 
send it out shortly.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2019-01-24 20:12 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-24  6:17 [PATCH] mm: Move maxable seq_file logic into a single place Chris Down
2019-01-24  8:58 ` Michal Hocko
2019-01-24 16:09 ` Johannes Weiner
2019-01-24 16:56   ` Chris Down
2019-01-24 19:25     ` Chris Down

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).