* [LTP] [PATCH v5] hugetlb/hugemmap: add hugemmap33 to test hugetlbfs quota accounting
@ 2026-08-31 4:19 Pavithra
2026-08-31 9:12 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 2+ messages in thread
From: Pavithra @ 2026-08-31 4:19 UTC (permalink / raw)
To: ltp; +Cc: pavrampu
Test hugetlbfs quota accounting with filesystem size limits to check
for regressions in quota handling for MAP_PRIVATE and MAP_SHARED pages.
Signed-off-by: Pavithra <pavrampu@linux.ibm.com>
---
v4 -> v5:
- split do_map() into three dedicated functions.
- Remove ACTION_COW, ACTION_TOUCH, QUOTA_OK, QUOTA_FAIL and QUOTA_COW_FAIL macros.
- Fix untouched mapping test to hold the reservation until process exit instead of calling munmap() explicitly.
Link to v4: https://lore.kernel.org/ltp/20260809174900.1847247-1-pavrampu@linux.ibm.com/
---
runtest/hugetlb | 1 +
testcases/kernel/mem/.gitignore | 1 +
.../kernel/mem/hugetlb/hugemmap/hugemmap33.c | 233 ++++++++++++++++++
3 files changed, 235 insertions(+)
create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap33.c
diff --git a/runtest/hugetlb b/runtest/hugetlb
index 621c9718a..e3ee42c2f 100644
--- a/runtest/hugetlb
+++ b/runtest/hugetlb
@@ -35,6 +35,7 @@ hugemmap29 hugemmap29
hugemmap30 hugemmap30
hugemmap31 hugemmap31
hugemmap32 hugemmap32
+hugemmap33 hugemmap33
hugemmap34 hugemmap34
hugemmap35 hugemmap35
hugemmap36 hugemmap36
diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
index 9e706e1c8..763f134dd 100644
--- a/testcases/kernel/mem/.gitignore
+++ b/testcases/kernel/mem/.gitignore
@@ -35,6 +35,7 @@
/hugetlb/hugemmap/hugemmap30
/hugetlb/hugemmap/hugemmap31
/hugetlb/hugemmap/hugemmap32
+/hugetlb/hugemmap/hugemmap33
/hugetlb/hugemmap/hugemmap34
/hugetlb/hugemmap/hugemmap35
/hugetlb/hugemmap/hugemmap36
diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap33.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap33.c
new file mode 100644
index 000000000..403d7eaf6
--- /dev/null
+++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap33.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * Copyright (C) 2005-2007 David Gibson & Adam Litke, IBM Corporation.
+ * Copyright (c) Linux Test Project, 2024
+ * Copyright (C) 2025-2026 Naveed & Pavithra, IBM Corporation.
+ * Assisted with AI tools
+ */
+
+/*\
+ * Test hugetlbfs quota accounting with filesystem size limits.
+ *
+ * The number of global huge pages available to a mounted hugetlbfs filesystem
+ * can be limited using a quota mechanism by setting the size attribute at
+ * mount time. Older kernels did not properly handle quota accounting for
+ * MAP_PRIVATE pages and MAP_SHARED reservations.
+ *
+ * Commit a1e78772d72b introduced MAP_PRIVATE reservations at mmap() time,
+ * so quota is checked upfront and mmap() fails with ENOMEM when over quota.
+ * Before this, quota was only checked at fault time resulting in SIGBUS.
+ *
+ * Root is required to mount the quota-limited hugetlbfs instance.
+ */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/vfs.h>
+#include <sys/statfs.h>
+#include <sys/mount.h>
+
+#include "hugetlb.h"
+
+#define MNTPOINT "hugetlbfs/"
+
+static long hpage_size;
+static int quota_mounted;
+
+static void verify_quota_stat(long tot, long free, long avail)
+{
+ struct statfs s;
+
+ SAFE_STATFS(MNTPOINT, &s);
+
+ if ((long)s.f_blocks != tot || (long)s.f_bfree != free || (long)s.f_bavail != avail) {
+ tst_res(TFAIL, "Bad quota counters: total=%li free=%li avail=%li, expected %li %li %li",
+ (long)s.f_blocks, (long)s.f_bfree, (long)s.f_bavail,
+ tot, free, avail);
+ return;
+ }
+ tst_res(TPASS, "Quota counters are correct: total=%li free=%li avail=%li",
+ tot, free, avail);
+}
+
+static void verify_quota_ok(unsigned long size, int mmap_flags)
+{
+ int fd;
+ char *a, *b;
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof(path), "%s/test_file_%d", MNTPOINT, getpid());
+ fd = SAFE_OPEN(path, O_CREAT | O_RDWR, 0600);
+ SAFE_UNLINK(path);
+
+ TESTPTR(mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, fd, 0));
+ a = TST_RET_PTR;
+ if (a == MAP_FAILED) {
+ tst_res(TFAIL | TERRNO, "mmap failed unexpectedly");
+ SAFE_CLOSE(fd);
+ return;
+ }
+
+ for (b = a; b < a + size; b += hpage_size)
+ *b = 1;
+
+ tst_res(TPASS, "Quota test passed as expected");
+ SAFE_MUNMAP(a, size);
+ SAFE_CLOSE(fd);
+}
+
+static void verify_quota_fail(unsigned long size, int mmap_flags)
+{
+ int fd;
+ char *a;
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof(path), "%s/test_file_%d", MNTPOINT, getpid());
+ fd = SAFE_OPEN(path, O_CREAT | O_RDWR, 0600);
+ SAFE_UNLINK(path);
+
+ TESTPTR(mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, fd, 0));
+ a = TST_RET_PTR;
+ if (a == MAP_FAILED) {
+ if (TST_ERR == ENOMEM) {
+ tst_res(TPASS | TERRNO, "mmap failed as expected due to quota");
+ SAFE_CLOSE(fd);
+ return;
+ }
+ tst_res(TFAIL | TERRNO, "mmap failed unexpectedly");
+ SAFE_CLOSE(fd);
+ return;
+ }
+
+ tst_res(TFAIL, "mmap succeeded but quota exhaustion was expected");
+ SAFE_MUNMAP(a, size);
+ SAFE_CLOSE(fd);
+}
+
+static void verify_quota_cow_fail(unsigned long size, int mmap_flags)
+{
+ int fd;
+ char *a, *b, *c;
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof(path), "%s/test_file_%d", MNTPOINT, getpid());
+ fd = SAFE_OPEN(path, O_CREAT | O_RDWR, 0600);
+ SAFE_UNLINK(path);
+
+ TESTPTR(mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, fd, 0));
+ a = TST_RET_PTR;
+ if (a == MAP_FAILED) {
+ tst_res(TFAIL | TERRNO, "mmap failed unexpectedly");
+ SAFE_CLOSE(fd);
+ return;
+ }
+
+ for (b = a; b < a + size; b += hpage_size)
+ *b = 1;
+
+ TESTPTR(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0));
+ c = TST_RET_PTR;
+ if (c == MAP_FAILED) {
+ if (TST_ERR == ENOMEM) {
+ tst_res(TPASS | TERRNO, "COW mmap failed as expected due to quota");
+ SAFE_MUNMAP(a, size);
+ SAFE_CLOSE(fd);
+ return;
+ }
+ tst_res(TFAIL | TERRNO, "COW mmap failed unexpectedly");
+ SAFE_MUNMAP(a, size);
+ SAFE_CLOSE(fd);
+ return;
+ }
+
+ tst_res(TFAIL, "COW mmap succeeded but quota exhaustion was expected");
+ SAFE_MUNMAP(c, size);
+ SAFE_MUNMAP(a, size);
+ SAFE_CLOSE(fd);
+}
+
+static void run_quota_test(void (*fn)(unsigned long, int),
+ unsigned long size, int mmap_flags)
+{
+ pid_t pid;
+ int status;
+
+ pid = SAFE_FORK();
+ if (pid == 0) {
+ fn(size, mmap_flags);
+ exit(0);
+ }
+
+ SAFE_WAITPID(pid, &status, 0);
+
+ if (WIFSIGNALED(status))
+ tst_res(TFAIL, "Child killed by unexpected signal %d", WTERMSIG(status));
+}
+
+static void run_test(void)
+{
+ tst_res(TINFO, "Testing unused quota cleanup for untouched mappings");
+ run_quota_test(verify_quota_ok, hpage_size, MAP_PRIVATE);
+ verify_quota_stat(1, 1, 1);
+ run_quota_test(verify_quota_ok, hpage_size, MAP_SHARED);
+ verify_quota_stat(1, 1, 1);
+
+ tst_res(TINFO, "Testing page instantiation within quota limits");
+ run_quota_test(verify_quota_ok, hpage_size, MAP_PRIVATE);
+ run_quota_test(verify_quota_ok, hpage_size, MAP_SHARED);
+
+ tst_res(TINFO, "Testing page instantiation over quota");
+ run_quota_test(verify_quota_fail, 2 * hpage_size, MAP_SHARED);
+
+ tst_res(TINFO, "Testing private mapping quota check");
+ run_quota_test(verify_quota_fail, 2 * hpage_size, MAP_PRIVATE);
+
+ tst_res(TINFO, "Testing COW over quota");
+ run_quota_test(verify_quota_cow_fail, hpage_size, MAP_SHARED);
+ run_quota_test(verify_quota_cow_fail, hpage_size, MAP_PRIVATE);
+
+ tst_res(TINFO, "Testing operations within quota after failures");
+ run_quota_test(verify_quota_ok, hpage_size, MAP_SHARED);
+ run_quota_test(verify_quota_ok, hpage_size, MAP_PRIVATE);
+}
+
+static void setup(void)
+{
+ char mount_opts[BUFSIZ];
+
+ hpage_size = tst_get_hugepage_size();
+
+ snprintf(mount_opts, sizeof(mount_opts), "size=%luK",
+ hpage_size / 1024);
+
+ if (mount("none", MNTPOINT, "hugetlbfs", 0, mount_opts) == -1) {
+ if (errno == ENODEV)
+ tst_brk(TCONF, "hugetlbfs not supported");
+ tst_brk(TBROK | TERRNO, "mount() failed");
+ }
+ quota_mounted = 1;
+
+ tst_res(TINFO, "Mounted hugetlbfs with quota at %s (size=%luK)",
+ MNTPOINT, hpage_size / 1024);
+}
+
+static void cleanup(void)
+{
+ if (quota_mounted)
+ SAFE_UMOUNT(MNTPOINT);
+}
+
+static struct tst_test test = {
+ .tags = (struct tst_tag[]) {
+ {"linux-git", "a1e78772d72b"},
+ {}
+ },
+ .needs_root = 1,
+ .mntpoint = MNTPOINT,
+ .forks_child = 1,
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = run_test,
+ .hugepages = {2, TST_NEEDS},
+};
--
2.55.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [LTP] hugetlb/hugemmap: add hugemmap33 to test hugetlbfs quota accounting
2026-08-31 4:19 [LTP] [PATCH v5] hugetlb/hugemmap: add hugemmap33 to test hugetlbfs quota accounting Pavithra
@ 2026-08-31 9:12 ` linuxtestproject.agent
0 siblings, 0 replies; 2+ messages in thread
From: linuxtestproject.agent @ 2026-08-31 9:12 UTC (permalink / raw)
To: Pavithra; +Cc: ltp
Hi Pavithra,
On Aug 31, 2026, Pavithra wrote:
> hugetlb/hugemmap: add hugemmap33 to test hugetlbfs quota accounting
> for (b = a; b < a + size; b += hpage_size)
> *b = 1;
>
> tst_res(TINFO, "Testing unused quota cleanup for untouched mappings");
> run_quota_test(verify_quota_ok, hpage_size, MAP_PRIVATE);
> verify_quota_stat(1, 1, 1);
verify_quota_ok() faults and instantiates every page, so this does not test
cleanup of an untouched mapping. Use a map/unmap helper that does not access
the mapping before checking the quota counters.
> TESTPTR(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0));
> c = TST_RET_PTR;
> if (c == MAP_FAILED) {
> if (TST_ERR == ENOMEM) {
> tst_res(TPASS | TERRNO, "COW mmap failed as expected due to quota");
No copy-on-write fault occurs because the second mapping is never accessed.
This retests private mmap reservation accounting; exercise a private write
that requires COW, or remove the COW claim.
> static void run_test(void)
> {
> tst_res(TINFO, "Testing unused quota cleanup for untouched mappings");
> run_quota_test(verify_quota_ok, hpage_size, MAP_PRIVATE);
> ...
> run_quota_test(verify_quota_ok, hpage_size, MAP_PRIVATE);
> }
>
> static struct tst_test test = {
> ...
> .test_all = run_test,
These multiple cases are manually dispatched through .test_all. Represent
them with a tcase array and use .test with .tcnt.
> +/hugetlb/hugemmap/hugemmap33
Test binaries must be ignored by a .gitignore in their own directory. Move
this entry to testcases/kernel/mem/hugetlb/hugemmap/.gitignore.
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] 2+ messages in thread
end of thread, other threads:[~2026-08-31 9:13 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-31 4:19 [LTP] [PATCH v5] hugetlb/hugemmap: add hugemmap33 to test hugetlbfs quota accounting Pavithra
2026-08-31 9:12 ` [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.