[LTP] [PATCH] memcg/memcontrol04: Fix the judgment error in test_memcg_low()

Jin Guojie guojie.jin@gmail.com
Wed Dec 4 08:36:20 CET 2024


Hi Andrea,

I carefully analyzed the description in memcontrol04.c and the memory
allocation in the code, and found no problems with the case.
In addition, memcontrol04.c comes from test_memcontrol.c in kernel
selftests, and the contents of the two are exactly the same.
By the way, test_memcontrol.c in kselftest also failed the test. The
error is "nonzero memory.events: low in the unprotected A/B/E group",
exactly the same as memcontrol04.c.
It is a reported problem in the kernel mailing lists, but no one has solved it.
(https://lore.kernel.org/all/20230522095233.4246-2-haifeng.xu@shopee.com/T/#mfda771d975e71816ae70d4ac35f957a56cb12bb1)

According to the hint in your previous email, "to take a look at the
kernel, because it could be there's an underlying bug somewhere",
I checked the processing of memory.low in the kernel code and found a
key problem.

When the kernel reclaims memory, it determines the low boundary of a
cgroup not based on the memory.low set by the user, but based on the
"effective-low-boundary".
The calculation of effective-low-boundary is done by the function
effective_protection() in mm/page_counter.c.

The comments of effective_protection() say that,
" a cgroup's effective-low-boundary is derived from its own
memory.low, its parent's and siblings' memory.low, as well as the
actual memory usage in the tree.
If the children aren't claiming (all of) the protection afforded to
them by the parent, distribute the remainder in proportion to the
(unprotected) memory of each cgroup."

The following is a code snippet from effective_protection(),

        if (parent_effective > siblings_protected &&
            parent_usage > siblings_protected &&
            usage > protected) {
                unsigned long unclaimed;
                unclaimed = parent_effective - siblings_protected;
                unclaimed *= usage - protected;
                unclaimed /= parent_usage - siblings_protected;
                ep += unclaimed;
        }

According to the above algorithm, several children will share the
remaining space of the parent in proportion.

For a cgroup with memory.low=0, this code will cause the
effective-low-boundary calculated to be greater than 0.

This leads to a series of unexpected results:
1. When running memcontrol04, even though we specify memory.low of
group F to be 0, but the effective-low-boundary of group F in kernel
is greater than 0.
2. There will always be some allocated memory(about 100KB) in group F
that is not completely released。
3. When reclaim occurs, the "low" value in group F's memory.events
file will increase, resulting in a non-zero result.

In the cgroup documentation,
(https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html)
it is said that the meaning of "low" in the memory.events file is "The
number of times the cgroup is reclaimed due to high memory pressure
even though its usage is under the low boundary."
This means that, if the memory.low value is set to be 0, the "low"
value in memory.events should never be increased.

To fix this problem, the key is that effective-low-boundary should not
be greater than memory.low at any time.

I tried to modify the calculation method of effective-low-boundary in
the kernel, by simply adding a line of judgment.

The following experiments are conducted in the latest kernel (6.13.0-rc1+)

(1) Code change to effective_protection()

diff --git a/mm/page_counter.c b/mm/page_counter.c
index b249d15af9dd..0c86b7885143 100644
--- a/mm/page_counter.c
+++ b/mm/page_counter.c
@@ -404,6 +404,7 @@ static unsigned long effective_protection(unsigned
long usage,
                ep += unclaimed;
        }

+       ep = (ep > setting) ? setting : ep;
        return ep;
 }

(2) with the modified kernel, memcontrol04 can pass, and groups F's
memory.events:low remains 0.

memcontrol04.c:208: TPASS: Expect: (C oom events=0) == 0
memcontrol04.c:211: TPASS: Expect: (C low events=479) > 0
memcontrol04.c:208: TPASS: Expect: (D oom events=0) == 0
memcontrol04.c:211: TPASS: Expect: (D low events=479) > 0
memcontrol04.c:208: TPASS: Expect: (E oom events=0) == 0
memcontrol04.c:214: TPASS: Expect: (E low events=0) == 0
memcontrol04.c:208: TPASS: Expect: (F oom events=0) == 0
memcontrol04.c:214: TPASS: Expect: (F low events=0) == 0

Summary:
passed   60
failed   0
broken   0
skipped  0


Please take a look at the above analysis and modification of the
kernel and see if it is correct.
If it is reasonable, I may submit this issue to the kernel mailing lists.

Jin


More information about the ltp mailing list