[LTP] [PATCH v3] Migrating the libhugetlbfs/testcases/slbpacaflush.c test

Cyril Hrubis chrubis@suse.cz
Wed Mar 4 11:27:40 CET 2026


Hi!
> diff --git a/runtest/hugetlb b/runtest/hugetlb
> index 299c07ac9..d956866ac 100644
> --- a/runtest/hugetlb
> +++ b/runtest/hugetlb
> @@ -35,6 +35,7 @@ hugemmap29 hugemmap29
>  hugemmap30 hugemmap30
>  hugemmap31 hugemmap31
>  hugemmap32 hugemmap32
> +hugemmap41 hugemmap41
>  hugemmap05_1 hugemmap05 -m
>  hugemmap05_2 hugemmap05 -s
>  hugemmap05_3 hugemmap05 -s -m
> diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
> index c96fe8bfc..b7e108956 100644
> --- a/testcases/kernel/mem/.gitignore
> +++ b/testcases/kernel/mem/.gitignore
> @@ -34,6 +34,7 @@
>  /hugetlb/hugemmap/hugemmap30
>  /hugetlb/hugemmap/hugemmap31
>  /hugetlb/hugemmap/hugemmap32
> +/hugetlb/hugemmap/hugemmap41
>  /hugetlb/hugeshmat/hugeshmat01
>  /hugetlb/hugeshmat/hugeshmat02
>  /hugetlb/hugeshmat/hugeshmat03
> diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap41.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap41.c
> new file mode 100644
> index 000000000..4657fd99d
> --- /dev/null
> +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap41.c
> @@ -0,0 +1,124 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2005-2006 IBM Corporation.
> + * Author: David Gibson & Adam Litke
> + */
> +/*\
> + * [Description]
> + *
> + * ppc64 kernels (prior to 2.6.15-rc5) have a bug in the hugepage SLB
> + * flushing path.  After opening new hugetlb areas, we update the
> + * masks in the thread_struct, copy to the PACA, then do slbies on
> + * each CPU.  The trouble is we only copy to the PACA on the CPU where
> + * we're opening the segments, which can leave a stale copy in the
> + * PACAs on other CPUs.
> + *
> + * This can be triggered either with multiple threads sharing the mm,
> + * or with a single thread which is migrated from one CPU, to another
> + * (where the mapping occurs), then back again (where we touch the
> + * stale SLB).  We use the second method in this test, since it's
> + * easier to force (using sched_setaffinity).  However it relies on a
> + * close-to-idle system, if any process other than a kernel thread
> + * runs on the first CPU between runs of the test process, the SLB
> + * will be flushed and we won't trigger the bug, hence the
> + * PASS_INCONCLUSIVE().  Obviously, this test won't work on a 1-cpu
> + * system (should get CONFIG() on the sched_setaffinity)
> + *
> + */
> +#define _GNU_SOURCE
> +
> +#include "hugetlb.h"
> +
> +#include <stdio.h>
> +#include <sched.h>
> +#include <unistd.h>
> +
> +#define MNTPOINT "hugetlbfs/"
> +
> +static long hpage_size;
> +static int fd;
> +static void *p;
> +static volatile unsigned long *q;
> +static int online_cpus[2];
> +static int err;
> +static cpu_set_t cpu0, cpu1;
> +
> +/*
> + * Helper to get online CPUs (based on thread affinity)
> + * Returns number of CPUs found, fills in `online_cpus[]`.
> + */
> +static unsigned int tst_get_online_cpus(int online_cpus[], unsigned int online_cpus_cnt)
> +{
> +	cpu_set_t mask;
> +	unsigned int count = 0;
> +
> +	if (sched_getaffinity(0, sizeof(mask), &mask) < 0)
> +		tst_brk(TBROK | TERRNO, "sched_getaffinity() failed");
> +
> +	for (int i = 0; i < CPU_SETSIZE && count < online_cpus_cnt; i++) {
> +		if (CPU_ISSET(i, &mask))
> +			online_cpus[count++] = i;
> +	}
> +
> +	return count;
> +}
> +
> +static void run_test(void)
> +{
> +	if (tst_get_online_cpus(online_cpus, 2) != 2)
> +		tst_brk(TCONF, "Require at least 2 online CPUs.");
> +
> +	CPU_ZERO(&cpu0);
> +	CPU_SET(online_cpus[0], &cpu0);
> +
> +	CPU_ZERO(&cpu1);
> +	CPU_SET(online_cpus[1], &cpu1);
> +
> +	err = sched_setaffinity(getpid(), sizeof(cpu_set_t), &cpu0);
> +	if (err != 0)
> +		tst_res(TFAIL | TERRNO, "sched_setaffinity(cpu%d)", online_cpus[0]);
> +
> +	err = sched_setaffinity(getpid(), sizeof(cpu_set_t), &cpu1);
> +	if (err != 0)
> +		tst_res(TFAIL | TERRNO, "sched_setaffinity(cpu%d)", online_cpus[1]);
> +
> +	p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

I wonder if it wouldn't be easier to pass MAP_HUGETLB instead of
creating a file on a hugetlb. Or is there something that prevents us
doing that?

> +	err = sched_setaffinity(getpid(), sizeof(cpu_set_t), &cpu0);
> +	if (err != 0)
> +	tst_res(TFAIL, "sched_setaffinity(cpu%d)", online_cpus[0]);

Missing tab before tst_res()

Also given the amount of setaffinity calls here it may make sense to add
SAFE_SCHED_SETAFFINITY() to the library.


> +	q = (volatile unsigned long *)(p + getpagesize());
> +	*q = 0xdeadbeef;
> +
> +	tst_res(TPASS, "Nothing bad happened, probably.");
> +
> +	SAFE_MUNMAP(p, hpage_size);
> +}
> +
> +static void setup(void)
> +{
> +	hpage_size = tst_get_hugepage_size();
> +
> +	/* Fix: pass 3 arguments */

No comments like this please.

> +	fd = tst_creat_unlinked(MNTPOINT, O_RDWR | O_CREAT, 0644);
> +	if (fd < 0)
> +		tst_brk(TBROK | TERRNO, "tst_creat_unlinked() failed");

tst_creat_unlinked() cannot fail.

> +}
> +
> +static void cleanup(void)
> +{
> +	if (fd > 0)
> +		SAFE_CLOSE(fd);
> +}
> +
> +static struct tst_test test = {
> +	.needs_root = 1,
> +	.mntpoint = MNTPOINT,
> +	.needs_hugetlbfs = 1,
> +	.needs_tmpdir = 1,
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.test_all = run_test,
> +	.hugepages = {1, TST_NEEDS},
> +};
> -- 
> 2.43.5
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp

-- 
Cyril Hrubis
chrubis@suse.cz


More information about the ltp mailing list