* [LTP] [PATCH v10] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
@ 2026-11-07 6:28 Pavithra
2026-11-07 10:51 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 7+ messages in thread
From: Pavithra @ 2026-11-07 6:28 UTC (permalink / raw)
To: ltp; +Cc: pavrampu
Stress test fallocate() on hugetlbfs with three concurrent threads:
one continuously punches and fills holes, one faults in hugepages,
and one continuously mmaps and munmaps the same file range.
Verify no hugepage leak occurs after the stress run.
Signed-off-by: Pavithra <pavrampu@linux.ibm.com>
---
v9 -> v10:
- Save the original SIGBUS handler in thread_fault() and restore it before
the thread exits.
- Replace pthread_cancel()/pthread_testcancel() and the cleanup handler with
a volatile "run" flag.
- Drop the unused thread return value variables and the global
fault_mmap_addr.
Link to v9: https://lore.kernel.org/ltp/20260923080150.44934-1-pavrampu@linux.ibm.com/
---
runtest/hugetlb | 1 +
testcases/kernel/mem/.gitignore | 1 +
.../hugetlb/hugefallocate/hugefallocate03.c | 200 ++++++++++++++++++
3 files changed, 202 insertions(+)
create mode 100644 testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
diff --git a/runtest/hugetlb b/runtest/hugetlb
index fd687a14e..2e7bd1779 100644
--- a/runtest/hugetlb
+++ b/runtest/hugetlb
@@ -1,5 +1,6 @@
hugefallocate01 hugefallocate01
hugefallocate02 hugefallocate02
+hugefallocate03 hugefallocate03
hugefork01 hugefork01
hugefork02 hugefork02
diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
index 763f134dd..f4d5a6dae 100644
--- a/testcases/kernel/mem/.gitignore
+++ b/testcases/kernel/mem/.gitignore
@@ -2,6 +2,7 @@
/cpuset/cpuset02
/hugetlb/hugefallocate/hugefallocate01
/hugetlb/hugefallocate/hugefallocate02
+/hugetlb/hugefallocate/hugefallocate03
/hugetlb/hugefork/hugefork01
/hugetlb/hugefork/hugefork02
/hugetlb/hugemmap/hugemmap01
diff --git a/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
new file mode 100644
index 000000000..a63fa2f8f
--- /dev/null
+++ b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 Pavithra <pavrampu@linux.ibm.com>
+ */
+
+/*\
+ * Stress test :manpage:`fallocate(2)`. This test starts three threads:
+ *
+ * - Thread one will continually punch/fill holes via :manpage:`fallocate(2)`.
+ * - Thread two will continually fault in those same pages.
+ * - Thread three will continually :manpage:`mmap(2)` / :manpage:`munmap(2)` that page range.
+ *
+ * Requires root to mount hugetlbfs.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <sys/mount.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <time.h>
+
+#include "hugetlb.h"
+#include "lapi/fallocate.h"
+#include "tst_safe_pthread.h"
+
+#define MNTPOINT "hugetlbfs/"
+#define MAX_PAGES_TO_USE 100
+#define FALLOCATE_ITERATIONS 100000
+
+static int fd = -1;
+static unsigned long max_hpages;
+static long hpage_size;
+static void *thread_fallocate(void *arg)
+{
+ int i, err;
+ long tpage;
+
+ (void)arg;
+
+ for (i = 0; i < FALLOCATE_ITERATIONS; i++) {
+ tpage = ((long long)random()) % (max_hpages);
+ err = fallocate(fd,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ tpage * hpage_size, hpage_size);
+ if (err) {
+ tst_res(TFAIL | TERRNO, "fallocate(PUNCH_HOLE) failed at page %ld", tpage);
+ return NULL;
+ }
+ err = fallocate(fd, 0, tpage * hpage_size, hpage_size);
+ if (err) {
+ tst_res(TFAIL | TERRNO, "fallocate(fill) failed at page %ld", tpage);
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+static volatile int run;
+static sigjmp_buf fault_jmp;
+
+static void sigbus_handler(int signum LTP_ATTRIBUTE_UNUSED)
+{
+ siglongjmp(fault_jmp, 1);
+}
+
+static void *thread_fault(void *arg)
+{
+ long tpage;
+ char foo;
+ void *addr;
+ struct sigaction sa = {
+ .sa_handler = sigbus_handler,
+ };
+ struct sigaction old_sa;
+
+ (void)arg;
+
+ SAFE_SIGACTION(SIGBUS, &sa, &old_sa);
+
+ addr = SAFE_MMAP(NULL, max_hpages * hpage_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, 0);
+
+ while (run) {
+ tpage = ((long long)random()) % (max_hpages);
+
+ if (sigsetjmp(fault_jmp, 1) == 0) {
+ foo = *((char *)(addr + (tpage * hpage_size)));
+ *((volatile char *)(addr + (tpage * hpage_size))) = foo;
+ }
+ }
+
+ SAFE_MUNMAP(addr, max_hpages * hpage_size);
+
+ /* fault_jmp is no longer valid once this thread exits */
+ SAFE_SIGACTION(SIGBUS, &old_sa, NULL);
+
+ return NULL;
+}
+
+static void *thread_mmap_munmap(void *arg)
+{
+ void *addr;
+
+ (void)arg;
+
+ while (run) {
+ addr = mmap(NULL, max_hpages * hpage_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (addr != MAP_FAILED)
+ SAFE_MUNMAP(addr, max_hpages * hpage_size);
+ }
+
+ return NULL;
+}
+
+static void run_test(void)
+{
+ int err;
+ long nr_hpages_free;
+ unsigned long free_before, free_after;
+ unsigned long rsvd_before, rsvd_after;
+ pthread_t falloc_th, fault_th, mmap_munmap_th;
+
+ fd = tst_creat_unlinked(MNTPOINT, 0, 0600);
+
+ unsigned int seed = (unsigned int)getpid() * time(NULL);
+
+ srandom(seed);
+ tst_res(TINFO, "Seed = %u", seed);
+ nr_hpages_free = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ max_hpages = MIN(nr_hpages_free, MAX_PAGES_TO_USE);
+ free_before = nr_hpages_free;
+ rsvd_before = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
+
+ /* First preallocate file with max_hpages pages */
+ err = fallocate(fd, 0, 0, hpage_size * max_hpages);
+ if (err) {
+ if (errno == EOPNOTSUPP)
+ tst_brk(TCONF, "fallocate() Operation is not supported");
+ tst_brk(TBROK | TERRNO, "fallocate() failed to preallocate");
+ }
+
+ free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ if (free_before - free_after != max_hpages) {
+ tst_brk(TBROK, "fallocate did not preallocate %lu huge pages",
+ max_hpages);
+ }
+
+ run = 1;
+
+ SAFE_PTHREAD_CREATE(&falloc_th, NULL, thread_fallocate, NULL);
+
+ SAFE_PTHREAD_CREATE(&fault_th, NULL, thread_fault, NULL);
+
+ SAFE_PTHREAD_CREATE(&mmap_munmap_th, NULL, thread_mmap_munmap, NULL);
+
+ SAFE_PTHREAD_JOIN(falloc_th, NULL);
+
+ run = 0;
+
+ SAFE_PTHREAD_JOIN(fault_th, NULL);
+
+ SAFE_PTHREAD_JOIN(mmap_munmap_th, NULL);
+
+ SAFE_CLOSE(fd);
+
+ free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ rsvd_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
+
+ TST_EXP_EQ_LU(free_after, free_before);
+ TST_EXP_EQ_LU(rsvd_after, rsvd_before);
+}
+
+static void setup(void)
+{
+ hpage_size = tst_get_hugepage_size();
+}
+
+static void cleanup(void)
+{
+ if (fd != -1)
+ 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 = {MAX_PAGES_TO_USE, TST_REQUEST},
+};
--
2.56.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [LTP] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
2026-11-07 6:28 [LTP] [PATCH v10] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs Pavithra
@ 2026-11-07 10:51 ` linuxtestproject.agent
0 siblings, 0 replies; 7+ messages in thread
From: linuxtestproject.agent @ 2026-11-07 10:51 UTC (permalink / raw)
To: Pavithra; +Cc: ltp
Hi Pavithra,
On Sat Nov 7, 2026, Pavithra <pavrampu@linux.ibm.com> wrote:
> hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
> +#include <pthread.h>
> +#include <signal.h>
> +#include <setjmp.h>
> +#include <time.h>
> +
> +#include "hugetlb.h"
> +#include "lapi/fallocate.h"
> +#include "tst_safe_pthread.h"
testcases/kernel/mem/hugetlb/hugefallocate/Makefile is missing
"hugefallocate03: CFLAGS += -pthread" (or "LDLIBS += -lpthread"). On
supported distributions with glibc < 2.34, linking fails with undefined
references to pthread_create and pthread_join.
> + for (i = 0; i < FALLOCATE_ITERATIONS; i++) {
> + tpage = ((long long)random()) % (max_hpages);
> + err = fallocate(fd,
> + FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
> + tpage * hpage_size, hpage_size);
> + if (err) {
> + tst_res(TFAIL | TERRNO, "fallocate(PUNCH_HOLE) failed at page %ld", tpage);
> + return NULL;
> + }
> + err = fallocate(fd, 0, tpage * hpage_size, hpage_size);
> + if (err) {
> + tst_res(TFAIL | TERRNO, "fallocate(fill) failed at page %ld", tpage);
> + return NULL;
> + }
> + }
Each iteration punches and refills a hugepage, which zeroes a full hugepage in
the kernel (e.g. 200 GB total for 2 MB hugepages, or 1.6 TB for 16 MB
hugepages on ppc64le) and can exceed the default 30s timeout. Set .runtime in
struct tst_test and check tst_remaining_runtime() in the loop condition.
> + nr_hpages_free = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
> + max_hpages = MIN(nr_hpages_free, MAX_PAGES_TO_USE);
> + free_before = nr_hpages_free;
> + rsvd_before = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
> +
> + /* First preallocate file with max_hpages pages */
> + err = fallocate(fd, 0, 0, hpage_size * max_hpages);
> + if (err) {
> + if (errno == EOPNOTSUPP)
> + tst_brk(TCONF, "fallocate() Operation is not supported");
> + tst_brk(TBROK | TERRNO, "fallocate() failed to preallocate");
> + }
Because .hugepages uses TST_REQUEST, tst_hugepages and nr_hpages_free can be 0
when the system cannot allocate hugepages. In that case max_hpages is 0 and
fallocate(fd, 0, 0, 0) fails with EINVAL, triggering TBROK instead of TCONF;
check "if (!tst_hugepages || !nr_hpages_free) tst_brk(TCONF, ...);" first.
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread
* [LTP] [PATCH v11] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
@ 2026-11-07 12:05 Pavithra
2026-11-07 16:44 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 7+ messages in thread
From: Pavithra @ 2026-11-07 12:05 UTC (permalink / raw)
To: ltp; +Cc: pavrampu
Stress test fallocate() on hugetlbfs with three concurrent threads:
one continuously punches and fills holes, one faults in hugepages,
and one continuously mmaps and munmaps the same file range.
Verify no hugepage leak occurs after the stress run.
Signed-off-by: Pavithra <pavrampu@linux.ibm.com>
---
v10 -> v11:
- Set .runtime and stop the fallocate loop via tst_remaining_runtime() to avoid
exceeding the default timeout with large hugepage sizes.
- Report TCONF instead of TBROK when no huge pages can be reserved/are free.
- Makefile: add -pthread for hugefallocate03 (needed to link on glibc < 2.34).
Link to v10: https://lore.kernel.org/ltp/20261107062811.79329-1-pavrampu@linux.ibm.com/
---
runtest/hugetlb | 1 +
testcases/kernel/mem/.gitignore | 1 +
.../kernel/mem/hugetlb/hugefallocate/Makefile | 1 +
.../hugetlb/hugefallocate/hugefallocate03.c | 204 ++++++++++++++++++
4 files changed, 207 insertions(+)
create mode 100644 testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
diff --git a/runtest/hugetlb b/runtest/hugetlb
index fd687a14e..2e7bd1779 100644
--- a/runtest/hugetlb
+++ b/runtest/hugetlb
@@ -1,5 +1,6 @@
hugefallocate01 hugefallocate01
hugefallocate02 hugefallocate02
+hugefallocate03 hugefallocate03
hugefork01 hugefork01
hugefork02 hugefork02
diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
index 763f134dd..f4d5a6dae 100644
--- a/testcases/kernel/mem/.gitignore
+++ b/testcases/kernel/mem/.gitignore
@@ -2,6 +2,7 @@
/cpuset/cpuset02
/hugetlb/hugefallocate/hugefallocate01
/hugetlb/hugefallocate/hugefallocate02
+/hugetlb/hugefallocate/hugefallocate03
/hugetlb/hugefork/hugefork01
/hugetlb/hugefork/hugefork02
/hugetlb/hugemmap/hugemmap01
diff --git a/testcases/kernel/mem/hugetlb/hugefallocate/Makefile b/testcases/kernel/mem/hugetlb/hugefallocate/Makefile
index 77ebb0aef..0d3e61ec7 100644
--- a/testcases/kernel/mem/hugetlb/hugefallocate/Makefile
+++ b/testcases/kernel/mem/hugetlb/hugefallocate/Makefile
@@ -8,3 +8,4 @@ include $(top_srcdir)/include/mk/testcases.mk
include $(abs_srcdir)/../Makefile.inc
include $(top_srcdir)/include/mk/generic_leaf_target.mk
+hugefallocate03: CFLAGS+=-pthread
diff --git a/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
new file mode 100644
index 000000000..6db6160eb
--- /dev/null
+++ b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 Pavithra <pavrampu@linux.ibm.com>
+ */
+
+/*\
+ * Stress test :manpage:`fallocate(2)`. This test starts three threads:
+ *
+ * - Thread one will continually punch/fill holes via :manpage:`fallocate(2)`.
+ * - Thread two will continually fault in those same pages.
+ * - Thread three will continually :manpage:`mmap(2)` / :manpage:`munmap(2)` that page range.
+ *
+ * Requires root to mount hugetlbfs.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <sys/mount.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <time.h>
+
+#include "hugetlb.h"
+#include "lapi/fallocate.h"
+#include "tst_safe_pthread.h"
+
+#define MNTPOINT "hugetlbfs/"
+#define MAX_PAGES_TO_USE 100
+#define FALLOCATE_ITERATIONS 100000
+
+static int fd = -1;
+static unsigned long max_hpages;
+static long hpage_size;
+static void *thread_fallocate(void *arg)
+{
+ int i, err;
+ long tpage;
+
+ (void)arg;
+
+ for (i = 0; i < FALLOCATE_ITERATIONS && tst_remaining_runtime(); i++) {
+ tpage = ((long long)random()) % (max_hpages);
+ err = fallocate(fd,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ tpage * hpage_size, hpage_size);
+ if (err) {
+ tst_res(TFAIL | TERRNO, "fallocate(PUNCH_HOLE) failed at page %ld", tpage);
+ return NULL;
+ }
+ err = fallocate(fd, 0, tpage * hpage_size, hpage_size);
+ if (err) {
+ tst_res(TFAIL | TERRNO, "fallocate(fill) failed at page %ld", tpage);
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+static volatile int run;
+static sigjmp_buf fault_jmp;
+
+static void sigbus_handler(int signum LTP_ATTRIBUTE_UNUSED)
+{
+ siglongjmp(fault_jmp, 1);
+}
+
+static void *thread_fault(void *arg)
+{
+ long tpage;
+ char foo;
+ void *addr;
+ struct sigaction sa = {
+ .sa_handler = sigbus_handler,
+ };
+ struct sigaction old_sa;
+
+ (void)arg;
+
+ SAFE_SIGACTION(SIGBUS, &sa, &old_sa);
+
+ addr = SAFE_MMAP(NULL, max_hpages * hpage_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, 0);
+
+ while (run) {
+ tpage = ((long long)random()) % (max_hpages);
+
+ if (sigsetjmp(fault_jmp, 1) == 0) {
+ foo = *((char *)(addr + (tpage * hpage_size)));
+ *((volatile char *)(addr + (tpage * hpage_size))) = foo;
+ }
+ }
+
+ SAFE_MUNMAP(addr, max_hpages * hpage_size);
+
+ /* fault_jmp is no longer valid once this thread exits */
+ SAFE_SIGACTION(SIGBUS, &old_sa, NULL);
+
+ return NULL;
+}
+
+static void *thread_mmap_munmap(void *arg)
+{
+ void *addr;
+
+ (void)arg;
+
+ while (run) {
+ addr = mmap(NULL, max_hpages * hpage_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (addr != MAP_FAILED)
+ SAFE_MUNMAP(addr, max_hpages * hpage_size);
+ }
+
+ return NULL;
+}
+
+static void run_test(void)
+{
+ int err;
+ long nr_hpages_free;
+ unsigned long free_before, free_after;
+ unsigned long rsvd_before, rsvd_after;
+ pthread_t falloc_th, fault_th, mmap_munmap_th;
+
+ fd = tst_creat_unlinked(MNTPOINT, 0, 0600);
+
+ unsigned int seed = (unsigned int)getpid() * time(NULL);
+
+ srandom(seed);
+ tst_res(TINFO, "Seed = %u", seed);
+ nr_hpages_free = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ if (!tst_hugepages || !nr_hpages_free)
+ tst_brk(TCONF, "No huge pages available");
+
+ max_hpages = MIN(nr_hpages_free, MAX_PAGES_TO_USE);
+ free_before = nr_hpages_free;
+ rsvd_before = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
+
+ /* First preallocate file with max_hpages pages */
+ err = fallocate(fd, 0, 0, hpage_size * max_hpages);
+ if (err) {
+ if (errno == EOPNOTSUPP)
+ tst_brk(TCONF, "fallocate() Operation is not supported");
+ tst_brk(TBROK | TERRNO, "fallocate() failed to preallocate");
+ }
+
+ free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ if (free_before - free_after != max_hpages) {
+ tst_brk(TBROK, "fallocate did not preallocate %lu huge pages",
+ max_hpages);
+ }
+
+ run = 1;
+
+ SAFE_PTHREAD_CREATE(&falloc_th, NULL, thread_fallocate, NULL);
+
+ SAFE_PTHREAD_CREATE(&fault_th, NULL, thread_fault, NULL);
+
+ SAFE_PTHREAD_CREATE(&mmap_munmap_th, NULL, thread_mmap_munmap, NULL);
+
+ SAFE_PTHREAD_JOIN(falloc_th, NULL);
+
+ run = 0;
+
+ SAFE_PTHREAD_JOIN(fault_th, NULL);
+
+ SAFE_PTHREAD_JOIN(mmap_munmap_th, NULL);
+
+ SAFE_CLOSE(fd);
+
+ free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ rsvd_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
+
+ TST_EXP_EQ_LU(free_after, free_before);
+ TST_EXP_EQ_LU(rsvd_after, rsvd_before);
+}
+
+static void setup(void)
+{
+ hpage_size = tst_get_hugepage_size();
+}
+
+static void cleanup(void)
+{
+ if (fd != -1)
+ 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,
+ .runtime = 60,
+ .hugepages = {MAX_PAGES_TO_USE, TST_REQUEST},
+};
--
2.56.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [LTP] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
2026-11-07 12:05 [LTP] [PATCH v11] " Pavithra
@ 2026-11-07 16:44 ` linuxtestproject.agent
0 siblings, 0 replies; 7+ messages in thread
From: linuxtestproject.agent @ 2026-11-07 16:44 UTC (permalink / raw)
To: Pavithra; +Cc: ltp
Hi Pavithra,
On 2026-11-07, Pavithra <pavrampu@linux.ibm.com> wrote:
> hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
Verdict - Reviewed
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread
* [LTP] [PATCH v9] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
@ 2026-09-23 8:01 Pavithra
2026-09-23 10:00 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 7+ messages in thread
From: Pavithra @ 2026-09-23 8:01 UTC (permalink / raw)
To: ltp; +Cc: pavrampu
Stress test fallocate() on hugetlbfs with three concurrent threads:
one continuously punches and fills holes, one faults in hugepages,
and one continuously mmaps and munmaps the same file range.
Verify no hugepage leak occurs after the stress run.
Signed-off-by: Pavithra <pavrampu@linux.ibm.com>
---
v8 -> v9:
- Add missing #include <time.h> for time()
- Remove trailing colons from fallocate() error format strings
- Remove thread_err flag; return early on fallocate failure to avoid
log flooding; tst_res() already marks the test as failed
- Use SAFE_MUNMAP() instead of plain munmap() in thread_fault_cleanup()
- Assign free_before = nr_hpages_free to avoid redundant meminfo read
- Change TST_NEEDS to TST_REQUEST in .hugepages to avoid unnecessary
TCONF on systems with large hugepage sizes or limited memory
Link to v8: https://lore.kernel.org/ltp/20260920113519.1138936-1-pavrampu@linux.ibm.com/
---
runtest/hugetlb | 1 +
testcases/kernel/mem/.gitignore | 1 +
.../hugetlb/hugefallocate/hugefallocate03.c | 214 ++++++++++++++++++
3 files changed, 216 insertions(+)
create mode 100644 testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
diff --git a/runtest/hugetlb b/runtest/hugetlb
index 621c9718a..cd1c2794e 100644
--- a/runtest/hugetlb
+++ b/runtest/hugetlb
@@ -1,5 +1,6 @@
hugefallocate01 hugefallocate01
hugefallocate02 hugefallocate02
+hugefallocate03 hugefallocate03
hugefork01 hugefork01
hugefork02 hugefork02
diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
index 9e706e1c8..3086d1ac6 100644
--- a/testcases/kernel/mem/.gitignore
+++ b/testcases/kernel/mem/.gitignore
@@ -2,6 +2,7 @@
/cpuset/cpuset02
/hugetlb/hugefallocate/hugefallocate01
/hugetlb/hugefallocate/hugefallocate02
+/hugetlb/hugefallocate/hugefallocate03
/hugetlb/hugefork/hugefork01
/hugetlb/hugefork/hugefork02
/hugetlb/hugemmap/hugemmap01
diff --git a/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
new file mode 100644
index 000000000..aca60baab
--- /dev/null
+++ b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2015 Oracle Corporation
+ * Author: Mike Kravetz
+ * Copyright (c) 2026 Pavithra <pavrampu@linux.ibm.com>
+ */
+
+/*\
+ * Stress test :manpage:`fallocate(2)`. This test starts three threads:
+ *
+ * - Thread one will continually punch/fill holes via :manpage:`fallocate(2)`.
+ * - Thread two will continually fault in those same pages.
+ * - Thread three will continually :manpage:`mmap(2)` / :manpage:`munmap(2)` that page range.
+ *
+ * Requires root to mount hugetlbfs.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <sys/mount.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <time.h>
+
+#include "hugetlb.h"
+#include "lapi/fallocate.h"
+#include "tst_safe_pthread.h"
+
+#define MNTPOINT "hugetlbfs/"
+#define MAX_PAGES_TO_USE 100
+#define FALLOCATE_ITERATIONS 100000
+
+static int fd = -1;
+static unsigned long max_hpages;
+static long hpage_size;
+static void *thread_fallocate(void *arg)
+{
+ int i, err;
+ long tpage;
+
+ (void)arg;
+
+ for (i = 0; i < FALLOCATE_ITERATIONS; i++) {
+ tpage = ((long long)random()) % (max_hpages);
+ err = fallocate(fd,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ tpage * hpage_size, hpage_size);
+ if (err) {
+ tst_res(TFAIL | TERRNO, "fallocate(PUNCH_HOLE) failed at page %ld", tpage);
+ return NULL;
+ }
+ err = fallocate(fd, 0, tpage * hpage_size, hpage_size);
+ if (err) {
+ tst_res(TFAIL | TERRNO, "fallocate(fill) failed at page %ld", tpage);
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+static void *fault_mmap_addr;
+static sigjmp_buf fault_jmp;
+
+static void sigbus_handler(int signum LTP_ATTRIBUTE_UNUSED)
+{
+ siglongjmp(fault_jmp, 1);
+}
+
+static void thread_fault_cleanup(void *arg)
+{
+ (void)arg;
+
+ if (fault_mmap_addr) {
+ SAFE_MUNMAP(fault_mmap_addr, max_hpages * hpage_size);
+ fault_mmap_addr = NULL;
+ }
+}
+
+static void *thread_fault(void *arg)
+{
+ long tpage;
+ char foo;
+ struct sigaction sa = {
+ .sa_handler = sigbus_handler,
+ };
+
+ (void)arg;
+
+ SAFE_SIGACTION(SIGBUS, &sa, NULL);
+
+ fault_mmap_addr = SAFE_MMAP(NULL, max_hpages * hpage_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, 0);
+
+ pthread_cleanup_push(thread_fault_cleanup, NULL);
+
+ while (1) {
+ tpage = ((long long)random()) % (max_hpages);
+
+ if (sigsetjmp(fault_jmp, 1) == 0) {
+ foo = *((char *)(fault_mmap_addr + (tpage * hpage_size)));
+ *((volatile char *)(fault_mmap_addr + (tpage * hpage_size))) = foo;
+ }
+
+ pthread_testcancel();
+ }
+
+ pthread_cleanup_pop(1);
+
+ return NULL;
+}
+
+static void *thread_mmap_munmap(void *arg)
+{
+ void *addr;
+
+ (void)arg;
+
+ while (1) {
+ addr = mmap(NULL, max_hpages * hpage_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (addr != MAP_FAILED)
+ SAFE_MUNMAP(addr, max_hpages * hpage_size);
+
+ pthread_testcancel();
+ }
+
+ return NULL;
+}
+
+static void run_test(void)
+{
+ int err;
+ long nr_hpages_free;
+ unsigned long free_before, free_after;
+ unsigned long rsvd_before, rsvd_after;
+ pthread_t falloc_th, fault_th, mmap_munmap_th;
+ void *falloc_th_ret, *fault_th_ret, *mmap_munmap_th_ret;
+
+ fd = tst_creat_unlinked(MNTPOINT, 0, 0600);
+
+ unsigned int seed = (unsigned int)getpid() * time(NULL);
+
+ srandom(seed);
+ tst_res(TINFO, "Seed = %u", seed);
+ nr_hpages_free = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ max_hpages = MIN(nr_hpages_free, MAX_PAGES_TO_USE);
+ free_before = nr_hpages_free;
+ rsvd_before = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
+
+ /* First preallocate file with max_hpages pages */
+ err = fallocate(fd, 0, 0, hpage_size * max_hpages);
+ if (err) {
+ if (errno == EOPNOTSUPP)
+ tst_brk(TCONF, "fallocate() Operation is not supported");
+ tst_brk(TBROK | TERRNO, "fallocate() failed to preallocate");
+ }
+
+ free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ if (free_before - free_after != max_hpages) {
+ tst_brk(TBROK, "fallocate did not preallocate %lu huge pages",
+ max_hpages);
+ }
+
+ SAFE_PTHREAD_CREATE(&falloc_th, NULL, thread_fallocate, NULL);
+
+ SAFE_PTHREAD_CREATE(&fault_th, NULL, thread_fault, NULL);
+
+ SAFE_PTHREAD_CREATE(&mmap_munmap_th, NULL, thread_mmap_munmap, NULL);
+
+ SAFE_PTHREAD_JOIN(falloc_th, &falloc_th_ret);
+
+ SAFE_PTHREAD_CANCEL(fault_th);
+
+ SAFE_PTHREAD_JOIN(fault_th, &fault_th_ret);
+
+ SAFE_PTHREAD_CANCEL(mmap_munmap_th);
+
+ SAFE_PTHREAD_JOIN(mmap_munmap_th, &mmap_munmap_th_ret);
+
+ SAFE_CLOSE(fd);
+
+ free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ rsvd_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
+
+ TST_EXP_EQ_LU(free_after, free_before);
+ TST_EXP_EQ_LU(rsvd_after, rsvd_before);
+}
+
+static void setup(void)
+{
+ hpage_size = tst_get_hugepage_size();
+}
+
+static void cleanup(void)
+{
+ if (fd != -1)
+ 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 = {MAX_PAGES_TO_USE, TST_REQUEST},
+};
--
2.55.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [LTP] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
2026-09-23 8:01 [LTP] [PATCH v9] " Pavithra
@ 2026-09-23 10:00 ` linuxtestproject.agent
2026-11-02 15:59 ` Cyril Hrubis
0 siblings, 1 reply; 7+ messages in thread
From: linuxtestproject.agent @ 2026-09-23 10:00 UTC (permalink / raw)
To: Pavithra; +Cc: ltp
Hi Pavithra,
On Wed Sep 23 13:31:50 2026 +0530, Pavithra wrote:
> hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
> +static int fd = -1;
> +static unsigned long max_hpages;
> +static long hpage_size;
> +static void *thread_fallocate(void *arg)
Add a blank line between variable declarations and function definitions.
> + SAFE_SIGACTION(SIGBUS, &sa, NULL);
> +
> + fault_mmap_addr = SAFE_MMAP(NULL, max_hpages * hpage_size,
> + PROT_READ | PROT_WRITE, MAP_SHARED,
> + fd, 0);
> +
> + pthread_cleanup_push(thread_fault_cleanup, NULL);
> +
> + while (1) {
> + tpage = ((long long)random()) % (max_hpages);
> +
> + if (sigsetjmp(fault_jmp, 1) == 0) {
> + foo = *((char *)(fault_mmap_addr + (tpage * hpage_size)));
> + *((volatile char *)(fault_mmap_addr + (tpage * hpage_size))) = foo;
> + }
Save the original SIGBUS handler and restore it upon thread termination or in
cleanup. If SIGBUS is raised after this thread terminates, siglongjmp() jumps
to an invalid stack.
> + while (1) {
> + addr = mmap(NULL, max_hpages * hpage_size,
> + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
> + if (addr != MAP_FAILED)
> + SAFE_MUNMAP(addr, max_hpages * hpage_size);
> +
> + pthread_testcancel();
> + }
Use SAFE_MMAP() instead of mmap() and drop the MAP_FAILED check.
> + nr_hpages_free = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
> + max_hpages = MIN(nr_hpages_free, MAX_PAGES_TO_USE);
> + free_before = nr_hpages_free;
> + rsvd_before = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
> +
> + /* First preallocate file with max_hpages pages */
> + err = fallocate(fd, 0, 0, hpage_size * max_hpages);
Because .hugepages uses TST_REQUEST, nr_hpages_free and max_hpages can be 0.
When max_hpages is 0, fallocate() fails with EINVAL (causing TBROK instead of
TCONF), and the worker threads divide by zero. Add a check to abort with
tst_brk(TCONF, ...) when max_hpages is 0.
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [LTP] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
2026-09-23 10:00 ` [LTP] " linuxtestproject.agent
@ 2026-11-02 15:59 ` Cyril Hrubis
0 siblings, 0 replies; 7+ messages in thread
From: Cyril Hrubis @ 2026-11-02 15:59 UTC (permalink / raw)
To: linuxtestproject.agent; +Cc: Pavithra, ltp
Hi!
> > + SAFE_SIGACTION(SIGBUS, &sa, NULL);
> > +
> > + fault_mmap_addr = SAFE_MMAP(NULL, max_hpages * hpage_size,
> > + PROT_READ | PROT_WRITE, MAP_SHARED,
> > + fd, 0);
> > +
> > + pthread_cleanup_push(thread_fault_cleanup, NULL);
> > +
> > + while (1) {
> > + tpage = ((long long)random()) % (max_hpages);
> > +
> > + if (sigsetjmp(fault_jmp, 1) == 0) {
> > + foo = *((char *)(fault_mmap_addr + (tpage * hpage_size)));
> > + *((volatile char *)(fault_mmap_addr + (tpage * hpage_size))) = foo;
> > + }
>
> Save the original SIGBUS handler and restore it upon thread termination or in
> cleanup. If SIGBUS is raised after this thread terminates, siglongjmp() jumps
> to an invalid stack.
More generally we can just remove all the thread cleanup registration
and cancelation points if we just do:
static volatile int run;
...
void *pthread_func(void *)
{
...
while (run) {
...
}
SAFE_MUNMAP(...);
reutrn NULL;
}
The main thread can then stop all three threads by setting run = 0 and
the cleanup runs without the pthread cleanup complexity.
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread
* [LTP] [PATCH v8] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
@ 2026-09-20 11:35 Pavithra
2026-09-20 14:43 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 7+ messages in thread
From: Pavithra @ 2026-09-20 11:35 UTC (permalink / raw)
To: ltp; +Cc: pavrampu
Stress test fallocate() on hugetlbfs with three concurrent threads:
one continuously punches and fills holes, one faults in hugepages,
and one continuously mmaps and munmaps the same file range.
Verify no hugepage leak occurs after the stress run.
Signed-off-by: Pavithra <pavrampu@linux.ibm.com>
---
v7 -> v8:
- Document why root privileges are required in the test description.
- Format syscall names with Sphinx :manpage: roles and avoid abbreviations.
- Drop redundant mutexes (fault_addr_lock, mmap_munmap_lock) and make mmap_munmap_addr local.
- Add sigsetjmp/siglongjmp handler to safely recover from concurrent SIGBUS during page faults.
- Use non-fatal mmap() in thread_mmap_munmap to tolerate transient ENOMEM under stress.
- Cast write-back pointer to (volatile char *) to prevent compiler optimization.
- Replace nanosleep() with pthread_testcancel() for thread cancellation points.
- Abort with tst_brk(TBROK) on preallocation failure instead of jumping to cleanup.
- Use TST_EXP_EQ_LU() macros to report hugepage counter assertions.
- Fix format specifiers (%u for seed, %lu for max_hpages) and check (fd != -1) in cleanup().
Link to v7: https://lore.kernel.org/ltp/20260919174920.1078796-1-pavrampu@linux.ibm.com/
---
runtest/hugetlb | 1 +
testcases/kernel/mem/.gitignore | 1 +
.../hugetlb/hugefallocate/hugefallocate03.c | 220 ++++++++++++++++++
3 files changed, 222 insertions(+)
create mode 100644 testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
diff --git a/runtest/hugetlb b/runtest/hugetlb
index 621c9718a..cd1c2794e 100644
--- a/runtest/hugetlb
+++ b/runtest/hugetlb
@@ -1,5 +1,6 @@
hugefallocate01 hugefallocate01
hugefallocate02 hugefallocate02
+hugefallocate03 hugefallocate03
hugefork01 hugefork01
hugefork02 hugefork02
diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
index 9e706e1c8..3086d1ac6 100644
--- a/testcases/kernel/mem/.gitignore
+++ b/testcases/kernel/mem/.gitignore
@@ -2,6 +2,7 @@
/cpuset/cpuset02
/hugetlb/hugefallocate/hugefallocate01
/hugetlb/hugefallocate/hugefallocate02
+/hugetlb/hugefallocate/hugefallocate03
/hugetlb/hugefork/hugefork01
/hugetlb/hugefork/hugefork02
/hugetlb/hugemmap/hugemmap01
diff --git a/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
new file mode 100644
index 000000000..b5441428b
--- /dev/null
+++ b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2015 Oracle Corporation
+ * Author: Mike Kravetz
+ * Copyright (c) 2026 Pavithra <pavrampu@linux.ibm.com>
+ */
+
+/*\
+ * Stress test :manpage:`fallocate(2)`. This test starts three threads:
+ *
+ * - Thread one will continually punch/fill holes via :manpage:`fallocate(2)`.
+ * - Thread two will continually fault in those same pages.
+ * - Thread three will continually :manpage:`mmap(2)` / :manpage:`munmap(2)` that page range.
+ *
+ * Requires root to mount hugetlbfs.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <sys/mount.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <signal.h>
+#include <setjmp.h>
+
+#include "hugetlb.h"
+#include "lapi/fallocate.h"
+#include "tst_safe_pthread.h"
+
+#define MNTPOINT "hugetlbfs/"
+#define MAX_PAGES_TO_USE 100
+#define FALLOCATE_ITERATIONS 100000
+
+static int fd = -1;
+static unsigned long max_hpages;
+static long hpage_size;
+static volatile int thread_err;
+
+static void *thread_fallocate(void *arg)
+{
+ int i, err;
+ long tpage;
+
+ (void)arg;
+
+ for (i = 0; i < FALLOCATE_ITERATIONS; i++) {
+ tpage = ((long long)random()) % (max_hpages);
+ err = fallocate(fd,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ tpage * hpage_size, hpage_size);
+ if (err) {
+ tst_res(TFAIL | TERRNO, "fallocate(PUNCH_HOLE) failed at page %ld:", tpage);
+ thread_err = 1;
+ }
+ err = fallocate(fd, 0, tpage * hpage_size, hpage_size);
+ if (err) {
+ tst_res(TFAIL | TERRNO, "fallocate(fill) failed at page %ld:", tpage);
+ thread_err = 1;
+ }
+ }
+ return NULL;
+}
+
+static void *fault_mmap_addr;
+static sigjmp_buf fault_jmp;
+
+static void sigbus_handler(int signum LTP_ATTRIBUTE_UNUSED)
+{
+ siglongjmp(fault_jmp, 1);
+}
+
+static void thread_fault_cleanup(void *arg)
+{
+ (void)arg;
+
+ if (fault_mmap_addr) {
+ munmap(fault_mmap_addr, max_hpages * hpage_size);
+ fault_mmap_addr = NULL;
+ }
+}
+
+static void *thread_fault(void *arg)
+{
+ long tpage;
+ char foo;
+ struct sigaction sa = {
+ .sa_handler = sigbus_handler,
+ };
+
+ (void)arg;
+
+ SAFE_SIGACTION(SIGBUS, &sa, NULL);
+
+ fault_mmap_addr = SAFE_MMAP(NULL, max_hpages * hpage_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, 0);
+
+ pthread_cleanup_push(thread_fault_cleanup, NULL);
+
+ while (1) {
+ tpage = ((long long)random()) % (max_hpages);
+
+ if (sigsetjmp(fault_jmp, 1) == 0) {
+ foo = *((char *)(fault_mmap_addr + (tpage * hpage_size)));
+ *((volatile char *)(fault_mmap_addr + (tpage * hpage_size))) = foo;
+ }
+
+ pthread_testcancel();
+ }
+
+ pthread_cleanup_pop(1);
+
+ return NULL;
+}
+
+static void *thread_mmap_munmap(void *arg)
+{
+ void *addr;
+
+ (void)arg;
+
+ while (1) {
+ addr = mmap(NULL, max_hpages * hpage_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (addr != MAP_FAILED)
+ SAFE_MUNMAP(addr, max_hpages * hpage_size);
+
+ pthread_testcancel();
+ }
+
+ return NULL;
+}
+
+static void run_test(void)
+{
+ int err;
+ long nr_hpages_free;
+ unsigned long free_before, free_after;
+ unsigned long rsvd_before, rsvd_after;
+ pthread_t falloc_th, fault_th, mmap_munmap_th;
+ void *falloc_th_ret, *fault_th_ret, *mmap_munmap_th_ret;
+
+ fd = tst_creat_unlinked(MNTPOINT, 0, 0600);
+
+ unsigned int seed = (unsigned int)getpid() * time(NULL);
+
+ srandom(seed);
+ tst_res(TINFO, "Seed = %u", seed);
+ nr_hpages_free = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ max_hpages = MIN(nr_hpages_free, MAX_PAGES_TO_USE);
+ free_before = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ rsvd_before = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
+
+ /* First preallocate file with max_hpages pages */
+ err = fallocate(fd, 0, 0, hpage_size * max_hpages);
+ if (err) {
+ if (errno == EOPNOTSUPP)
+ tst_brk(TCONF, "fallocate() Operation is not supported");
+ tst_brk(TBROK | TERRNO, "fallocate() failed to preallocate");
+ }
+
+ free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ if (free_before - free_after != max_hpages) {
+ tst_brk(TBROK, "fallocate did not preallocate %lu huge pages",
+ max_hpages);
+ }
+
+ thread_err = 0;
+
+ SAFE_PTHREAD_CREATE(&falloc_th, NULL, thread_fallocate, NULL);
+
+ SAFE_PTHREAD_CREATE(&fault_th, NULL, thread_fault, NULL);
+
+ SAFE_PTHREAD_CREATE(&mmap_munmap_th, NULL, thread_mmap_munmap, NULL);
+
+ SAFE_PTHREAD_JOIN(falloc_th, &falloc_th_ret);
+
+ SAFE_PTHREAD_CANCEL(fault_th);
+
+ SAFE_PTHREAD_JOIN(fault_th, &fault_th_ret);
+
+ SAFE_PTHREAD_CANCEL(mmap_munmap_th);
+
+ SAFE_PTHREAD_JOIN(mmap_munmap_th, &mmap_munmap_th_ret);
+
+ SAFE_CLOSE(fd);
+
+ free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ rsvd_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
+
+ if (thread_err)
+ tst_res(TFAIL, "fallocate() failed during stress, see above");
+
+ TST_EXP_EQ_LU(free_after, free_before);
+ TST_EXP_EQ_LU(rsvd_after, rsvd_before);
+}
+
+static void setup(void)
+{
+ hpage_size = tst_get_hugepage_size();
+}
+
+static void cleanup(void)
+{
+ if (fd != -1)
+ 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 = {MAX_PAGES_TO_USE, TST_NEEDS},
+};
--
2.55.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [LTP] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
2026-09-20 11:35 [LTP] [PATCH v8] " Pavithra
@ 2026-09-20 14:43 ` linuxtestproject.agent
0 siblings, 0 replies; 7+ messages in thread
From: linuxtestproject.agent @ 2026-09-20 14:43 UTC (permalink / raw)
To: Pavithra; +Cc: ltp
Hi Pavithra,
On Sun Sep 20 17:05:19 2026 +0530, Pavithra wrote:
> hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <sys/mount.h>
> +#include <limits.h>
> +#include <sys/param.h>
> +#include <sys/types.h>
> +#include <pthread.h>
> +#include <signal.h>
> +#include <setjmp.h>
Add missing #include <time.h> for time().
> + if (err) {
> + tst_res(TFAIL | TERRNO, "fallocate(PUNCH_HOLE) failed at page %ld:", tpage);
> + thread_err = 1;
> + }
> + err = fallocate(fd, 0, tpage * hpage_size, hpage_size);
> + if (err) {
> + tst_res(TFAIL | TERRNO, "fallocate(fill) failed at page %ld:", tpage);
> + thread_err = 1;
> + }
Drop the trailing colons in the format strings; TERRNO automatically appends
": <errno>". Remove thread_err as tst_res() already records the failure.
Break the loop or return early on failure to avoid flooding the test log
with thousands of failure messages.
> +static void thread_fault_cleanup(void *arg)
> +{
> + (void)arg;
> +
> + if (fault_mmap_addr) {
> + munmap(fault_mmap_addr, max_hpages * hpage_size);
> + fault_mmap_addr = NULL;
> + }
> +}
Use SAFE_MUNMAP() instead of munmap().
> + nr_hpages_free = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
> + max_hpages = MIN(nr_hpages_free, MAX_PAGES_TO_USE);
> + free_before = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
Assign free_before = nr_hpages_free instead of reading /proc/meminfo
twice in consecutive lines.
> + if (thread_err)
> + tst_res(TFAIL, "fallocate() failed during stress, see above");
Remove this check; tst_res() in thread_fallocate() already marks the test
as failed.
> + .hugepages = {MAX_PAGES_TO_USE, TST_NEEDS},
Using TST_NEEDS with MAX_PAGES_TO_USE (100) causes unnecessary TCONF on
systems where hugepages are large (e.g. 16MB on ppc64le, 512MB on arm64)
or where memory is limited. Use TST_REQUEST, or require a smaller minimum
in .hugepages to keep the test portable.
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread
* [LTP] [PATCH v7] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
@ 2026-09-19 17:49 Pavithra
2026-09-19 20:14 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 7+ messages in thread
From: Pavithra @ 2026-09-19 17:49 UTC (permalink / raw)
To: ltp; +Cc: pavrampu
Stress test fallocate() on hugetlbfs with three concurrent threads:
one continuously punches and fills holes, one faults in hugepages,
and one continuously mmaps and munmaps the same file range.
Verify no hugepage leak occurs after the stress run.
Signed-off-by: Pavithra <pavrampu@linux.ibm.com>
---
v6 -> v7:
- Add volatile thread_err flag to propagate fallocate() failures
from thread_fallocate to the final pass/fail verdict
- Add pthread_mutex_t guards for fault_mmap_addr and mmap_munmap_addr
to fix data races between threads and their cleanup handlers
- Change .hugepages = {2, ...} to {MAX_PAGES_TO_USE, ...}
Link to v6: https://lore.kernel.org/ltp/20250928122544.2176739-1-pavrampu@linux.ibm.com/
---
runtest/hugetlb | 1 +
testcases/kernel/mem/.gitignore | 1 +
.../hugetlb/hugefallocate/hugefallocate03.c | 233 ++++++++++++++++++
3 files changed, 235 insertions(+)
create mode 100644 testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
diff --git a/runtest/hugetlb b/runtest/hugetlb
index 621c9718a..cd1c2794e 100644
--- a/runtest/hugetlb
+++ b/runtest/hugetlb
@@ -1,5 +1,6 @@
hugefallocate01 hugefallocate01
hugefallocate02 hugefallocate02
+hugefallocate03 hugefallocate03
hugefork01 hugefork01
hugefork02 hugefork02
diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
index 9e706e1c8..3086d1ac6 100644
--- a/testcases/kernel/mem/.gitignore
+++ b/testcases/kernel/mem/.gitignore
@@ -2,6 +2,7 @@
/cpuset/cpuset02
/hugetlb/hugefallocate/hugefallocate01
/hugetlb/hugefallocate/hugefallocate02
+/hugetlb/hugefallocate/hugefallocate03
/hugetlb/hugefork/hugefork01
/hugetlb/hugefork/hugefork02
/hugetlb/hugemmap/hugemmap01
diff --git a/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
new file mode 100644
index 000000000..e947a87eb
--- /dev/null
+++ b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate03.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2015 Oracle Corporation
+ * Author: Mike Kravetz
+ * Copyright (c) 2026 Pavithra <pavrampu@linux.ibm.com>
+ */
+
+/*\
+ * Stress test fallocate. This test starts three threads.
+ * Thread one will continually punch/fill holes via falloc.
+ * Thread two will continually fault in those same pages.
+ * Thread three will continually mmap/munmap that page range.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <sys/mount.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#include "hugetlb.h"
+#include "lapi/fallocate.h"
+#include "tst_safe_pthread.h"
+
+#define MNTPOINT "hugetlbfs/"
+#define MAX_PAGES_TO_USE 100
+#define FALLOCATE_ITERATIONS 100000
+
+static int fd = -1;
+static unsigned long max_hpages;
+static long hpage_size;
+static volatile int thread_err;
+
+static void *thread_fallocate(void *arg)
+{
+ int i, err;
+ long tpage;
+
+ (void)arg;
+
+ for (i = 0; i < FALLOCATE_ITERATIONS; i++) {
+ tpage = ((long long)random()) % (max_hpages);
+ err = fallocate(fd,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ tpage * hpage_size, hpage_size);
+ if (err) {
+ tst_res(TFAIL | TERRNO, "fallocate(PUNCH_HOLE) failed at page %ld:", tpage);
+ thread_err = 1;
+ }
+ err = fallocate(fd, 0, tpage * hpage_size, hpage_size);
+ if (err) {
+ tst_res(TFAIL | TERRNO, "fallocate(fill) failed at page %ld:", tpage);
+ thread_err = 1;
+ }
+ }
+ return NULL;
+}
+
+static pthread_mutex_t fault_addr_lock = PTHREAD_MUTEX_INITIALIZER;
+static void *fault_mmap_addr;
+
+static void thread_fault_cleanup(void *arg)
+{
+ (void)arg;
+
+ pthread_mutex_lock(&fault_addr_lock);
+ if (fault_mmap_addr) {
+ munmap(fault_mmap_addr, max_hpages * hpage_size);
+ fault_mmap_addr = NULL;
+ }
+ pthread_mutex_unlock(&fault_addr_lock);
+}
+
+static void *thread_fault(void *arg)
+{
+ long tpage;
+ char foo;
+ struct timespec ts = {};
+
+ (void)arg;
+
+ pthread_mutex_lock(&fault_addr_lock);
+ fault_mmap_addr = SAFE_MMAP(NULL, max_hpages * hpage_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, 0);
+ pthread_mutex_unlock(&fault_addr_lock);
+
+ pthread_cleanup_push(thread_fault_cleanup, NULL);
+
+ while (1) {
+ tpage = ((long long)random()) % (max_hpages);
+ pthread_mutex_lock(&fault_addr_lock);
+ foo = *((char *)(fault_mmap_addr + (tpage * hpage_size)));
+ *((char *)(fault_mmap_addr + (tpage * hpage_size))) = foo;
+ pthread_mutex_unlock(&fault_addr_lock);
+
+ nanosleep(&ts, NULL); /* thread cancellation point */
+ }
+
+ pthread_cleanup_pop(1);
+
+ return NULL;
+}
+
+static pthread_mutex_t mmap_munmap_lock = PTHREAD_MUTEX_INITIALIZER;
+static void *mmap_munmap_addr;
+
+static void thread_mmap_munmap_cleanup(void *arg)
+{
+ (void)arg;
+
+ pthread_mutex_lock(&mmap_munmap_lock);
+ if (mmap_munmap_addr) {
+ munmap(mmap_munmap_addr, max_hpages * hpage_size);
+ mmap_munmap_addr = NULL;
+ }
+ pthread_mutex_unlock(&mmap_munmap_lock);
+}
+
+static void *thread_mmap_munmap(void *arg)
+{
+ struct timespec ts = {};
+
+ (void)arg;
+
+ pthread_cleanup_push(thread_mmap_munmap_cleanup, NULL);
+
+ while (1) {
+ pthread_mutex_lock(&mmap_munmap_lock);
+ mmap_munmap_addr = SAFE_MMAP(NULL, max_hpages * hpage_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ SAFE_MUNMAP(mmap_munmap_addr, max_hpages * hpage_size);
+ mmap_munmap_addr = NULL;
+ pthread_mutex_unlock(&mmap_munmap_lock);
+
+ nanosleep(&ts, NULL); /* thread cancellation point */
+ }
+
+ pthread_cleanup_pop(1);
+ return NULL;
+}
+
+static void run_test(void)
+{
+ int err;
+ long nr_hpages_free;
+ unsigned long free_before, free_after;
+ unsigned long rsvd_before, rsvd_after;
+ pthread_t falloc_th, fault_th, mmap_munmap_th;
+ void *falloc_th_ret, *fault_th_ret, *mmap_munmap_th_ret;
+
+ fd = tst_creat_unlinked(MNTPOINT, 0, 0600);
+
+ unsigned int seed = (int)getpid() * time(NULL);
+
+ srandom(seed);
+ tst_res(TINFO, "Seed = %d", seed);
+ nr_hpages_free = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ max_hpages = MIN(nr_hpages_free, MAX_PAGES_TO_USE);
+ free_before = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ rsvd_before = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
+
+ /* First preallocate file with max_hpages pages */
+ err = fallocate(fd, 0, 0, hpage_size * max_hpages);
+ if (err) {
+ if (errno == EOPNOTSUPP)
+ tst_brk(TCONF, "fallocate() Operation is not supported");
+ tst_res(TFAIL | TERRNO, "fallocate():");
+ goto windup;
+ }
+
+ free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ if (free_before - free_after != max_hpages) {
+ tst_res(TFAIL, "fallocate did not preallocate %ld huge pages",
+ max_hpages);
+ goto windup;
+ }
+
+ thread_err = 0;
+
+ SAFE_PTHREAD_CREATE(&falloc_th, NULL, thread_fallocate, NULL);
+
+ SAFE_PTHREAD_CREATE(&fault_th, NULL, thread_fault, NULL);
+
+ SAFE_PTHREAD_CREATE(&mmap_munmap_th, NULL, thread_mmap_munmap, NULL);
+
+ SAFE_PTHREAD_JOIN(falloc_th, &falloc_th_ret);
+
+ SAFE_PTHREAD_CANCEL(fault_th);
+
+ SAFE_PTHREAD_JOIN(fault_th, &fault_th_ret);
+
+ SAFE_PTHREAD_CANCEL(mmap_munmap_th);
+
+ SAFE_PTHREAD_JOIN(mmap_munmap_th, &mmap_munmap_th_ret);
+
+windup:
+ SAFE_CLOSE(fd);
+
+ free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ rsvd_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
+
+ if (thread_err)
+ tst_res(TFAIL, "fallocate() failed during stress, see above");
+ else if (free_after != free_before || rsvd_after != rsvd_before)
+ tst_res(TFAIL, "free or reserve counts incorrect after fallocate stress test");
+ else
+ tst_res(TPASS, "fallocate stress test passed");
+}
+
+static void setup(void)
+{
+ hpage_size = tst_get_hugepage_size();
+}
+
+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 = {MAX_PAGES_TO_USE, TST_NEEDS},
+};
--
2.55.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [LTP] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
2026-09-19 17:49 [LTP] [PATCH v7] " Pavithra
@ 2026-09-19 20:14 ` linuxtestproject.agent
0 siblings, 0 replies; 7+ messages in thread
From: linuxtestproject.agent @ 2026-09-19 20:14 UTC (permalink / raw)
To: Pavithra; +Cc: ltp
Hi Pavithra,
On Sat Sep 19 23:19:20 2026 +0530, Pavithra <pavrampu@linux.ibm.com> wrote:
> hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs
> +/*\
> + * Stress test fallocate. This test starts three threads.
> + * Thread one will continually punch/fill holes via falloc.
> + * Thread two will continually fault in those same pages.
> + * Thread three will continually mmap/munmap that page range.
> + */
Format syscall names using the `:manpage:` role (e.g.
`:manpage:`fallocate(2)``, `:manpage:`mmap(2)``, `:manpage:`munmap(2)``)
and avoid abbreviations like "falloc". Document why root privileges are
required (.needs_root = 1).
> + while (1) {
> + tpage = ((long long)random()) % (max_hpages);
> + pthread_mutex_lock(&fault_addr_lock);
> + foo = *((char *)(fault_mmap_addr + (tpage * hpage_size)));
> + *((char *)(fault_mmap_addr + (tpage * hpage_size))) = foo;
> + pthread_mutex_unlock(&fault_addr_lock);
> +
> + nanosleep(&ts, NULL); /* thread cancellation point */
> + }
fault_addr_lock is not accessed by any other thread and can be removed.
Cast to volatile char * when writing back to prevent the compiler from
optimizing out the write. Replace nanosleep(&ts, NULL) with
pthread_testcancel() for thread cancellation.
> + while (1) {
> + pthread_mutex_lock(&mmap_munmap_lock);
> + mmap_munmap_addr = SAFE_MMAP(NULL, max_hpages * hpage_size,
> + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
> + SAFE_MUNMAP(mmap_munmap_addr, max_hpages * hpage_size);
> + mmap_munmap_addr = NULL;
> + pthread_mutex_unlock(&mmap_munmap_lock);
> +
> + nanosleep(&ts, NULL); /* thread cancellation point */
> + }
mmap_munmap_lock is unnecessary since no other thread accesses this
address; mmap_munmap_addr can be a local variable. Replace
nanosleep(&ts, NULL) with pthread_testcancel().
> + unsigned int seed = (int)getpid() * time(NULL);
> +
> + srandom(seed);
> + tst_res(TINFO, "Seed = %d", seed);
seed is unsigned int; use %u instead of %d.
> + /* First preallocate file with max_hpages pages */
> + err = fallocate(fd, 0, 0, hpage_size * max_hpages);
> + if (err) {
> + if (errno == EOPNOTSUPP)
> + tst_brk(TCONF, "fallocate() Operation is not supported");
> + tst_res(TFAIL | TERRNO, "fallocate():");
> + goto windup;
> + }
> +
> + free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
> + if (free_before - free_after != max_hpages) {
> + tst_res(TFAIL, "fallocate did not preallocate %ld huge pages",
> + max_hpages);
> + goto windup;
> + }
If fallocate or preallocation fails, branching to windup causes the test
to report TPASS in the subsequent check because SAFE_CLOSE(fd) restores
the free counts and thread_err remains 0. Use tst_brk(TBROK | TERRNO, ...)
to abort on preallocation failure. Also use %lu instead of %ld for
max_hpages.
> +windup:
> + SAFE_CLOSE(fd);
> +
> + free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
> + rsvd_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
> +
> + if (thread_err)
> + tst_res(TFAIL, "fallocate() failed during stress, see above");
> + else if (free_after != free_before || rsvd_after != rsvd_before)
> + tst_res(TFAIL, "free or reserve counts incorrect after fallocate stress test");
> + else
> + tst_res(TPASS, "fallocate stress test passed");
Use TST_EXP_EQ_LU(free_after, free_before) and
TST_EXP_EQ_LU(rsvd_after, rsvd_before) to report free and reserve count
comparisons.
> +static void cleanup(void)
> +{
> + if (fd >= 0)
> + SAFE_CLOSE(fd);
> +}
Use if (fd != -1) instead of if (fd >= 0).
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-11-07 16:45 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-07 6:28 [LTP] [PATCH v10] hugetlb/hugefallocate: Add hugefallocate03 to stress test fallocate on hugetlbfs Pavithra
2026-11-07 10:51 ` [LTP] " linuxtestproject.agent
-- strict thread matches above, loose matches on Subject: below --
2026-11-07 12:05 [LTP] [PATCH v11] " Pavithra
2026-11-07 16:44 ` [LTP] " linuxtestproject.agent
2026-09-23 8:01 [LTP] [PATCH v9] " Pavithra
2026-09-23 10:00 ` [LTP] " linuxtestproject.agent
2026-11-02 15:59 ` Cyril Hrubis
2026-09-20 11:35 [LTP] [PATCH v8] " Pavithra
2026-09-20 14:43 ` [LTP] " linuxtestproject.agent
2026-09-19 17:49 [LTP] [PATCH v7] " Pavithra
2026-09-19 20:14 ` [LTP] " linuxtestproject.agent
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.