From: Chen Ridong <chenridong@huaweicloud.com>
To: Tiffany Yang <ynaffit@google.com>, linux-kernel@vger.kernel.org
Cc: "John Stultz" <jstultz@google.com>,
"Thomas Gleixner" <tglx@linutronix.de>,
"Stephen Boyd" <sboyd@kernel.org>,
"Anna-Maria Behnsen" <anna-maria@linutronix.de>,
"Frederic Weisbecker" <frederic@kernel.org>,
"Tejun Heo" <tj@kernel.org>,
"Johannes Weiner" <hannes@cmpxchg.org>,
"Michal Koutný" <mkoutny@suse.com>,
"Rafael J. Wysocki" <rafael@kernel.org>,
"Pavel Machek" <pavel@kernel.org>,
"Roman Gushchin" <roman.gushchin@linux.dev>,
"Chen Ridong" <chenridong@huawei.com>,
kernel-team@android.com, "Jonathan Corbet" <corbet@lwn.net>,
"Shuah Khan" <shuah@kernel.org>,
cgroups@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kselftest@vger.kernel.org
Subject: Re: [PATCH v4 2/2] cgroup: selftests: Add tests for freezer time
Date: Fri, 22 Aug 2025 15:19:26 +0800 [thread overview]
Message-ID: <bad4609b-4427-48ff-80e9-70cb3066253e@huaweicloud.com> (raw)
In-Reply-To: <20250822013749.3268080-8-ynaffit@google.com>
On 2025/8/22 9:37, Tiffany Yang wrote:
> Test cgroup v2 freezer time stat. Freezer time accounting should
> be independent of other cgroups in the hierarchy and should increase
> iff a cgroup is CGRP_FREEZE (regardless of whether it reaches
> CGRP_FROZEN).
>
> Skip these tests on systems without freeze time accounting.
>
> Signed-off-by: Tiffany Yang <ynaffit@google.com>
> Cc: Michal Koutný <mkoutny@suse.com>
> ---
> v3 -> v4:
> * Clean up logic around skipping selftests and decrease granularity of
> sleep times, as suggested by Michal.
> ---
> tools/testing/selftests/cgroup/test_freezer.c | 663 ++++++++++++++++++
> 1 file changed, 663 insertions(+)
>
> diff --git a/tools/testing/selftests/cgroup/test_freezer.c b/tools/testing/selftests/cgroup/test_freezer.c
> index 8730645d363a..dfb763819581 100644
> --- a/tools/testing/selftests/cgroup/test_freezer.c
> +++ b/tools/testing/selftests/cgroup/test_freezer.c
> @@ -804,6 +804,662 @@ static int test_cgfreezer_vfork(const char *root)
> return ret;
> }
>
> +/*
> + * Get the current frozen_usec for the cgroup.
> + */
> +static long cg_check_freezetime(const char *cgroup)
> +{
> + return cg_read_key_long(cgroup, "cgroup.stat.local",
> + "frozen_usec ");
> +}
> +
> +/*
> + * Test that the freeze time will behave as expected for an empty cgroup.
> + */
> +static int test_cgfreezer_time_empty(const char *root)
> +{
> + int ret = KSFT_FAIL;
> + char *cgroup = NULL;
> + long prev, curr;
> +
> + cgroup = cg_name(root, "cg_time_test_empty");
> + if (!cgroup)
> + goto cleanup;
> +
> + /*
> + * 1) Create an empty cgroup and check that its freeze time
> + * is 0.
> + */
> + if (cg_create(cgroup))
> + goto cleanup;
> +
> + curr = cg_check_freezetime(cgroup);
> + if (curr < 0) {
> + ret = KSFT_SKIP;
> + goto cleanup;
> + }
> + if (curr > 0) {
> + debug("Expect time (%ld) to be 0\n", curr);
> + goto cleanup;
> + }
> +
Perhaps we can simply use if (curr != 0) for the condition?
> + if (cg_freeze_nowait(cgroup, true))
> + goto cleanup;
> +
> + /*
> + * 2) Sleep for 1000 us. Check that the freeze time is at
> + * least 1000 us.
> + */
> + usleep(1000);
> + curr = cg_check_freezetime(cgroup);
> + if (curr < 1000) {
> + debug("Expect time (%ld) to be at least 1000 us\n",
> + curr);
> + goto cleanup;
> + }
> +
> + /*
> + * 3) Unfreeze the cgroup. Check that the freeze time is
> + * larger than at 2).
> + */
> + if (cg_freeze_nowait(cgroup, false))
> + goto cleanup;
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr <= prev) {
> + debug("Expect time (%ld) to be more than previous check (%ld)\n",
> + curr, prev);
> + goto cleanup;
> + }
> +
> + /*
> + * 4) Check the freeze time again to ensure that it has not
> + * changed.
> + */
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr != prev) {
> + debug("Expect time (%ld) to be unchanged from previous check (%ld)\n",
> + curr, prev);
> + goto cleanup;
> + }
> +
> + ret = KSFT_PASS;
> +
> +cleanup:
> + if (cgroup)
> + cg_destroy(cgroup);
> + free(cgroup);
> + return ret;
> +}
> +
> +/*
> + * A simple test for cgroup freezer time accounting. This test follows
> + * the same flow as test_cgfreezer_time_empty, but with a single process
> + * in the cgroup.
> + */
> +static int test_cgfreezer_time_simple(const char *root)
> +{
> + int ret = KSFT_FAIL;
> + char *cgroup = NULL;
> + long prev, curr;
> +
> + cgroup = cg_name(root, "cg_time_test_simple");
> + if (!cgroup)
> + goto cleanup;
> +
> + /*
> + * 1) Create a cgroup and check that its freeze time is 0.
> + */
> + if (cg_create(cgroup))
> + goto cleanup;
> +
> + curr = cg_check_freezetime(cgroup);
> + if (curr < 0) {
> + ret = KSFT_SKIP;
> + goto cleanup;
> + }
> + if (curr > 0) {
> + debug("Expect time (%ld) to be 0\n", curr);
> + goto cleanup;
> + }
> +
> + /*
> + * 2) Populate the cgroup with one child and check that the
> + * freeze time is still 0.
> + */
> + cg_run_nowait(cgroup, child_fn, NULL);
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr > prev) {
> + debug("Expect time (%ld) to be 0\n", curr);
> + goto cleanup;
> + }
> +
> + if (cg_freeze_nowait(cgroup, true))
> + goto cleanup;
> +
> + /*
> + * 3) Sleep for 1000 us. Check that the freeze time is at
> + * least 1000 us.
> + */
> + usleep(1000);
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr < 1000) {
> + debug("Expect time (%ld) to be at least 1000 us\n",
> + curr);
> + goto cleanup;
> + }
> +
> + /*
> + * 4) Unfreeze the cgroup. Check that the freeze time is
> + * larger than at 3).
> + */
> + if (cg_freeze_nowait(cgroup, false))
> + goto cleanup;
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr <= prev) {
> + debug("Expect time (%ld) to be more than previous check (%ld)\n",
> + curr, prev);
> + goto cleanup;
> + }
> +
> + /*
> + * 5) Sleep for 1000 us. Check that the freeze time is the
> + * same as at 4).
> + */
> + usleep(1000);
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr != prev) {
> + debug("Expect time (%ld) to be unchanged from previous check (%ld)\n",
> + curr, prev);
> + goto cleanup;
> + }
> +
> + ret = KSFT_PASS;
> +
> +cleanup:
> + if (cgroup)
> + cg_destroy(cgroup);
> + free(cgroup);
> + return ret;
> +}
> +
> +/*
> + * Test that freezer time accounting works as expected, even while we're
> + * populating a cgroup with processes.
> + */
> +static int test_cgfreezer_time_populate(const char *root)
> +{
> + int ret = KSFT_FAIL;
> + char *cgroup = NULL;
> + long prev, curr;
> + int i;
> +
> + cgroup = cg_name(root, "cg_time_test_populate");
> + if (!cgroup)
> + goto cleanup;
> +
> + if (cg_create(cgroup))
> + goto cleanup;
> +
> + curr = cg_check_freezetime(cgroup);
> + if (curr < 0) {
> + ret = KSFT_SKIP;
> + goto cleanup;
> + }
> + if (curr > 0) {
> + debug("Expect time (%ld) to be 0\n", curr);
> + goto cleanup;
> + }
> +
> + /*
> + * 1) Populate the cgroup with 100 processes. Check that
> + * the freeze time is 0.
> + */
> + for (i = 0; i < 100; i++)
> + cg_run_nowait(cgroup, child_fn, NULL);
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr != prev) {
> + debug("Expect time (%ld) to be 0\n", curr);
> + goto cleanup;
> + }
> +
> + /*
> + * 2) Wait for the group to become fully populated. Check
> + * that the freeze time is 0.
> + */
> + if (cg_wait_for_proc_count(cgroup, 100))
> + goto cleanup;
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr != prev) {
> + debug("Expect time (%ld) to be 0\n", curr);
> + goto cleanup;
> + }
> +
> + /*
> + * 3) Freeze the cgroup and then populate it with 100 more
> + * processes. Check that the freeze time continues to grow.
> + */
> + if (cg_freeze_nowait(cgroup, true))
> + goto cleanup;
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr <= prev) {
> + debug("Expect time (%ld) to be more than previous check (%ld)\n",
> + curr, prev);
> + goto cleanup;
> + }
> +
> + for (i = 0; i < 100; i++)
> + cg_run_nowait(cgroup, child_fn, NULL);
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr <= prev) {
> + debug("Expect time (%ld) to be more than previous check (%ld)\n",
> + curr, prev);
> + goto cleanup;
> + }
> +
> + /*
> + * 4) Wait for the group to become fully populated. Check
> + * that the freeze time is larger than at 3).
> + */
> + if (cg_wait_for_proc_count(cgroup, 200))
> + goto cleanup;
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr <= prev) {
> + debug("Expect time (%ld) to be more than previous check (%ld)\n",
> + curr, prev);
> + goto cleanup;
> + }
> +
> + /*
> + * 5) Unfreeze the cgroup. Check that the freeze time is
> + * larger than at 4).
> + */
> + if (cg_freeze_nowait(cgroup, false))
> + goto cleanup;
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr <= prev) {
> + debug("Expect time (%ld) to be more than previous check (%ld)\n",
> + curr, prev);
> + goto cleanup;
> + }
> +
> + /*
> + * 6) Kill the processes. Check that the freeze time is the
> + * same as it was at 5).
> + */
> + if (cg_killall(cgroup))
> + goto cleanup;
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr != prev) {
> + debug("Expect time (%ld) to be unchanged from previous check (%ld)\n",
> + curr, prev);
> + goto cleanup;
> + }
> +
> + /*
> + * 7) Freeze and unfreeze the cgroup. Check that the freeze
> + * time is larger than it was at 6).
> + */
> + if (cg_freeze_nowait(cgroup, true))
> + goto cleanup;
> + if (cg_freeze_nowait(cgroup, false))
> + goto cleanup;
> + prev = curr;
> + curr = cg_check_freezetime(cgroup);
> + if (curr <= prev) {
> + debug("Expect time (%ld) to be more than previous check (%ld)\n",
> + curr, prev);
> + goto cleanup;
> + }
> +
> + ret = KSFT_PASS;
> +
> +cleanup:
> + if (cgroup)
> + cg_destroy(cgroup);
> + free(cgroup);
> + return ret;
> +}
> +
> +/*
> + * Test that frozen time for a cgroup continues to work as expected,
> + * even as processes are migrated. Frozen cgroup A's freeze time should
> + * continue to increase and running cgroup B's should stay 0.
> + */
> +static int test_cgfreezer_time_migrate(const char *root)
> +{
> + long prev_A, curr_A, curr_B;
> + char *cgroup[2] = {0};
> + int ret = KSFT_FAIL;
> + int pid;
> +
> + cgroup[0] = cg_name(root, "cg_time_test_migrate_A");
> + if (!cgroup[0])
> + goto cleanup;
> +
> + cgroup[1] = cg_name(root, "cg_time_test_migrate_B");
> + if (!cgroup[1])
> + goto cleanup;
> +
> + if (cg_create(cgroup[0]))
> + goto cleanup;
> +
> + if (cg_check_freezetime(cgroup[0]) < 0) {
> + ret = KSFT_SKIP;
> + goto cleanup;
> + }
> +
> + if (cg_create(cgroup[1]))
> + goto cleanup;
> +
> + pid = cg_run_nowait(cgroup[0], child_fn, NULL);
> + if (pid < 0)
> + goto cleanup;
> +
> + if (cg_wait_for_proc_count(cgroup[0], 1))
> + goto cleanup;
> +
> + curr_A = cg_check_freezetime(cgroup[0]);
> + if (curr_A) {
> + debug("Expect time (%ld) to be 0\n", curr_A);
> + goto cleanup;
> + }
> + curr_B = cg_check_freezetime(cgroup[1]);
> + if (curr_B) {
> + debug("Expect time (%ld) to be 0\n", curr_B);
> + goto cleanup;
> + }
> +
> + /*
> + * Freeze cgroup A.
> + */
> + if (cg_freeze_wait(cgroup[0], true))
> + goto cleanup;
> + prev_A = curr_A;
> + curr_A = cg_check_freezetime(cgroup[0]);
> + if (curr_A <= prev_A) {
> + debug("Expect time (%ld) to be > 0\n", curr_A);
> + goto cleanup;
> + }
> +
> + /*
> + * Migrate from A (frozen) to B (running).
> + */
> + if (cg_enter(cgroup[1], pid))
> + goto cleanup;
> +
> + usleep(1000);
> + curr_B = cg_check_freezetime(cgroup[1]);
> + if (curr_B) {
> + debug("Expect time (%ld) to be 0\n", curr_B);
> + goto cleanup;
> + }
> +
> + prev_A = curr_A;
> + curr_A = cg_check_freezetime(cgroup[0]);
> + if (curr_A <= prev_A) {
> + debug("Expect time (%ld) to be more than previous check (%ld)\n",
> + curr_A, prev_A);
> + goto cleanup;
> + }
> +
> + ret = KSFT_PASS;
> +
> +cleanup:
> + if (cgroup[0])
> + cg_destroy(cgroup[0]);
> + free(cgroup[0]);
> + if (cgroup[1])
> + cg_destroy(cgroup[1]);
> + free(cgroup[1]);
> + return ret;
> +}
> +
> +/*
> + * The test creates a cgroup and freezes it. Then it creates a child cgroup.
> + * After that it checks that the child cgroup has a non-zero freeze time
> + * that is less than the parent's. Next, it freezes the child, unfreezes
> + * the parent, and sleeps. Finally, it checks that the child's freeze
> + * time has grown larger than the parent's.
> + */
> +static int test_cgfreezer_time_parent(const char *root)
> +{
> + char *parent, *child = NULL;
> + int ret = KSFT_FAIL;
> + long ptime, ctime;
> +
> + parent = cg_name(root, "cg_test_parent_A");
> + if (!parent)
> + goto cleanup;
> +
> + child = cg_name(parent, "cg_test_parent_B");
> + if (!child)
> + goto cleanup;
> +
> + if (cg_create(parent))
> + goto cleanup;
> +
> + if (cg_check_freezetime(parent) < 0) {
> + ret = KSFT_SKIP;
> + goto cleanup;
> + }
> +
> + if (cg_freeze_wait(parent, true))
> + goto cleanup;
> +
> + usleep(1000);
> + if (cg_create(child))
> + goto cleanup;
> +
> + if (cg_check_frozen(child, true))
> + goto cleanup;
> +
> + /*
> + * Since the parent was frozen the entire time the child cgroup
> + * was being created, we expect the parent's freeze time to be
> + * larger than the child's.
> + *
> + * Ideally, we would be able to check both times simultaneously,
> + * but here we get the child's after we get the parent's.
> + */
> + ptime = cg_check_freezetime(parent);
> + ctime = cg_check_freezetime(child);
> + if (ptime <= ctime) {
> + debug("Expect ptime (%ld) > ctime (%ld)\n", ptime, ctime);
> + goto cleanup;
> + }
> +
> + if (cg_freeze_nowait(child, true))
> + goto cleanup;
> +
> + if (cg_freeze_wait(parent, false))
> + goto cleanup;
> +
> + if (cg_check_frozen(child, true))
> + goto cleanup;
> +
> + usleep(100000);
> +
> + ctime = cg_check_freezetime(child);
> + ptime = cg_check_freezetime(parent);
> +
> + if (ctime <= ptime) {
> + debug("Expect ctime (%ld) > ptime (%ld)\n", ctime, ptime);
> + goto cleanup;
> + }
> +
> + ret = KSFT_PASS;
> +
> +cleanup:
> + if (child)
> + cg_destroy(child);
> + free(child);
> + if (parent)
> + cg_destroy(parent);
> + free(parent);
> + return ret;
> +}
> +
> +/*
> + * The test creates a parent cgroup and a child cgroup. Then, it freezes
> + * the child and checks that the child's freeze time is greater than the
> + * parent's, which should be zero.
> + */
> +static int test_cgfreezer_time_child(const char *root)
> +{
> + char *parent, *child = NULL;
> + int ret = KSFT_FAIL;
> + long ptime, ctime;
> +
> + parent = cg_name(root, "cg_test_child_A");
> + if (!parent)
> + goto cleanup;
> +
> + child = cg_name(parent, "cg_test_child_B");
> + if (!child)
> + goto cleanup;
> +
> + if (cg_create(parent))
> + goto cleanup;
> +
> + if (cg_check_freezetime(parent) < 0) {
> + ret = KSFT_SKIP;
> + goto cleanup;
> + }
> +
> + if (cg_create(child))
> + goto cleanup;
> +
> + if (cg_freeze_wait(child, true))
> + goto cleanup;
> +
> + ctime = cg_check_freezetime(child);
> + ptime = cg_check_freezetime(parent);
> + if (ptime != 0) {
> + debug("Expect ptime (%ld) to be 0\n", ptime);
> + goto cleanup;
> + }
> +
> + if (ctime <= ptime) {
> + debug("Expect ctime (%ld) <= ptime (%ld)\n", ctime, ptime);
> + goto cleanup;
> + }
> +
> + ret = KSFT_PASS;
> +
> +cleanup:
> + if (child)
> + cg_destroy(child);
> + free(child);
> + if (parent)
> + cg_destroy(parent);
> + free(parent);
> + return ret;
> +}
> +
> +/*
> + * The test creates the following hierarchy:
> + * A
> + * |
> + * B
> + * |
> + * C
> + *
> + * Then it freezes the cgroups in the order C, B, A.
> + * Then it unfreezes the cgroups in the order A, B, C.
> + * Then it checks that C's freeze time is larger than B's and
> + * that B's is larger than A's.
> + */
> +static int test_cgfreezer_time_nested(const char *root)
> +{
> + char *cgroup[3] = {0};
> + int ret = KSFT_FAIL;
> + long time[3] = {0};
> + int i;
> +
> + cgroup[0] = cg_name(root, "cg_test_time_A");
> + if (!cgroup[0])
> + goto cleanup;
> +
> + cgroup[1] = cg_name(cgroup[0], "B");
> + if (!cgroup[1])
> + goto cleanup;
> +
> + cgroup[2] = cg_name(cgroup[1], "C");
> + if (!cgroup[2])
> + goto cleanup;
> +
> + if (cg_create(cgroup[0]))
> + goto cleanup;
> +
> + if (cg_check_freezetime(cgroup[0]) < 0) {
> + ret = KSFT_SKIP;
> + goto cleanup;
> + }
> +
> + if (cg_create(cgroup[1]))
> + goto cleanup;
> +
> + if (cg_create(cgroup[2]))
> + goto cleanup;
> +
> + if (cg_freeze_nowait(cgroup[2], true))
> + goto cleanup;
> +
> + if (cg_freeze_nowait(cgroup[1], true))
> + goto cleanup;
> +
> + if (cg_freeze_nowait(cgroup[0], true))
> + goto cleanup;
> +
> + usleep(1000);
> +
> + if (cg_freeze_nowait(cgroup[0], false))
> + goto cleanup;
> +
> + if (cg_freeze_nowait(cgroup[1], false))
> + goto cleanup;
> +
> + if (cg_freeze_nowait(cgroup[2], false))
> + goto cleanup;
> +
> + time[2] = cg_check_freezetime(cgroup[2]);
> + time[1] = cg_check_freezetime(cgroup[1]);
> + time[0] = cg_check_freezetime(cgroup[0]);
> +
> + if (time[2] <= time[1]) {
> + debug("Expect C's time (%ld) > B's time (%ld)", time[2], time[1]);
> + goto cleanup;
> + }
> +
> + if (time[1] <= time[0]) {
> + debug("Expect B's time (%ld) > A's time (%ld)", time[1], time[0]);
> + goto cleanup;
> + }
> +
> + ret = KSFT_PASS;
> +
> +cleanup:
> + for (i = 2; i >= 0 && cgroup[i]; i--) {
> + cg_destroy(cgroup[i]);
> + free(cgroup[i]);
> + }
> +
> + return ret;
> +}
> +
> #define T(x) { x, #x }
> struct cgfreezer_test {
> int (*fn)(const char *root);
> @@ -819,6 +1475,13 @@ struct cgfreezer_test {
> T(test_cgfreezer_stopped),
> T(test_cgfreezer_ptraced),
> T(test_cgfreezer_vfork),
> + T(test_cgfreezer_time_empty),
> + T(test_cgfreezer_time_simple),
> + T(test_cgfreezer_time_populate),
> + T(test_cgfreezer_time_migrate),
> + T(test_cgfreezer_time_parent),
> + T(test_cgfreezer_time_child),
> + T(test_cgfreezer_time_nested),
> };
> #undef T
>
--
Best regards,
Ridong
next prev parent reply other threads:[~2025-08-22 7:19 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-22 1:37 [PATCH v4 0/2] cgroup: Track time in cgroup v2 freezer Tiffany Yang
2025-08-22 1:37 ` [PATCH v4 1/2] cgroup: cgroup.stat.local time accounting Tiffany Yang
2025-08-22 6:14 ` Chen Ridong
2025-08-22 6:58 ` Chen Ridong
2025-08-22 19:32 ` Tiffany Yang
2025-08-23 1:45 ` Chen Ridong
2025-08-25 21:00 ` Tiffany Yang
2025-08-22 1:37 ` [PATCH v4 2/2] cgroup: selftests: Add tests for freezer time Tiffany Yang
2025-08-22 7:19 ` Chen Ridong [this message]
2025-08-22 18:50 ` Tiffany Yang
2025-08-23 1:47 ` Chen Ridong
2025-08-22 17:51 ` [PATCH v4 0/2] cgroup: Track time in cgroup v2 freezer Tejun Heo
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=bad4609b-4427-48ff-80e9-70cb3066253e@huaweicloud.com \
--to=chenridong@huaweicloud.com \
--cc=anna-maria@linutronix.de \
--cc=cgroups@vger.kernel.org \
--cc=chenridong@huawei.com \
--cc=corbet@lwn.net \
--cc=frederic@kernel.org \
--cc=hannes@cmpxchg.org \
--cc=jstultz@google.com \
--cc=kernel-team@android.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=mkoutny@suse.com \
--cc=pavel@kernel.org \
--cc=rafael@kernel.org \
--cc=roman.gushchin@linux.dev \
--cc=sboyd@kernel.org \
--cc=shuah@kernel.org \
--cc=tglx@linutronix.de \
--cc=tj@kernel.org \
--cc=ynaffit@google.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;
as well as URLs for NNTP newsgroup(s).