All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH v4] hugetlb/hugeshmat: Add hugeshmat06 migrated from libhugetlbfs shm-perms
@ 2026-08-20  4:25 Samir Mulani
  2026-08-20 10:33 ` [LTP] " linuxtestproject.agent
  0 siblings, 1 reply; 4+ messages in thread
From: Samir Mulani @ 2026-08-20  4:25 UTC (permalink / raw)
  To: ltp; +Cc: liwang, Samir Mulani

Test shared memory behavior when multiple processes attach to a
hugepage-backed segment with different permissions.

At one point, reservation accounting of free hugepages between the
parent and child processes may become inconsistent during memory
operations. The parent creates a shared memory segment backed by
4 hugepages (permission 0640), attaches it read-write, initialises
each hugepage with a pattern (0x55), then detaches. Child processes
are forked in a loop, each reattaching the segment read-only via
SHM_RDONLY, verifying the data pattern, detaching, and exiting.

Per-process HugetlbPages: from /proc/<pid>/status is checked before
and after each child's attach/detach cycle. A non-zero value after
detach indicates a reservation accounting leak. Using a per-process
counter instead of the system-wide HugePages_Free: from /proc/meminfo
avoids false failures from concurrent hugepage users on the system.

Signed-off-by: Samir Mulani <samir@linux.ibm.com>
---
Changes in v4:
 1. Replace HugePages_Free: (system-wide /proc/meminfo) with
    HugetlbPages: (per-process /proc/<pid>/status) for reservation
    accounting check to avoid false failures when other processes
    use hugepages concurrently. [Cyril Hrubis]
 2. Use tst_hugepages directly instead of re-reading
    MEMINFO_HPAGE_TOTAL since the LTP framework already stores
    the reserved count. [Li Wang]
 3. Cap iteration count with MIN(tst_hugepages, MAX_CHILDREN)
    instead of computing it from total hugepages * hpage_size
    to avoid spawning excessive children on large-memory machines.
    [Li Wang]
 4. Reduce .hugepages request from 32 to HPAGES_IN_SEG (4) since
    only 4 hugepages are ever needed. [Li Wang]
 5. Move all child-local variables into the child process block to
    fix variable aliasing between the outer fork loop index and the
    inner hugepage read loop index. [Li Wang]
 6. Add data coherence check: each child verifies every hugepage
    contains the expected 0x55 pattern written by the parent,
    since children attach with SHM_RDONLY. [Li Wang]
 7. Move segment creation and pattern initialisation into setup()
    to keep run_test() focused on attach/verify/detach/accounting.
 8. Add TINFO message per child reporting successful attach.
    [Li Wang]
 9. Fix checkpatch.pl quoted string split across lines warnings.

Link:
https://lore.kernel.org/ltp/49b1dbd9-4c51-414a-806c-1d5cc6b5e1c7@linux.ibm.com/ # v3 

 runtest/hugetlb                               |   1 +
 testcases/kernel/mem/.gitignore               |   1 +
 .../mem/hugetlb/hugeshmat/hugeshmat06.c       | 187 ++++++++++++++++++
 3 files changed, 189 insertions(+)
 create mode 100644 testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat06.c

diff --git a/runtest/hugetlb b/runtest/hugetlb
index 6b35c1f42..1eb5c3339 100644
--- a/runtest/hugetlb
+++ b/runtest/hugetlb
@@ -49,6 +49,7 @@ hugeshmat02 hugeshmat02 -i 5
 hugeshmat03 hugeshmat03 -i 5
 hugeshmat04 hugeshmat04 -i 5
 hugeshmat05 hugeshmat05 -i 5
+hugeshmat06 hugeshmat06 -i 5
 
 hugeshmctl01 hugeshmctl01 -i 5
 hugeshmctl02 hugeshmctl02 -i 5
diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
index e63a6dde7..704f89d5e 100644
--- a/testcases/kernel/mem/.gitignore
+++ b/testcases/kernel/mem/.gitignore
@@ -45,6 +45,7 @@
 /hugetlb/hugeshmat/hugeshmat03
 /hugetlb/hugeshmat/hugeshmat04
 /hugetlb/hugeshmat/hugeshmat05
+/hugetlb/hugeshmat/hugeshmat06
 /hugetlb/hugeshmctl/hugeshmctl01
 /hugetlb/hugeshmctl/hugeshmctl02
 /hugetlb/hugeshmctl/hugeshmctl03
diff --git a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat06.c b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat06.c
new file mode 100644
index 000000000..b8c40cea0
--- /dev/null
+++ b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat06.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2005-2006 IBM Corporation.
+ * Author: David Gibson & Adam Litke
+ */
+
+/*\
+ * [Description]
+ *
+ * Tests shared memory behavior when multiple processes attach to a
+ * hugepage-backed segment with different permissions.
+ *
+ * The parent creates a shared memory segment (permission 0640) backed by
+ * hugepages, attaches it read-write, initialises each hugepage with a
+ * pattern (0x55), then detaches.  A number of child processes are then
+ * forked; each child reattaches the segment read-only (SHM_RDONLY),
+ * verifies the expected pattern in every hugepage, detaches, and exits.
+ *
+ * The test validates two things:
+ *  1. Per-process HugetlbPages accounting (from /proc/self/status) must
+ *     return to zero after the child detaches — catching reservation-
+ *     accounting leaks described in the original libhugetlbfs shm-perms
+ *     test.
+ *  2. Read-only children can successfully read the data written by the
+ *     parent (data coherence check).
+ *
+ * Using per-process /proc/self/status HugetlbPages: rather than the
+ * system-wide HugePages_Free: counter avoids false failures caused by
+ * concurrent users of hugepages on the system.
+ */
+
+#include "hugetlb.h"
+#include "tst_safe_sysv_ipc.h"
+
+#define SEGMENT_KEY	(0x82ba15ff)
+#define MNTPOINT	"hugetlbfs/"
+#define HPAGES_IN_SEG	4
+#define PATTERN		0x55
+#define MAX_CHILDREN	128
+
+static int global_shmid = -1;
+static long hpage_size;
+static long segment_size;
+
+/*
+ * get_proc_hugetlb_kb - return HugetlbPages value (in kB) for a given pid
+ * as reported by /proc/<pid>/status.
+ */
+static long get_proc_hugetlb_kb(pid_t pid)
+{
+	return SAFE_READ_PROC_STATUS(pid, "HugetlbPages:");
+}
+
+static void setup(void)
+{
+	int shmid;
+	char *p;
+	int i;
+
+	hpage_size = tst_get_hugepage_size();
+	if (!hpage_size)
+		tst_brk(TCONF, "Hugepages are not supported");
+
+	segment_size = HPAGES_IN_SEG * hpage_size;
+
+	/* Create the hugepage SHM segment with 0640 permissions */
+	shmid = SAFE_SHMGET(SEGMENT_KEY, segment_size,
+			    IPC_CREAT | SHM_HUGETLB | 0640);
+	global_shmid = shmid;
+
+	/* Attach read-write, write a known pattern into each hugepage */
+	p = SAFE_SHMAT(shmid, NULL, 0);
+
+	for (i = 0; i < HPAGES_IN_SEG; i++)
+		memset(p + (i * hpage_size), PATTERN, hpage_size);
+
+	SAFE_SHMDT((const void *)p);
+}
+
+static void cleanup(void)
+{
+	if (global_shmid >= 0)
+		SAFE_SHMCTL(global_shmid, IPC_RMID, NULL);
+}
+
+static void run_test(void)
+{
+	int i, iterations;
+	pid_t pid;
+
+	/*
+	 * Number of attach/detach cycles to exercise reservation accounting.
+	 * Use tst_hugepages (reserved by the framework) but cap at
+	 * MAX_CHILDREN to avoid spawning an unreasonable number of children
+	 * on large-memory machines.
+	 */
+	iterations = MIN((long)tst_hugepages, (long)MAX_CHILDREN);
+
+	tst_res(TINFO, "Running %d child attach/detach iterations", iterations);
+
+	for (i = 0; i < iterations; i++) {
+		pid = SAFE_FORK();
+		if (pid == 0) {
+			/* ---- child ---- */
+			char *shmaddr;
+			long hugetlb_before, hugetlb_after;
+			int j;
+
+			/*
+			 * HugetlbPages should be 0 before we attach
+			 * (no hugepages mapped in this fresh child).
+			 */
+			hugetlb_before = get_proc_hugetlb_kb(getpid());
+			if (hugetlb_before != 0) {
+				tst_res(TWARN,
+					"Child %d: HugetlbPages before attach is %ld kB (expected 0)",
+					getpid(), hugetlb_before);
+			}
+
+			/* Re-open existing segment (size 0 = use existing) */
+			shmaddr = SAFE_SHMAT(global_shmid, NULL, SHM_RDONLY);
+
+			tst_res(TINFO, "Child %d attached segment successfully",
+				getpid());
+
+			/* Verify the pattern written by the parent */
+			for (j = 0; j < HPAGES_IN_SEG; j++) {
+				unsigned char val =
+					*((unsigned char *)shmaddr +
+					  (j * hpage_size));
+
+				if (val != PATTERN) {
+					tst_res(TFAIL,
+						"Child %d: hugepage[%d] data mismatch: got 0x%02x, expected 0x%02x",
+						getpid(), j, (unsigned int)val, PATTERN);
+					SAFE_SHMDT((const void *)shmaddr);
+					exit(EXIT_FAILURE);
+				}
+			}
+
+			SAFE_SHMDT((const void *)shmaddr);
+
+			/*
+			 * After detaching, HugetlbPages must drop back to 0.
+			 * A non-zero value indicates a reservation accounting
+			 * leak.
+			 */
+			hugetlb_after = get_proc_hugetlb_kb(getpid());
+			if (hugetlb_after != 0) {
+				tst_res(TFAIL,
+					"Child %d: HugetlbPages after detach is %ld kB (expected 0), reservation accounting leak",
+					getpid(), hugetlb_after);
+				exit(EXIT_FAILURE);
+			}
+
+			exit(EXIT_SUCCESS);
+		}
+	}
+
+	/*
+	 * Wait for all children.  tst_reap_children() calls tst_brk(TBROK)
+	 * if any child exited non-zero, so a TFAIL inside a child is
+	 * automatically promoted to a test-level failure here.
+	 */
+	tst_reap_children();
+
+	tst_res(TPASS,
+		"All %d children attached read-only and verified reservation accounting",
+		iterations);
+}
+
+static struct tst_test test = {
+	.needs_root	 = 1,
+	.mntpoint	 = MNTPOINT,
+	.needs_hugetlbfs = 1,
+	.needs_tmpdir	 = 1,
+	.forks_child	 = 1,
+	.setup		 = setup,
+	.cleanup	 = cleanup,
+	.test_all	 = run_test,
+	/*
+	 * Request HPAGES_IN_SEG hugepages; that is all the test needs.
+	 * TST_NEEDS means the test is skipped if the kernel cannot
+	 * provide them.
+	 */
+	.hugepages	 = {HPAGES_IN_SEG, TST_NEEDS},
+};
-- 
2.52.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 4+ messages in thread
* [LTP] [PATCH v5] hugetlb/hugeshmat: Add hugeshmat06 migrated from libhugetlbfs shm-perms
@ 2026-08-20 12:55 Samir Mulani
  2026-08-20 18:40 ` [LTP] " linuxtestproject.agent
  0 siblings, 1 reply; 4+ messages in thread
