From: Cyril Hrubis <chrubis@suse.cz>
To: Pavithra <pavrampu@linux.ibm.com>
Cc: "Michal Koutný" <mkoutny@suse.com>, ltp@lists.linux.it
Subject: Re: [LTP] [PATCH v7] memcg/memcontrol05: add cgroup v2 task migration charge accounting test
Date: Fri, 30 Oct 2026 16:29:37 +0100 [thread overview]
Message-ID: <auS34aeU5tMadFsg@yuki.lan> (raw)
In-Reply-To: <20260830173408.261946-1-pavrampu@linux.ibm.com>
Hi!
> Verify that in cgroup v2, memory charges remain pinned to the cgroup
> that allocated them when a task migrates, and that new allocations after
> migration are charged to the destination cgroup.
>
> Signed-off-by: Pavithra <pavrampu@linux.ibm.com>
> ---
> v6 -> v7:
> - Replace named checkpoint enum with single index 0
> - Collapse wake/wait pairs into TST_CHECKPOINT_WAKE_AND_WAIT(0)
> - Drop worker_stage tracking
> - Replace manual pass/fail blocks with TST_EXP_LE_LU()
> - Remove MB(4) factor from migration charge check
> - Kill worker with SAFE_KILL/SAFE_WAITPID instead of checkpoint-based exit handshake
> link to v6: https://lore.kernel.org/ltp/20260817155701.943752-1-pavrampu@linux.ibm.com/
> ---
> runtest/controllers | 1 +
> testcases/kernel/controllers/memcg/.gitignore | 1 +
> .../kernel/controllers/memcg/memcontrol05.c | 160 ++++++++++++++++++
> 3 files changed, 162 insertions(+)
> create mode 100644 testcases/kernel/controllers/memcg/memcontrol05.c
>
> diff --git a/runtest/controllers b/runtest/controllers
> index 93c52c439..a9050ef0e 100644
> --- a/runtest/controllers
> +++ b/runtest/controllers
> @@ -24,6 +24,7 @@ memcontrol01 memcontrol01
> memcontrol02 memcontrol02
> memcontrol03 memcontrol03
> memcontrol04 memcontrol04
> +memcontrol05 memcontrol05
>
> cgroup_fj_function_debug cgroup_fj_function.sh debug
> cgroup_fj_function_cpuset cgroup_fj_function.sh cpuset
> diff --git a/testcases/kernel/controllers/memcg/.gitignore b/testcases/kernel/controllers/memcg/.gitignore
> index 3883cede6..8b9f6005c 100644
> --- a/testcases/kernel/controllers/memcg/.gitignore
> +++ b/testcases/kernel/controllers/memcg/.gitignore
> @@ -9,3 +9,4 @@ memcontrol01
> memcontrol02
> memcontrol03
> memcontrol04
> +memcontrol05
> diff --git a/testcases/kernel/controllers/memcg/memcontrol05.c b/testcases/kernel/controllers/memcg/memcontrol05.c
> new file mode 100644
> index 000000000..d452039e6
> --- /dev/null
> +++ b/testcases/kernel/controllers/memcg/memcontrol05.c
> @@ -0,0 +1,160 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2026 IBM
> + * Author : Pavithra <pavrampu@linux.ibm.com>
> + */
> +
> +/*\
> + * Origin: ``testcases/kernel/controllers/memctl/memctl_testplan.txt``
> + * Verify memory controller charge accounting during task migration.
> + *
> + * Two child cgroups (``group_a``, ``group_b``) are created under the test cgroup.
> + * A worker process is placed in ``group_a`` and allocates a known amount of
> + * anonymous memory, touching every page to ensure physical allocation.
> + * Root is required to create cgroup subdirectories and to write a PID
> + * into ``cgroup.procs`` to migrate the worker between cgroups.
> + *
> + * Test 1 - No charge transfer on migration:
> + * The worker is migrated to ``group_b`` by writing its PID to
> + * ``group_b/cgroup.procs``. In cgroup v2 memory charges are never
> + * transferred on task migration; they remain pinned to the cgroup
> + * that allocated them. ``group_b/memory.current`` must not increase
> + * beyond its baseline after the migration.
> + *
> + * Test 2 - New allocations charged to destination cgroup:
> + * After migration the worker allocates an additional chunk of memory.
> + * This new allocation must be charged to ``group_b``, so
> + * ``group_b/memory.current`` must increase from the post-migration
> + * baseline.
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <stdlib.h>
> +#include <sys/types.h>
> +#include <sys/wait.h>
> +#include "tst_test.h"
> +#include "memcontrol_common.h"
> +
> +#define ALLOC_SIZE MB(60)
> +#define ALLOC_SIZE2 MB(20)
> +#define MIN_MEM_AVAIL 128
> +
> +static struct tst_cg_group *group_a;
> +static struct tst_cg_group *group_b;
> +static pid_t worker_pid;
> +
> +static void touch_pages(char *buf, size_t size)
> +{
> + size_t i;
> +
> + for (i = 0; i < size; i += getpagesize())
> + buf[i] = 1;
> +}
> +
> +static void worker(void)
> +{
> + char *buf1, *buf2;
> +
> + SAFE_CG_PRINTF(group_a, "cgroup.procs", "%d", getpid());
> +
> + buf1 = SAFE_MMAP(NULL, ALLOC_SIZE, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> + touch_pages(buf1, ALLOC_SIZE);
> +
> + TST_CHECKPOINT_WAKE_AND_WAIT(0);
> +
> + buf2 = SAFE_MMAP(NULL, ALLOC_SIZE2, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> + touch_pages(buf2, ALLOC_SIZE2);
> +
> + TST_CHECKPOINT_WAKE(0);
> +
> + pause();
> +}
> +
> +static void test_memcg_task_migration(void)
> +{
> + long baseline_b, after_migrate, after_migrate_a, after_alloc2, current_a;
> +
> + worker_pid = 0;
> +
> + group_a = tst_cg_group_mk(tst_cg, "group_a");
> + group_b = tst_cg_group_mk(tst_cg, "group_b");
> +
> + if (SAFE_CG_HAS(tst_cg, "memory.swap.max")) {
> + SAFE_CG_PRINT(group_a, "memory.swap.max", "0");
> + SAFE_CG_PRINT(group_b, "memory.swap.max", "0");
> + }
> +
> + SAFE_CG_SCANF(group_b, "memory.current", "%ld", &baseline_b);
> + tst_res(TINFO, "group_b baseline memory.current=%ld", baseline_b);
> +
> + worker_pid = SAFE_FORK();
> + if (!worker_pid) {
> + worker();
> + exit(0);
> + }
> +
> + TST_CHECKPOINT_WAIT(0);
> +
> + SAFE_CG_SCANF(group_a, "memory.current", "%ld", ¤t_a);
> + TST_EXP_LE_LU(ALLOC_SIZE, current_a);
> +
> + SAFE_CG_PRINTF(group_b, "cgroup.procs", "%d", worker_pid);
> + tst_res(TINFO, "Migrated worker PID %d to group_b", worker_pid);
> +
> + SAFE_CG_SCANF(group_b, "memory.current", "%ld", &after_migrate);
> + tst_res(TINFO,
> + "group_b memory.current=%ld after migration (baseline=%ld)",
> + after_migrate, baseline_b);
> +
> + TST_EXP_LE_LU(after_migrate, baseline_b);
I do not think that it's actually guaranteed that nothing is charged in
the cgroup_b after the migration. I guess that we can use values_close()
function here.
> + SAFE_CG_SCANF(group_a, "memory.current", "%ld", &after_migrate_a);
> + tst_res(TINFO, "group_a memory.current=%ld after migration", after_migrate_a);
> + TST_EXP_EXPR(after_migrate_a >= (long)ALLOC_SIZE,
> + "group_a memory.current (%ld) still holds pre-migration charges (>= ALLOC_SIZE %ld)",
> + after_migrate_a, (long)ALLOC_SIZE);
> +
> + TST_CHECKPOINT_WAKE_AND_WAIT(0);
> +
> + SAFE_CG_SCANF(group_b, "memory.current", "%ld", &after_alloc2);
> + tst_res(TINFO, "group_b memory.current=%ld after second alloc (baseline=%ld)",
> + after_alloc2, after_migrate);
> +
> + TST_EXP_EXPR(after_alloc2 >= after_migrate + (long)ALLOC_SIZE2,
> + "group_b memory.current (%ld) increased by >= ALLOC_SIZE2 (%ld)",
> + after_alloc2, (long)ALLOC_SIZE2);
And here as well, I suppose that we can only assert that the
after_alloc2 >= ALLOC_SIZE2.
Also CCing Michal Koutny, our cgroup expert.
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
prev parent reply other threads:[~2026-10-30 15:29 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-30 17:34 [LTP] [PATCH v7] memcg/memcontrol05: add cgroup v2 task migration charge accounting test Pavithra
2026-08-30 17:59 ` [LTP] " linuxtestproject.agent
2026-10-30 15:29 ` Cyril Hrubis [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=auS34aeU5tMadFsg@yuki.lan \
--to=chrubis@suse.cz \
--cc=ltp@lists.linux.it \
--cc=mkoutny@suse.com \
--cc=pavrampu@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox