Commit f86b810c authored by Chris Down's avatar Chris Down Committed by Linus Torvalds
Browse files

mm, memcg: prevent memory.low load/store tearing



This can be set concurrently with reads, which may cause the wrong value
to be propagated.

Signed-off-by: default avatarChris Down <chris@chrisdown.name>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Acked-by: default avatarMichal Hocko <mhocko@suse.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Roman Gushchin <guro@fb.com>
Cc: Tejun Heo <tj@kernel.org>
Link: http://lkml.kernel.org/r/448206f44b0fa7be9dad2ca2601d2bcb2c0b7844.1584034301.git.chris@chrisdown.name


Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 15b42562
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ static void propagate_protected_usage(struct page_counter *c,
				      unsigned long usage)
{
	unsigned long protected, old_protected;
	unsigned long low;
	long delta;

	if (!c->parent)
@@ -30,8 +31,9 @@ static void propagate_protected_usage(struct page_counter *c,
			atomic_long_add(delta, &c->parent->children_min_usage);
	}

	if (c->low || atomic_long_read(&c->low_usage)) {
		protected = min(usage, c->low);
	low = READ_ONCE(c->low);
	if (low || atomic_long_read(&c->low_usage)) {
		protected = min(usage, low);
		old_protected = atomic_long_xchg(&c->low_usage, protected);
		delta = protected - old_protected;
		if (delta)
@@ -222,7 +224,7 @@ void page_counter_set_low(struct page_counter *counter, unsigned long nr_pages)
{
	struct page_counter *c;

	counter->low = nr_pages;
	WRITE_ONCE(counter->low, nr_pages);

	for (c = counter; c; c = c->parent)
		propagate_protected_usage(c, atomic_long_read(&c->usage));