From: Samir Mulani @ 2026-08-20 12:55 UTC (permalink / raw)
  To: ltp; +Cc: liwang, Samir Mulani

Test shared memory behavior when multiple processes attach to a
hugepage-backed segment with different permissions.

At one point, reservation accounting of free hugepages between the
parent and child processes may become inconsistent during memory
operations. The parent creates a shared memory segment backed by
4 hugepages (permission 0640), attaches it read-write, initialises
each hugepage with a pattern (0x55), then detaches. Child processes
are forked in a loop, each reattaching the segment read-only via
SHM_RDONLY, verifying the data pattern, detaching, and exiting.

If the reservation accounting leaks, repeated read-only attaches
will exhaust the hugepage pool and shmat() will fail. The test
uses raw shmat() in each child and reports this failure as TFAIL.

Signed-off-by: Samir Mulani <samir@linux.ibm.com>
---
Changes in v5:
 1. Use raw shmat() instead of SAFE_SHMAT() and report pool
    exhaustion as TFAIL. HugetlbPages from /proc/<pid>/status
    only tracks mapped pages and can return zero after shmdt()
    even when resv_huge_pages is still leaked, so it is not a
    reliable oracle for this regression. [LTP AI Reviewer]
 2. Remove get_proc_hugetlb_kb() helper and the HugetlbPages
    check as they are no longer needed. [LTP AI Reviewer]
 3. Use IPC_PRIVATE instead of a fixed SEGMENT_KEY to avoid
    accidentally reusing or destroying a pre-existing segment.
    [LTP AI Reviewer]
 4. Drop the deprecated [Description] tag from the /*\ block.
    [LTP AI Reviewer]

Link: https://lore.kernel.org/ltp/49b1dbd9-4c51-414a-806c-1d5cc6b5e1c7@linux.ibm.com/ # v3 
Link: https://lore.kernel.org/ltp/20260820042516.46631-1-samir@linux.ibm.com/ # v4

 runtest/hugetlb                               |   1 +
 testcases/kernel/mem/.gitignore               |   1 +
 .../mem/hugetlb/hugeshmat/hugeshmat06.c       | 152 ++++++++++++++++++
 3 files changed, 154 insertions(+)
 create mode 100644 testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat06.c

diff --git a/runtest/hugetlb b/runtest/hugetlb
index 6b35c1f42..1eb5c3339 100644
--- a/runtest/hugetlb
+++ b/runtest/hugetlb
@@ -49,6 +49,7 @@ hugeshmat02 hugeshmat02 -i 5
 hugeshmat03 hugeshmat03 -i 5
 hugeshmat04 hugeshmat04 -i 5
 hugeshmat05 hugeshmat05 -i 5
+hugeshmat06 hugeshmat06 -i 5
 
 hugeshmctl01 hugeshmctl01 -i 5
 hugeshmctl02 hugeshmctl02 -i 5
diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore
index e63a6dde7..704f89d5e 100644
--- a/testcases/kernel/mem/.gitignore
+++ b/testcases/kernel/mem/.gitignore
@@ -45,6 +45,7 @@
 /hugetlb/hugeshmat/hugeshmat03
 /hugetlb/hugeshmat/hugeshmat04
 /hugetlb/hugeshmat/hugeshmat05
+/hugetlb/hugeshmat/hugeshmat06
 /hugetlb/hugeshmctl/hugeshmctl01
 /hugetlb/hugeshmctl/hugeshmctl02
 /hugetlb/hugeshmctl/hugeshmctl03
diff --git a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat06.c b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat06.c
new file mode 100644
index 000000000..440d85672
--- /dev/null
+++ b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat06.c
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2005-2006 IBM Corporation.
+ * Author: David Gibson & Adam Litke
+ */
+
+/*\
+ * Tests shared memory behavior when multiple processes attach to a
+ * hugepage-backed segment with different permissions.
+ *
+ * The parent creates a shared memory segment (permission 0640) backed by
+ * hugepages, attaches it read-write, initialises each hugepage with a
+ * pattern (0x55), then detaches.  A number of child processes are then
+ * forked; each child reattaches the segment read-only (SHM_RDONLY),
+ * verifies the expected pattern in every hugepage, detaches, and exits.
+ *
+ * The original libhugetlbfs shm-perms regression leaked resv_huge_pages
+ * on each read-only attach, eventually exhausting the hugepage reservation
+ * pool.  This is detected by using raw shmat() in each child so that a
+ * pool-exhaustion failure is reported as TFAIL rather than TBROK.
+ */
+
+#include "hugetlb.h"
+#include "tst_safe_sysv_ipc.h"
+
+#define MNTPOINT	"hugetlbfs/"
+#define HPAGES_IN_SEG	4
+#define PATTERN		0x55
+#define MAX_CHILDREN	128
+
+static int global_shmid = -1;
+static long hpage_size;
+static long segment_size;
+
+static void setup(void)
+{
+	int shmid;
+	char *p;
+	int i;
+
+	hpage_size = tst_get_hugepage_size();
+	if (!hpage_size)
+		tst_brk(TCONF, "Hugepages are not supported");
+
+	segment_size = HPAGES_IN_SEG * hpage_size;
+
+	/* Create the hugepage SHM segment with 0640 permissions */
+	shmid = SAFE_SHMGET(IPC_PRIVATE, segment_size,
+			    IPC_CREAT | SHM_HUGETLB | 0640);
+	global_shmid = shmid;
+
+	/* Attach read-write, write a known pattern into each hugepage */
+	p = SAFE_SHMAT(shmid, NULL, 0);
+
+	for (i = 0; i < HPAGES_IN_SEG; i++)
+		memset(p + (i * hpage_size), PATTERN, hpage_size);
+
+	SAFE_SHMDT((const void *)p);
+}
+
+static void cleanup(void)
+{
+	if (global_shmid >= 0)
+		SAFE_SHMCTL(global_shmid, IPC_RMID, NULL);
+}
+
+static void run_test(void)
+{
+	int i, iterations;
+	pid_t pid;
+
+	/*
+	 * Number of attach/detach cycles to exercise reservation accounting.
+	 * Use tst_hugepages (reserved by the framework) but cap at
+	 * MAX_CHILDREN to avoid spawning an unreasonable number of children
+	 * on large-memory machines.
+	 */
+	iterations = MIN((long)tst_hugepages, (long)MAX_CHILDREN);
+
+	tst_res(TINFO, "Running %d child attach/detach iterations", iterations);
+
+	for (i = 0; i < iterations; i++) {
+		pid = SAFE_FORK();
+		if (pid == 0) {
+			/* ---- child ---- */
+			char *shmaddr;
+			int j;
+
+			/*
+			 * Use raw shmat() instead of SAFE_SHMAT() so that a
+			 * failure caused by resv_huge_pages exhaustion is
+			 * reported as TFAIL, not TBROK.
+			 */
+			shmaddr = shmat(global_shmid, NULL, SHM_RDONLY);
+			if (shmaddr == (void *)-1) {
+				tst_res(TFAIL | TERRNO,
+					"Child %d: shmat() failed, hugepage reservation pool may be exhausted",
+					getpid());
+				exit(EXIT_FAILURE);
+			}
+
+			tst_res(TINFO, "Child %d attached segment successfully",
+				getpid());
+
+			/* Verify the pattern written by the parent */
+			for (j = 0; j < HPAGES_IN_SEG; j++) {
+				unsigned char val =
+					*((unsigned char *)shmaddr +
+					  (j * hpage_size));
+
+				if (val != PATTERN) {
+					tst_res(TFAIL,
+						"Child %d: hugepage[%d] data mismatch: got 0x%02x, expected 0x%02x",
+						getpid(), j, (unsigned int)val, PATTERN);
+					SAFE_SHMDT((const void *)shmaddr);
+					exit(EXIT_FAILURE);
+				}
+			}
+
+			SAFE_SHMDT((const void *)shmaddr);
+			exit(EXIT_SUCCESS);
+		}
+	}
+
+	/*
+	 * Wait for all children.  tst_reap_children() calls tst_brk(TBROK)
+	 * if any child exited non-zero, so a TFAIL inside a child is
+	 * automatically promoted to a test-level failure here.
+	 */
+	tst_reap_children();
+
+	tst_res(TPASS,
+		"All %d children attached read-only and verified reservation accounting",
+		iterations);
+}
+
+static struct tst_test test = {
+	.needs_root	 = 1,
+	.mntpoint	 = MNTPOINT,
+	.needs_hugetlbfs = 1,
+	.needs_tmpdir	 = 1,
+	.forks_child	 = 1,
+	.setup		 = setup,
+	.cleanup	 = cleanup,
+	.test_all	 = run_test,
+	/*
+	 * Request HPAGES_IN_SEG hugepages; that is all the test needs.
+	 * TST_NEEDS means the test is skipped if the kernel cannot
+	 * provide them.
+	 */
+	.hugepages	 = {HPAGES_IN_SEG, TST_NEEDS},
+};
-- 
2.52.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-08-20 18:40 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-20  4:25 [LTP] [PATCH v4] hugetlb/hugeshmat: Add hugeshmat06 migrated from libhugetlbfs shm-perms Samir Mulani
2026-08-20 10:33 ` [LTP] " linuxtestproject.agent
2026-08-20 16:49   ` Samir M
  -- strict thread matches above, loose matches on Subject: below --
2026-08-20 12:55 [LTP] [PATCH v5] " Samir Mulani
2026-08-20 18:40 ` [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.