From: Pavithra <pavrampu@linux.ibm.com>
To: ltp@lists.linux.it
Cc: pavrampu@linux.ibm.com
Subject: [LTP] [PATCH v5] hugetlb/hugemmap: add hugemmap33 to test hugetlbfs quota accounting
Date: Mon, 31 Aug 2026 09:49:09 +0530 [thread overview]
Message-ID: <20260831041909.312922-1-pavrampu@linux.ibm.com> (raw)
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
next reply other threads:[~2026-08-31 4:19 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-31 4:19 Pavithra [this message]
2026-08-31 9:12 ` [LTP] hugetlb/hugemmap: add hugemmap33 to test hugetlbfs quota accounting linuxtestproject.agent
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=20260831041909.312922-1-pavrampu@linux.ibm.com \
--to=pavrampu@linux.ibm.com \
--cc=ltp@lists.linux.it \
/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 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.