[LTP] [PATCH 5/5] mremap05: Convert to new API
Andrea Cervesato
andrea.cervesato@suse.de
Tue Jul 21 14:41:05 CEST 2026
From: Andrea Cervesato <andrea.cervesato@suse.com>
Convert the mremap05 test case from the legacy LTP API to the new
tst_test API.
Rewrite the test as a data-only struct tcase array with a single
run() handler, replacing the old function-pointer setup/cleanup
dispatch table. Use TST_EXP_FAIL_PTR_VOID() to verify that
mremap(MREMAP_FIXED) fails with EINVAL when MREMAP_MAYMOVE is not
set, when the target address is not page aligned, and when the old
and new ranges overlap. For the two successful-move cases, verify
both that mremap() returns the requested fixed address and that the
mapping's content is preserved across the move, including when the
target address was already mapped (proving the previous mapping
there is silently unmapped and replaced).
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
testcases/kernel/syscalls/mremap/mremap05.c | 315 +++++++++++-----------------
1 file changed, 127 insertions(+), 188 deletions(-)
diff --git a/testcases/kernel/syscalls/mremap/mremap05.c b/testcases/kernel/syscalls/mremap/mremap05.c
index 971cc8e5ee52c9a489782e3734178f59cd7e4a3c..3ccbda75a01ec1943ff92236767a85850e2f77df 100644
--- a/testcases/kernel/syscalls/mremap/mremap05.c
+++ b/testcases/kernel/syscalls/mremap/mremap05.c
@@ -1,239 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012 Linux Test Project, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it
- * is free of the rightful claim of any third person regarding
- * infringement or the like. Any license provided herein, whether
- * implied or otherwise, applies only to this software file. Patent
- * licenses, if any, provided herein do not apply to combinations of
- * this program with other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
+ * Copyright (c) 2026 Linux Test Project
*/
-/*
- * Test Name: mremap05
+
+/*\
+ * Verify the behavior of the ``MREMAP_FIXED`` flag of :manpage:`mremap(2)`:
*
- * Test Description:
- * Verify that MREMAP_FIXED fails without MREMAP_MAYMOVE.
- * Verify that MREMAP_FIXED|MREMAP_MAYMOVE fails if target address
- * is not page aligned.
- * Verify that MREMAP_FIXED|MREMAP_MAYMOVE fails if old range
- * overlaps with new range.
- * Verify that MREMAP_FIXED|MREMAP_MAYMOVE can move mapping to new address.
- * Verify that MREMAP_FIXED|MREMAP_MAYMOVE unmaps previous mapping
- * at the address range specified by new_address and new_size.
+ * - ``MREMAP_FIXED`` fails with ``EINVAL`` without ``MREMAP_MAYMOVE``.
+ * - ``MREMAP_FIXED | MREMAP_MAYMOVE`` fails with ``EINVAL`` if the target
+ * address is not page aligned.
+ * - ``MREMAP_FIXED | MREMAP_MAYMOVE`` fails with ``EINVAL`` if the old range
+ * overlaps with the new range.
+ * - ``MREMAP_FIXED | MREMAP_MAYMOVE`` can move a mapping to a new, free
+ * address, preserving its content.
+ * - ``MREMAP_FIXED | MREMAP_MAYMOVE`` unmaps a previously existing mapping at
+ * the target address range and replaces it with the moved mapping.
*/
#define _GNU_SOURCE
-#include "config.h"
#include <sys/mman.h>
#include <errno.h>
#include <unistd.h>
-#include "test.h"
-#include "tso_safe_macros.h"
+#include "tst_test.h"
-char *TCID = "mremap05";
+static int pagesize;
-struct test_case_t {
- char *old_address;
- char *new_address;
- size_t old_size; /* in pages */
- size_t new_size; /* in pages */
+static struct tcase {
+ size_t old_pages;
+ size_t new_pages;
int flags;
- const char *msg;
- void *exp_ret;
+ int align_offset;
+ int overlap;
+ int free_dst;
+ int expect_move;
int exp_errno;
- char *ret;
- void (*setup) (struct test_case_t *);
- void (*cleanup) (struct test_case_t *);
-};
-
-static void setup(void);
-static void cleanup(void);
-static void setup0(struct test_case_t *);
-static void setup1(struct test_case_t *);
-static void setup2(struct test_case_t *);
-static void setup3(struct test_case_t *);
-static void setup4(struct test_case_t *);
-static void cleanup0(struct test_case_t *);
-static void cleanup1(struct test_case_t *);
-
-struct test_case_t tdat[] = {
+ const char *msg;
+} tcases[] = {
{
- .old_size = 1,
- .new_size = 1,
- .flags = MREMAP_FIXED,
- .msg = "MREMAP_FIXED requires MREMAP_MAYMOVE",
- .exp_ret = MAP_FAILED,
- .exp_errno = EINVAL,
- .setup = setup0,
- .cleanup = cleanup0},
+ .old_pages = 1,
+ .new_pages = 1,
+ .flags = MREMAP_FIXED,
+ .free_dst = 1,
+ .exp_errno = EINVAL,
+ .msg = "MREMAP_FIXED requires MREMAP_MAYMOVE",
+ },
{
- .old_size = 1,
- .new_size = 1,
- .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
- .msg = "new_addr has to be page aligned",
- .exp_ret = MAP_FAILED,
- .exp_errno = EINVAL,
- .setup = setup1,
- .cleanup = cleanup0},
+ .old_pages = 1,
+ .new_pages = 1,
+ .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
+ .align_offset = 1,
+ .exp_errno = EINVAL,
+ .msg = "new_addr has to be page aligned",
+ },
{
- .old_size = 2,
- .new_size = 1,
- .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
- .msg = "old/new area must not overlap",
- .exp_ret = MAP_FAILED,
- .exp_errno = EINVAL,
- .setup = setup2,
- .cleanup = cleanup0},
+ .old_pages = 2,
+ .new_pages = 1,
+ .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
+ .overlap = 1,
+ .exp_errno = EINVAL,
+ .msg = "old/new area must not overlap",
+ },
{
- .old_size = 1,
- .new_size = 1,
- .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
- .msg = "mremap #1",
- .setup = setup3,
- .cleanup = cleanup0},
+ .old_pages = 1,
+ .new_pages = 1,
+ .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
+ .free_dst = 1,
+ .expect_move = 1,
+ .msg = "move mapping to free address",
+ },
{
- .old_size = 1,
- .new_size = 1,
- .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
- .msg = "mremap #2",
- .setup = setup4,
- .cleanup = cleanup1},
+ .old_pages = 1,
+ .new_pages = 1,
+ .flags = MREMAP_FIXED | MREMAP_MAYMOVE,
+ .free_dst = 0,
+ .expect_move = 1,
+ .msg = "move mapping onto an occupied address",
+ },
};
-static int pagesize;
-static int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
-
-static void free_test_area(void *p, int size)
-{
- SAFE_MUNMAP(cleanup, p, size);
-}
-
-static void *get_test_area(int size, int free_area)
+static void *get_test_area(size_t size, int free_area)
{
void *p;
- p = mmap(NULL, size, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
- if (p == MAP_FAILED)
- tst_brkm(TBROK | TERRNO, cleanup, "get_test_area mmap");
+
+ p = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
if (free_area)
- free_test_area(p, size);
+ SAFE_MUNMAP(p, size);
+
return p;
}
-static void test_mremap(struct test_case_t *t)
+static void setup(void)
{
- t->ret = mremap(t->old_address, t->old_size, t->new_size, t->flags,
- t->new_address);
-
- if (t->ret == t->exp_ret) {
- if (t->ret != MAP_FAILED) {
- tst_resm(TPASS, "%s", t->msg);
- if (*(t->ret) == 0x1)
- tst_resm(TPASS, "%s value OK", t->msg);
- else
- tst_resm(TPASS, "%s value failed", t->msg);
- } else {
- if (errno == t->exp_errno)
- tst_resm(TPASS, "%s", t->msg);
- else
- tst_resm(TFAIL | TERRNO, "%s", t->msg);
- }
- } else {
- tst_resm(TFAIL, "%s ret: %p, expected: %p", t->msg,
- t->ret, t->exp_ret);
- }
+ pagesize = getpagesize();
}
-static void setup0(struct test_case_t *t)
+static void fill_pattern(char *addr, size_t pages)
{
- t->old_address = get_test_area(t->old_size * pagesize, 0);
- t->new_address = get_test_area(t->new_size * pagesize, 1);
-}
+ size_t i;
-static void setup1(struct test_case_t *t)
-{
- t->old_address = get_test_area(t->old_size * pagesize, 0);
- t->new_address = get_test_area((t->new_size + 1) * pagesize, 1) + 1;
+ for (i = 0; i < pages; i++)
+ addr[i * pagesize] = (char)(0x1 + i);
}
-static void setup2(struct test_case_t *t)
+static int check_pattern(const char *msg, char *addr, size_t pages)
{
- t->old_address = get_test_area(t->old_size * pagesize, 0);
- t->new_address = t->old_address;
-}
+ size_t i;
-static void setup3(struct test_case_t *t)
-{
- t->old_address = get_test_area(t->old_size * pagesize, 0);
- t->new_address = get_test_area(t->new_size * pagesize, 1);
- t->exp_ret = t->new_address;
- *(t->old_address) = 0x1;
-}
+ for (i = 0; i < pages; i++) {
+ char got = addr[i * pagesize];
+ char exp = (char)(0x1 + i);
-static void setup4(struct test_case_t *t)
-{
- t->old_address = get_test_area(t->old_size * pagesize, 0);
- t->new_address = get_test_area(t->new_size * pagesize, 0);
- t->exp_ret = t->new_address;
- *(t->old_address) = 0x1;
- *(t->new_address) = 0x2;
-}
+ if (got != exp) {
+ tst_res(TFAIL, "%s: page %zu content 0x%x, expected 0x%x",
+ msg, i, (unsigned char)got, (unsigned char)exp);
+ return 1;
+ }
+ }
-static void cleanup0(struct test_case_t *t)
-{
- if (t->ret == MAP_FAILED)
- free_test_area(t->old_address, t->old_size * pagesize);
- else
- free_test_area(t->ret, t->new_size * pagesize);
+ return 0;
}
-static void cleanup1(struct test_case_t *t)
+static void run(unsigned int n)
{
- if (t->ret == MAP_FAILED) {
- free_test_area(t->old_address, t->old_size * pagesize);
- free_test_area(t->new_address, t->new_size * pagesize);
+ struct tcase *tc = &tcases[n];
+ char *old_address;
+ char *new_address;
+ char *ret;
+ size_t old_size = tc->old_pages * pagesize;
+ size_t new_size = tc->new_pages * pagesize;
+
+ old_address = get_test_area(old_size, 0);
+
+ if (tc->overlap) {
+ new_address = old_address;
+ } else if (tc->align_offset) {
+ new_address = get_test_area(new_size + pagesize, 1) +
+ tc->align_offset;
} else {
- free_test_area(t->ret, t->new_size * pagesize);
+ new_address = get_test_area(new_size, tc->free_dst);
}
-}
-int main(int ac, char **av)
-{
- int lc, testno;
+ if (tc->expect_move) {
+ fill_pattern(old_address, tc->old_pages);
+
+ if (!tc->free_dst)
+ *new_address = 0x7f;
- tst_parse_opts(ac, av, NULL, NULL);
+ TESTPTR(mremap(old_address, old_size, new_size, tc->flags,
+ new_address));
+ ret = TST_RET_PTR;
- setup();
- for (lc = 0; TEST_LOOPING(lc); lc++) {
- tst_count = 0;
- for (testno = 0; testno < TST_TOTAL; testno++) {
- tdat[testno].setup(&tdat[testno]);
- test_mremap(&tdat[testno]);
- tdat[testno].cleanup(&tdat[testno]);
+ if (ret != new_address) {
+ tst_res(TFAIL, "%s: ret %p, expected %p",
+ tc->msg, ret, new_address);
+ } else if (check_pattern(tc->msg, ret, tc->new_pages) == 0) {
+ tst_res(TPASS, "%s", tc->msg);
}
+ } else {
+ TST_EXP_FAIL_PTR_VOID(mremap(old_address, old_size, new_size,
+ tc->flags, new_address),
+ tc->exp_errno, "%s", tc->msg);
}
- cleanup();
- tst_exit();
-}
-static void setup(void)
-{
- pagesize = getpagesize();
+ if (TST_RET_PTR == MAP_FAILED)
+ SAFE_MUNMAP(old_address, old_size);
+ else
+ SAFE_MUNMAP(TST_RET_PTR, new_size);
}
-static void cleanup(void)
-{
-}
+static struct tst_test test = {
+ .setup = setup,
+ .test = run,
+ .tcnt = ARRAY_SIZE(tcases),
+};
--
2.51.0
More information about the ltp
mailing list