From: Pavithra <pavrampu@linux.ibm.com>
To: ltp@lists.linux.it
Cc: pavrampu@linux.ibm.com
Subject: [LTP] [PATCH] Migrating the libhugetlbfs/testcases/quota.c - v2
Date: Sat, 4 Apr 2026 17:41:20 +0530 [thread overview]
Message-ID: <20260404121120.1611032-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>
---
runtest/hugetlb | 1 +
testcases/kernel/mem/.gitignore | 1 +
.../kernel/mem/hugetlb/hugemmap/hugemmap33.c | 273 ++++++++++++++++++
3 files changed, 275 insertions(+)
create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap33.c
diff --git a/runtest/hugetlb b/runtest/hugetlb
index 0896d3c94..24fa717ec 100644
--- a/runtest/hugetlb
+++ b/runtest/hugetlb
@@ -35,6 +35,7 @@ hugemmap29 hugemmap29
hugemmap30 hugemmap30
hugemmap31 hugemmap31
hugemmap32 hugemmap32
+hugemmap33 hugemmap33
hugemmap34 hugemmap34
hugemmap05_1 hugemmap05 -m
hugemmap05_2 hugemmap05 -s
diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
index b4455de51..7f1bcd4e7 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/hugeshmat/hugeshmat01
/hugetlb/hugeshmat/hugeshmat02
diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap33.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap33.c
new file mode 100644
index 000000000..75ecf5796
--- /dev/null
+++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap33.c
@@ -0,0 +1,273 @@
+// 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 in a
+ * number of cases (e.g., for MAP_PRIVATE pages, and with MAP_SHARED reservation).
+ *
+ * This test replays some scenarios on a privately mounted filesystem with
+ * quota to check for regressions in hugetlbfs quota accounting.
+ */
+
+#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 private_resv;
+static char quota_mnt[PATH_MAX];
+static int quota_mounted;
+
+/* map action flags */
+#define ACTION_COW 0x0001
+#define ACTION_TOUCH 0x0002
+
+/* Test result expectations */
+#define EXPECT_SUCCESS 0
+#define EXPECT_SIGNAL 1
+#define EXPECT_FAILURE 2
+
+static void verify_quota_stat(long tot, long free, long avail)
+{
+ struct statfs s;
+
+ SAFE_STATFS(quota_mnt, &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 (expected %li), "
+ "free=%li (expected %li), avail=%li (expected %li)",
+ (long)s.f_blocks, tot, (long)s.f_bfree, free,
+ (long)s.f_bavail, avail);
+ }
+}
+
+static void do_map(unsigned long size, int mmap_flags, int action_flags)
+{
+ int fd;
+ char *a = MAP_FAILED, *b, *c = MAP_FAILED;
+ char path[PATH_MAX + 32];
+
+ snprintf(path, sizeof(path), "%s/test_file_%d", quota_mnt, getpid());
+ fd = SAFE_OPEN(path, O_CREAT | O_RDWR, 0600);
+ SAFE_UNLINK(path);
+
+ a = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, fd, 0);
+ if (a == MAP_FAILED) {
+ if (errno == ENOMEM || errno == ENOSPC) {
+ tst_res(TINFO | TERRNO, "mmap failed as expected due to quota");
+ goto cleanup_fd;
+ }
+ tst_brk(TBROK | TERRNO, "mmap failed unexpectedly");
+ }
+
+ if (action_flags & ACTION_TOUCH) {
+ for (b = a; b < a + size; b += hpage_size)
+ *b = 1;
+ }
+
+ if (action_flags & ACTION_COW) {
+ c = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (c == MAP_FAILED) {
+ if (errno == ENOMEM || errno == ENOSPC) {
+ tst_res(TINFO | TERRNO, "COW mapping failed as expected due to quota");
+ goto cleanup_a;
+ }
+ tst_brk(TBROK | TERRNO, "COW mapping failed unexpectedly");
+ }
+
+ if (*c != 1) {
+ tst_res(TINFO, "Data mismatch when setting up COW");
+ goto cleanup_c;
+ }
+ *c = 0;
+ SAFE_MUNMAP(c, size);
+ }
+
+ SAFE_MUNMAP(a, size);
+ SAFE_CLOSE(fd);
+ return;
+
+cleanup_c:
+ SAFE_MUNMAP(c, size);
+cleanup_a:
+ SAFE_MUNMAP(a, size);
+cleanup_fd:
+ SAFE_CLOSE(fd);
+ exit(1);
+}
+
+static void run_quota_test(int expected_result,
+ unsigned long size, int mmap_flags,
+ int action_flags)
+{
+ pid_t pid;
+ int status;
+ int actual_result;
+
+ pid = SAFE_FORK();
+ if (pid == 0) {
+ do_map(size, mmap_flags, action_flags);
+ exit(0);
+ }
+
+ SAFE_WAITPID(pid, &status, 0);
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 0)
+ actual_result = EXPECT_SUCCESS;
+ else
+ actual_result = EXPECT_FAILURE;
+ } else {
+ actual_result = EXPECT_SIGNAL;
+ }
+
+ if (actual_result != expected_result) {
+ static const char * const result_names[] = {"success", "signal", "failure"};
+
+ tst_res(TFAIL,
+ "Unexpected result: expected %s, got %s",
+ result_names[expected_result],
+ result_names[actual_result]);
+ } else {
+ tst_res(TPASS, "Quota test passed as expected");
+ }
+}
+
+static int kernel_has_private_reservations(void)
+{
+ int fd;
+ long t, f, r, s;
+ long nt, nf, nr, ns;
+ void *p;
+ char path[PATH_MAX];
+
+ t = SAFE_READ_MEMINFO(MEMINFO_HPAGE_TOTAL);
+ f = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ r = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
+ s = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SURP);
+
+ snprintf(path, sizeof(path), "%s/test_priv_resv", MNTPOINT);
+ fd = SAFE_OPEN(path, O_CREAT | O_RDWR, 0600);
+ SAFE_UNLINK(path);
+
+ p = SAFE_MMAP(NULL, hpage_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, fd, 0);
+
+ nt = SAFE_READ_MEMINFO(MEMINFO_HPAGE_TOTAL);
+ nf = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE);
+ nr = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD);
+ ns = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SURP);
+
+ SAFE_MUNMAP(p, hpage_size);
+ SAFE_CLOSE(fd);
+
+ /* Check if reservation was created for private mapping */
+ if ((nt == t + 1) && (nf == f + 1) && (ns == s + 1) && (nr == r + 1))
+ return 1;
+ else if ((nt == t) && (nf == f) && (ns == s)) {
+ if (nr == r + 1)
+ return 1;
+ else if (nr == r)
+ return 0;
+ }
+
+ tst_brk(TCONF, "Unexpected counter state - "
+ "T:%li F:%li R:%li S:%li -> T:%li F:%li R:%li S:%li",
+ t, f, r, s, nt, nf, nr, ns);
+ return -1;
+}
+
+static void run_test(void)
+{
+ int bad_priv_resv = private_resv ? EXPECT_FAILURE : EXPECT_SIGNAL;
+
+ tst_res(TINFO, "Testing unused quota cleanup for untouched mappings");
+ run_quota_test(EXPECT_SUCCESS, hpage_size, MAP_PRIVATE, 0);
+ verify_quota_stat(1, 1, 1);
+ run_quota_test(EXPECT_SUCCESS, hpage_size, MAP_SHARED, 0);
+ verify_quota_stat(1, 1, 1);
+
+ tst_res(TINFO, "Testing page instantiation within quota limits");
+ run_quota_test(EXPECT_SUCCESS, hpage_size, MAP_PRIVATE, ACTION_TOUCH);
+ run_quota_test(EXPECT_SUCCESS, hpage_size, MAP_SHARED, ACTION_TOUCH);
+
+ tst_res(TINFO, "Testing page instantiation over quota");
+ run_quota_test(EXPECT_FAILURE, 2 * hpage_size, MAP_SHARED, ACTION_TOUCH);
+
+ tst_res(TINFO, "Testing private mapping quota check");
+ run_quota_test(bad_priv_resv, 2 * hpage_size, MAP_PRIVATE, ACTION_TOUCH);
+
+ tst_res(TINFO, "Testing COW over quota");
+ run_quota_test(bad_priv_resv, hpage_size, MAP_SHARED,
+ ACTION_TOUCH | ACTION_COW);
+ run_quota_test(bad_priv_resv, hpage_size, MAP_PRIVATE,
+ ACTION_TOUCH | ACTION_COW);
+
+ tst_res(TINFO, "Testing operations within quota after failures");
+ run_quota_test(EXPECT_SUCCESS, hpage_size, MAP_SHARED, ACTION_TOUCH);
+ run_quota_test(EXPECT_SUCCESS, hpage_size, MAP_PRIVATE, ACTION_TOUCH);
+}
+
+static void setup(void)
+{
+ char mount_opts[BUFSIZ];
+
+ hpage_size = tst_get_hugepage_size();
+
+ /* Create a quota-limited hugetlbfs mount */
+ snprintf(quota_mnt, sizeof(quota_mnt), "%s/quota_test", MNTPOINT);
+ SAFE_MKDIR(quota_mnt, 0755);
+
+ snprintf(mount_opts, sizeof(mount_opts), "size=%luK",
+ hpage_size / 1024);
+
+ if (mount("none", quota_mnt, "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)",
+ quota_mnt, hpage_size / 1024);
+
+ private_resv = kernel_has_private_reservations();
+ tst_res(TINFO, "Kernel %s private reservations",
+ private_resv ? "has" : "does not have");
+}
+
+static void cleanup(void)
+{
+ if (quota_mounted) {
+ SAFE_UMOUNT(quota_mnt);
+ SAFE_RMDIR(quota_mnt);
+ }
+}
+
+static struct tst_test test = {
+ .needs_root = 1,
+ .mntpoint = MNTPOINT,
+ .needs_hugetlbfs = 1,
+ .forks_child = 1,
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = run_test,
+ .hugepages = {2, TST_NEEDS},
+};
--
2.53.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
next reply other threads:[~2026-04-04 12:11 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-04 12:11 Pavithra [this message]
2026-07-02 12:44 ` [LTP] Migrating the libhugetlbfs/testcases/quota.c - v2 linuxtestproject.agent
2026-07-02 12:50 ` [LTP] [PATCH] " Andrea Cervesato via ltp
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=20260404121120.1611032-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.