Re: [PATCH v2 2/2] selftests/x86/amx: Test dynamic fpstate cleanup across exec()
From: Guixiong Wei
Date: Mon Oct 19 2026 - 21:59:30 EST
> From: "Chang S. Bae"<chang.seok.bae@xxxxxxxxx>
> Date: Thu, Oct 15, 2026, 08:19
> Subject: Re: [PATCH v2 2/2] selftests/x86/amx: Test dynamic fpstate cleanup across exec()
> To: "Guixiong Wei"<weiguixiong@xxxxxxxxxxxxx>, <x86@xxxxxxxxxx>
> Cc: "Thomas Gleixner"<tglx@xxxxxxxxxx>, "Ingo Molnar"<mingo@xxxxxxxxxx>, "Borislav Petkov"<bp@xxxxxxxxx>, "Dave Hansen"<dave.hansen@xxxxxxxxxxxxxxx>, "H . Peter Anvin"<hpa@xxxxxxxxx>, "Shuah Khan"<shuah@xxxxxxxxxx>, <linux-kernel@xxxxxxxxxxxxxxx>, <linux-kselftest@xxxxxxxxxxxxxxx>
> On 10/7/2026 10:59 PM, Guixiong Wei wrote:
> >
> > -int main(void)
> > +static int count_dynamic_fpstates(void)
> > +{
> > + char *line = NULL;
> > + size_t line_size = 0;
> > + FILE *fp;
> > + int count = 0;
> > +
> > + fp = fopen("/proc/vmallocinfo", "r");
> > + if (!fp)
> > + return -errno;
>
> The call site doesn't interprete the error code. Instead, you can simply
> call fatal_error() here and below on an IO error.
>
Will do. v3 drops the -errno plumbing and calls fatal_error() on
fopen()/getline()/ferror() failures
> > +
> > + while (getline(&line, &line_size, fp) >= 0) {
> > + if (strstr(line, "__xfd_enable_feature") ||
> > + strstr(line, "fpstate_realloc"))
> > + count++;
> > + }
> > +
> > + if (ferror(fp))
> > + count = -EIO;
> > +
> > + free(line);
> > + fclose(fp);
> > + return count;
> > +}
>
> > +static void test_exec(void)
> > +{
> > + char iterations_arg[16];
> > + char baseline_arg[16];
> > + int before, after, delta;
> > + pid_t child;
> > + int status;
> > +
> > + printf("[RUN]\tCheck dynamic fpstate cleanup across exec().\n");
> > +
> > + before = count_dynamic_fpstates();
> > + if (before < 0) {
> > + printf("[SKIP]\tCannot read /proc/vmallocinfo: %s\n",
> > + strerror(-before));
> > + return;
> > + }
> > +
> > + child = fork();
> > + if (child < 0)
> > + fatal_error("fork");
> > + if (!child) {
> > + snprintf(iterations_arg, sizeof(iterations_arg), "%d",
> > + EXEC_TEST_ITERS);
> > + snprintf(baseline_arg, sizeof(baseline_arg), "%d", before);
> > + execl("/proc/self/exe", "amx", EXEC_TEST_ARG, iterations_arg,
> > + baseline_arg, NULL);
> > + fatal_error("exec");
> > + }
>
> This nested exec() with passing numbers via arguments looks more
> complicate than necessary.
>
> Instead, you could put the fork()/exec() sequence in a loop. Before each
> exec(), call load_rand_tiledata(), and adjust main() to return
> immediately from the exec test. I found this also reproduces the
> increase in /proc/vmallocinfo.
>
Agreed, much simpler. v3 restructures test_exec() as:
for (i = 0; i < EXEC_TEST_ITERS; i++) {
child = fork();
if (child < 0)
fatal_error("fork");
if (!child) {
req_xtiledata_perm();
load_rand_tiledata(&stashed_tiles);
execl("/proc/self/exe", "amx",
EXEC_TEST_ARG, NULL);
fatal_error("exec");
}
if (waitpid(child, &status, 0) != child)
fatal_error("waitpid");
...
}
main() short-circuits when argv[1] == EXEC_TEST_ARG and exits 0, so
the exec'd child does nothing beyond returning. The baseline/final
counts are taken by the parent around the loop. Confirmed on an AMX
host: unfixed kernel reports EXEC_TEST_ITERS leaked allocations,
fixed kernel reports 0.
> > +
> > + if (waitpid(child, &status, 0) != child)
> > + fatal_error("waitpid");
> > + if (WIFEXITED(status) && WEXITSTATUS(status) == KSFT_SKIP) {
> > + printf("[SKIP]\tDynamic fpstate allocation was not isolated.\n");
> > + return;
> > + }
> > + if (!WIFEXITED(status) || WEXITSTATUS(status))
> > + fatal_error("exec test child");
> > +
> > + after = count_dynamic_fpstates();
> > + if (after < 0) {
> > + printf("[SKIP]\tCannot read /proc/vmallocinfo after exec(): %s\n",
> > + strerror(-after));
> > + return;
> > + }
> > +
> > + delta = after - before;
> > + if (!delta) {
> > + printf("[OK]\tDynamic fpstate allocations were freed across exec().\n");
> > + return;
> > + }
> > +
> > + if (delta == EXEC_TEST_ITERS)
> > + errx(1, "[FAIL]\texec() leaked %d dynamic fpstate allocations",
> > + delta);
>
> errx() terminates the entire test, preventing subsequent tests from
> running. Unless this failure makes it unsafe or meaningless to continue,
> why not report the failure with printf() and let the remaining tests run?
>
Will do. v3 replaces the errx() with a printf("[FAIL]\t...") and
returns from test_exec() so later subtests still execute. The
failure is still visible in kselftest output.
> > +
> > + printf("[SKIP]\tDynamic fpstate vmalloc usage changed concurrently.\n");
> > +}
>
> Thanks,
> Chang
>
Thanks,
Guixiong