All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH v1 0/3] Add process_madvise support
@ 2022-10-06 11:06 Andrea Cervesato via ltp
  2022-10-06 11:06 ` [LTP] [PATCH v1 1/3] Add process_madvise01 test Andrea Cervesato via ltp
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Andrea Cervesato via ltp @ 2022-10-06 11:06 UTC (permalink / raw)
  To: ltp

Added process_madvise testing suite to test MADV_COLD and MADV_PAGEOUT.
It requires MADV_COLD and MADV_PAGEOUT definition inside LTP before
push.

Andrea Cervesato (3):
  Add process_madvise01 test
  Add process_madvise02 test
  Add process_madvise03 test

 testcases/kernel/syscalls/cma/.gitignore      |   3 +
 testcases/kernel/syscalls/cma/cma.h           | 101 ++++++++++++
 .../kernel/syscalls/cma/process_madvise01.c   | 153 ++++++++++++++++++
 .../kernel/syscalls/cma/process_madvise02.c   | 128 +++++++++++++++
 .../kernel/syscalls/cma/process_madvise03.c   | 139 ++++++++++++++++
 5 files changed, 524 insertions(+)
 create mode 100644 testcases/kernel/syscalls/cma/cma.h
 create mode 100644 testcases/kernel/syscalls/cma/process_madvise01.c
 create mode 100644 testcases/kernel/syscalls/cma/process_madvise02.c
 create mode 100644 testcases/kernel/syscalls/cma/process_madvise03.c

-- 
2.35.3


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

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

* [LTP] [PATCH v1 1/3] Add process_madvise01 test
  2022-10-06 11:06 [LTP] [PATCH v1 0/3] Add process_madvise support Andrea Cervesato via ltp
@ 2022-10-06 11:06 ` Andrea Cervesato via ltp
  2022-10-18 11:51   ` Richard Palethorpe
  2022-10-06 11:06 ` [LTP] [PATCH v1] Rewrite process_vm01 test using new LTP API Andrea Cervesato via ltp
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: Andrea Cervesato via ltp @ 2022-10-06 11:06 UTC (permalink / raw)
  To: ltp

Test for checking MADV_COLD support in process_madvise syscall.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 testcases/kernel/syscalls/cma/.gitignore      |   1 +
 testcases/kernel/syscalls/cma/cma.h           | 101 ++++++++++++
 .../kernel/syscalls/cma/process_madvise01.c   | 153 ++++++++++++++++++
 3 files changed, 255 insertions(+)
 create mode 100644 testcases/kernel/syscalls/cma/cma.h
 create mode 100644 testcases/kernel/syscalls/cma/process_madvise01.c

diff --git a/testcases/kernel/syscalls/cma/.gitignore b/testcases/kernel/syscalls/cma/.gitignore
index 1ee39d93e..846704294 100644
--- a/testcases/kernel/syscalls/cma/.gitignore
+++ b/testcases/kernel/syscalls/cma/.gitignore
@@ -2,3 +2,4 @@
 /process_vm_readv02
 /process_vm_readv03
 /process_vm_writev02
+/process_madvise01
diff --git a/testcases/kernel/syscalls/cma/cma.h b/testcases/kernel/syscalls/cma/cma.h
new file mode 100644
index 000000000..08a0d9319
--- /dev/null
+++ b/testcases/kernel/syscalls/cma/cma.h
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+#ifndef CMA_H__
+#define CMA_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "tst_safe_stdio.h"
+
+struct addr_mapping {
+	int size;
+	int rss;
+	int pss;
+	int shared_clean;
+	int shared_dirty;
+	int private_clean;
+	int private_dirty;
+	int referenced;
+	int anonymous;
+	int anon_huge_pages;
+	int shmem_huge_pages;
+	int shmem_pmd_mapped;
+	int swap;
+	int kernel_page_size;
+	int mmu_page_size;
+	int locked;
+	int protection_key;
+};
+
+static inline void read_address_mapping(unsigned long address, struct addr_mapping *mapping)
+{
+	FILE *f;
+	int found = 0;
+	char label[BUFSIZ];
+	char line[BUFSIZ];
+	char smaps[BUFSIZ];
+	char ptr_str[BUFSIZ];
+	int value;
+
+	snprintf(smaps, BUFSIZ, "/proc/%i/smaps", getpid());
+	snprintf(ptr_str, BUFSIZ, "%lx", address);
+
+	f = SAFE_FOPEN(smaps, "r");
+
+	while (fgets(line, BUFSIZ, f) != NULL) {
+		if (strncmp(ptr_str, line, strlen(ptr_str)) == 0)
+			found = 1;
+
+		if (!found)
+			continue;
+
+		if (found && strcmp(line, "VmFlags") >= 0)
+			break;
+
+		if (sscanf(line, "%31[^:]: %d", label, &value) > 0) {
+			if (strcmp(label, "Size") == 0)
+				mapping->size = value;
+			else if (strcmp(label, "Rss") == 0)
+				mapping->rss = value;
+			else if (strcmp(label, "Pss") == 0)
+				mapping->pss = value;
+			else if (strcmp(label, "Shared_Clean") == 0)
+				mapping->shared_clean = value;
+			else if (strcmp(label, "Shared_Dirty") == 0)
+				mapping->shared_dirty = value;
+			else if (strcmp(label, "Private_Clean") == 0)
+				mapping->private_clean = value;
+			else if (strcmp(label, "Private_Dirty") == 0)
+				mapping->private_dirty = value;
+			else if (strcmp(label, "Referenced") == 0)
+				mapping->referenced = value;
+			else if (strcmp(label, "Anonymous") == 0)
+				mapping->anonymous = value;
+			else if (strcmp(label, "AnonHugePages") == 0)
+				mapping->anon_huge_pages = value;
+			else if (strcmp(label, "ShmemHugePages") == 0)
+				mapping->shmem_huge_pages = value;
+			else if (strcmp(label, "ShmemPmdMapped") == 0)
+				mapping->shmem_pmd_mapped = value;
+			else if (strcmp(label, "Swap") == 0)
+				mapping->swap = value;
+			else if (strcmp(label, "KernelPageSize") == 0)
+				mapping->kernel_page_size = value;
+			else if (strcmp(label, "MMUPageSize") == 0)
+				mapping->mmu_page_size = value;
+			else if (strcmp(label, "Locked") == 0)
+				mapping->locked = value;
+			else if (strcmp(label, "ProtectionKey") == 0)
+				mapping->protection_key = value;
+		}
+	}
+
+	SAFE_FCLOSE(f);
+}
+
+#endif
diff --git a/testcases/kernel/syscalls/cma/process_madvise01.c b/testcases/kernel/syscalls/cma/process_madvise01.c
new file mode 100644
index 000000000..d907d982c
--- /dev/null
+++ b/testcases/kernel/syscalls/cma/process_madvise01.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * [Description]
+ *
+ * Spawn child inside cgroup and set max memory. Allocate anonymous memory
+ * pages inside child and deactivate them with MADV_COLD. Then apply memory
+ * pressure and check if memory pages have been swapped out.
+ *
+ * The advice might be ignored for some pages in the range when it is
+ * not applicable, so test passes if swap memory increases after
+ * reclaiming memory with MADV_COLD.
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/mman.h>
+#include "tst_test.h"
+#include "lapi/mmap.h"
+#include "lapi/syscalls.h"
+#include "cma.h"
+
+#define MEM_LIMIT	(50 * 1024 * 1024)
+#define MEM_CHILD	(10 * 1024 * 1024)
+#define MEM_PRESS	MEM_LIMIT
+
+static void **data_ptr;
+
+static void child_alloc(void)
+{
+	char *ptr;
+	char *data;
+	size_t cmem;
+	size_t cswap;
+	int freed = 1;
+	struct addr_mapping map_before;
+	struct addr_mapping map_after;
+
+	tst_res(TINFO, "Set memory limit");
+
+	SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid());
+	SAFE_CG_PRINTF(tst_cg, "memory.max", "%d", MEM_LIMIT);
+
+	tst_res(TINFO, "Allocate memory");
+
+	*data_ptr = SAFE_MMAP(NULL, MEM_CHILD,
+			PROT_READ | PROT_WRITE,
+			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+	memset(*data_ptr, 'a', MEM_CHILD);
+
+	read_address_mapping((unsigned long)*data_ptr, &map_before);
+
+	SAFE_CG_SCANF(tst_cg, "memory.current", "%zu", &cmem);
+	tst_res(TINFO, "Allocated %lu / %d bytes", cmem, MEM_LIMIT);
+
+	TST_CHECKPOINT_WAKE_AND_WAIT(0);
+
+	tst_res(TINFO, "Apply memory pressure");
+
+	data = SAFE_MMAP(NULL, MEM_PRESS,
+			PROT_READ | PROT_WRITE,
+			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+	memset(data, 'b', MEM_PRESS);
+	SAFE_MUNMAP(data, MEM_PRESS);
+
+	SAFE_CG_SCANF(tst_cg, "memory.swap.current", "%zu", &cswap);
+	tst_res(TINFO, "Swap now contains %lu bytes", cswap);
+
+	for (ptr = *data_ptr; *ptr != '\0'; ptr++) {
+		if (*ptr == 'a') {
+			freed = 0;
+			break;
+		}
+	}
+
+	if (freed) {
+		tst_res(TFAIL, "Memory has been freed");
+		return;
+	}
+
+	read_address_mapping((unsigned long)*data_ptr, &map_after);
+
+	SAFE_MUNMAP(*data_ptr, MEM_CHILD);
+
+	if (map_before.swap < map_after.swap)
+		tst_res(TPASS, "Memory has been swapped out");
+	else
+		tst_res(TFAIL, "Swap memory has decreased");
+}
+
+static void setup(void)
+{
+	data_ptr = SAFE_MMAP(NULL, sizeof(void *),
+			PROT_READ | PROT_WRITE,
+			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+}
+
+static void cleanup(void)
+{
+	if (*data_ptr)
+		SAFE_MUNMAP(*data_ptr, MEM_CHILD);
+
+	if (data_ptr)
+		SAFE_MUNMAP(data_ptr, sizeof(void *));
+}
+
+static void run(void)
+{
+	int ret;
+	int pidfd;
+	pid_t pid_alloc;
+	struct iovec vec;
+
+	pid_alloc = SAFE_FORK();
+	if (!pid_alloc) {
+		child_alloc();
+		return;
+	}
+
+	TST_CHECKPOINT_WAIT(0);
+
+	tst_res(TINFO, "Apply MADV_COLD advise rule");
+
+	pidfd = SAFE_PIDFD_OPEN(pid_alloc, 0);
+
+	vec.iov_base = *data_ptr;
+	vec.iov_len = MEM_CHILD;
+
+	ret = tst_syscall(__NR_process_madvise, pidfd, &vec, 1UL,
+			MADV_COLD, 0UL);
+
+	if (ret == -1)
+		tst_brk(TBROK | TERRNO, "process_madvise failed");
+
+	if (ret != MEM_CHILD)
+		tst_brk(TBROK, "process_madvise reclaimed only %d bytes", ret);
+
+	TST_CHECKPOINT_WAKE(0);
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.cleanup = cleanup,
+	.test_all = run,
+	.forks_child = 1,
+	.min_kver = "5.10",
+	.needs_checkpoints = 1,
+	.needs_cgroup_ver = TST_CG_V2,
+	.needs_cgroup_ctrls = (const char *const []){ "memory", NULL },
+};
-- 
2.35.3


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

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

* [LTP] [PATCH v1] Rewrite process_vm01 test using new LTP API
  2022-10-06 11:06 [LTP] [PATCH v1 0/3] Add process_madvise support Andrea Cervesato via ltp
  2022-10-06 11:06 ` [LTP] [PATCH v1 1/3] Add process_madvise01 test Andrea Cervesato via ltp
@ 2022-10-06 11:06 ` Andrea Cervesato via ltp
  2022-10-06 11:10   ` Andrea Cervesato via ltp
  2022-10-06 11:06 ` [LTP] [PATCH v1 2/3] Add process_madvise02 test Andrea Cervesato via ltp
  2022-10-06 11:06 ` [LTP] [PATCH v1 3/3] Add process_madvise03 test Andrea Cervesato via ltp
  3 siblings, 1 reply; 11+ messages in thread
From: Andrea Cervesato via ltp @ 2022-10-06 11:06 UTC (permalink / raw)
  To: ltp

Now test is run on process_vm_writev by default and process_vm_readv can
be selected by passing -r command line option.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 runtest/syscalls                             |   2 +-
 testcases/kernel/syscalls/cma/process_vm01.c | 464 ++++++++-----------
 2 files changed, 188 insertions(+), 278 deletions(-)

diff --git a/runtest/syscalls b/runtest/syscalls
index 3847e8af2..70f22fbd5 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1031,7 +1031,7 @@ profil01 profil01
 process_vm_readv01 process_vm01 -r
 process_vm_readv02 process_vm_readv02
 process_vm_readv03 process_vm_readv03
-process_vm_writev01 process_vm01 -w
+process_vm_writev01 process_vm01
 process_vm_writev02 process_vm_writev02
 
 prot_hsymlinks prot_hsymlinks
diff --git a/testcases/kernel/syscalls/cma/process_vm01.c b/testcases/kernel/syscalls/cma/process_vm01.c
index 16f14d66b..bfd5c5acb 100644
--- a/testcases/kernel/syscalls/cma/process_vm01.c
+++ b/testcases/kernel/syscalls/cma/process_vm01.c
@@ -1,47 +1,18 @@
+// 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) Linux Test Project, 2012
+ * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
  */
 
-/*
- * errno tests shared by process_vm_readv, process_vm_writev tests.
+/*\
+ * [Description]
+ *
+ * Test errno codes in process_vm_readv and process_vm_writev syscalls.
  */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/uio.h>
-#include <sys/wait.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <limits.h>
+
 #include <pwd.h>
-#include "config.h"
-#include "test.h"
-#include "safe_macros.h"
+#include <stdlib.h>
+#include "tst_test.h"
 #include "lapi/syscalls.h"
 
 struct process_vm_params {
@@ -56,137 +27,27 @@ struct process_vm_params {
 	unsigned long flags;
 };
 
-static int rflag;
-static int wflag;
-
-static option_t options[] = {
-	{"r", &rflag, NULL},
-	{"w", &wflag, NULL},
-	{NULL, NULL, NULL}
-};
-
-static char TCID_readv[] = "process_vm_readv";
-static char TCID_writev[] = "process_vm_writev";
-char *TCID = "cma01";
-int TST_TOTAL = 1;
-static void (*cma_test_params) (struct process_vm_params * params) = NULL;
-
-static void setup(char *argv[]);
-static void cleanup(void);
-static void help(void);
-
-static void cma_test_params_read(struct process_vm_params *params);
-static void cma_test_params_write(struct process_vm_params *params);
-static void cma_test_errnos(void);
-
-int main(int argc, char *argv[])
-{
-	int lc;
-
-	tst_parse_opts(argc, argv, options, &help);
-
-	setup(argv);
-	for (lc = 0; TEST_LOOPING(lc); lc++) {
-		tst_count = 0;
-		cma_test_errnos();
-	}
-	cleanup();
-	tst_exit();
-}
-
-static void setup(char *argv[])
-{
-	tst_require_root();
-
-	if (rflag && wflag)
-		tst_brkm(TBROK, NULL, "Parameters -r -w can not be used"
-			 " at the same time.");
-	else if (rflag) {
-		TCID = TCID_readv;
-		cma_test_params = cma_test_params_read;
-	} else if (wflag) {
-		TCID = TCID_writev;
-		cma_test_params = cma_test_params_write;
-	} else
-		tst_brkm(TBROK, NULL, "Parameter missing, required -r or -w.");
-	TEST_PAUSE;
-}
-
-static void cleanup(void)
-{
-}
-
-static void help(void)
-{
-	printf("  -r      Use process_vm_readv\n");
-	printf("  -w      Use process_vm_writev\n");
-}
-
-static void cma_test_params_read(struct process_vm_params *params)
-{
-	TEST(tst_syscall(__NR_process_vm_readv,
-			 params->pid,
-			 params->lvec, params->liovcnt,
-			 params->rvec, params->riovcnt,
-			 params->flags));
-}
-
-static void cma_test_params_write(struct process_vm_params *params)
-{
-	TEST(tst_syscall(__NR_process_vm_writev,
-			 params->pid,
-			 params->lvec, params->liovcnt,
-			 params->rvec, params->riovcnt,
-			 params->flags));
-}
-
-static int cma_check_ret(long expected_ret, long act_ret)
-{
-	if (expected_ret == act_ret) {
-		tst_resm(TPASS, "expected ret success - "
-			 "returned value = %ld", act_ret);
-	} else {
-		tst_resm(TFAIL, "unexpected failure - "
-			 "returned value = %ld, expected: %ld",
-			 act_ret, expected_ret);
-		return 1;
-	}
-	return 0;
-}
-
-static int cma_check_errno(long expected_errno)
-{
-	if (TEST_ERRNO == expected_errno)
-		tst_resm(TPASS | TTERRNO, "expected failure");
-	else if (TEST_ERRNO == 0) {
-		tst_resm(TFAIL, "call succeeded unexpectedly");
-		return 1;
-	} else {
-		tst_resm(TFAIL | TTERRNO, "unexpected failure - "
-			 "expected = %ld : %s, actual",
-			 expected_errno, strerror(expected_errno));
-		return 2;
-	}
-	return 0;
-}
+static char *str_read;
+static void (*test_params)(struct process_vm_params *params);
 
-static struct process_vm_params *cma_alloc_sane_params(void)
+static struct process_vm_params *alloc_params(void)
 {
 	struct process_vm_params *sane_params;
 	int len;
 
 	len = getpagesize();
-	sane_params = SAFE_MALLOC(NULL, sizeof(struct process_vm_params));
+
+	sane_params = SAFE_MALLOC(sizeof(struct process_vm_params));
 	sane_params->len = len;
-	sane_params->ldummy = SAFE_MALLOC(NULL, len);
-	sane_params->rdummy = SAFE_MALLOC(NULL, len);
+	sane_params->ldummy = SAFE_MALLOC(len);
+	sane_params->rdummy = SAFE_MALLOC(len);
 
-	sane_params->lvec = SAFE_MALLOC(NULL, sizeof(struct iovec));
+	sane_params->lvec = SAFE_MALLOC(sizeof(struct process_vm_params));
 	sane_params->lvec->iov_base = sane_params->ldummy;
 	sane_params->lvec->iov_len = len;
 	sane_params->liovcnt = 1;
 
-	sane_params->rvec = SAFE_MALLOC(NULL, sizeof(struct iovec));
+	sane_params->rvec = SAFE_MALLOC(sizeof(struct process_vm_params));
 	sane_params->rvec->iov_base = sane_params->rdummy;
 	sane_params->rvec->iov_len = len;
 	sane_params->riovcnt = 1;
@@ -197,7 +58,7 @@ static struct process_vm_params *cma_alloc_sane_params(void)
 	return sane_params;
 }
 
-static void cma_free_params(struct process_vm_params *params)
+static void free_params(struct process_vm_params *params)
 {
 	if (params) {
 		free(params->ldummy);
@@ -208,195 +69,244 @@ static void cma_free_params(struct process_vm_params *params)
 	}
 }
 
-static void cma_test_sane_params(void)
+static void test_readv(struct process_vm_params *params)
+{
+	TEST(tst_syscall(__NR_process_vm_readv,
+		params->pid,
+		params->lvec, params->liovcnt,
+		params->rvec, params->riovcnt,
+		params->flags));
+}
+
+static void test_writev(struct process_vm_params *params)
+{
+	TEST(tst_syscall(__NR_process_vm_writev,
+		params->pid,
+		params->lvec, params->liovcnt,
+		params->rvec, params->riovcnt,
+		params->flags));
+}
+
+static void check_errno(long expected_errno)
+{
+	if (TST_ERR == expected_errno)
+		tst_res(TPASS | TTERRNO, "expected failure");
+	else if (TST_ERR == 0)
+		tst_res(TFAIL, "call succeeded unexpectedly");
+	else
+		tst_res(TFAIL | TTERRNO, "unexpected failure - "
+			"expected = %ld : %s, actual",
+			expected_errno, strerror(expected_errno));
+}
+
+static void test_sane_params(void)
 {
 	struct process_vm_params *sane_params;
 
-	sane_params = cma_alloc_sane_params();
-	tst_resm(TINFO, "test_sane_params");
-	cma_test_params(sane_params);
-	cma_check_ret(sane_params->len, TEST_RETURN);
-	cma_free_params(sane_params);
+	tst_res(TINFO, "Testing sane parameters");
+
+	sane_params = alloc_params();
+	test_params(sane_params);
+	TST_EXP_EQ_LI(TST_RET, sane_params->len);
+	free_params(sane_params);
 }
 
-static void cma_test_flags(void)
+static void test_flags(void)
 {
 	struct process_vm_params *params;
 	long flags[] = { -INT_MAX, -1, 1, INT_MAX, 0 };
-	int flags_size = sizeof(flags) / sizeof(flags[0]);
+	int flags_size = ARRAY_SIZE(flags) / sizeof(flags[0]);
 	int i;
 
-	params = cma_alloc_sane_params();
+	params = alloc_params();
+
 	for (i = 0; i < flags_size; i++) {
 		params->flags = flags[i];
-		tst_resm(TINFO, "test_flags, flags=%ld", flags[i]);
-		cma_test_params(params);
+
+		tst_res(TINFO, "Testing flags=%ld", flags[i]);
+		test_params(params);
+
 		/* atm. only flags == 0 is allowed, everything else
-		 * should fail with EINVAL */
+		 * should fail with EINVAL
+		 */
 		if (flags[i] != 0) {
-			cma_check_ret(-1, TEST_RETURN);
-			cma_check_errno(EINVAL);
+			TST_EXP_EQ_LI(TST_RET, -1);
+			check_errno(EINVAL);
 		} else {
-			cma_check_ret(params->len, TEST_RETURN);
+			TST_EXP_EQ_LI(TST_RET, params->len);
 		}
 	}
-	cma_free_params(params);
+
+	free_params(params);
 }
 
-static void cma_test_iov_len_overflow(void)
+static void test_iov_len_overflow(void)
 {
 	struct process_vm_params *params;
-	ssize_t maxlen = -1;
-	params = cma_alloc_sane_params();
-
-	params->lvec->iov_len = maxlen;
-	params->rvec->iov_len = maxlen;
-	tst_resm(TINFO, "test_iov_len_overflow");
-	cma_test_params(params);
-	cma_check_ret(-1, TEST_RETURN);
-	cma_check_errno(EINVAL);
-	cma_free_params(params);
+
+	tst_res(TINFO, "Testing iov_len = -1");
+
+	params = alloc_params();
+	params->lvec->iov_len = -1;
+	params->rvec->iov_len = -1;
+	test_params(params);
+	TST_EXP_EQ_LI(TST_RET, -1);
+	check_errno(EINVAL);
+	free_params(params);
 }
 
-static void cma_test_iov_invalid(void)
+static void test_iov_invalid(void)
 {
 	struct process_vm_params *sane_params;
 	struct process_vm_params params_copy;
 
-	sane_params = cma_alloc_sane_params();
-	/* make a shallow copy we can 'damage' */
+	sane_params = alloc_params();
 
+	tst_res(TINFO, "Testing lvec->iov_base = -1");
 	params_copy = *sane_params;
-	tst_resm(TINFO, "test_iov_invalid - lvec->iov_base");
 	params_copy.lvec->iov_base = (void *)-1;
-	cma_test_params(&params_copy);
-	cma_check_ret(-1, TEST_RETURN);
-	cma_check_errno(EFAULT);
+	test_params(&params_copy);
+	TST_EXP_EQ_LI(TST_RET, -1);
+	check_errno(EFAULT);
 
+	tst_res(TINFO, "Testing rvec->iov_base = -1");
 	params_copy = *sane_params;
-	tst_resm(TINFO, "test_iov_invalid - rvec->iov_base");
 	params_copy.rvec->iov_base = (void *)-1;
-	cma_test_params(&params_copy);
-	cma_check_ret(-1, TEST_RETURN);
-	cma_check_errno(EFAULT);
+	test_params(&params_copy);
+	TST_EXP_EQ_LI(TST_RET, -1);
+	check_errno(EFAULT);
 
+	tst_res(TINFO, "Testing lvec = -1");
 	params_copy = *sane_params;
-	tst_resm(TINFO, "test_iov_invalid - lvec");
 	params_copy.lvec = (void *)-1;
-	cma_test_params(&params_copy);
-	cma_check_ret(-1, TEST_RETURN);
-	cma_check_errno(EFAULT);
+	test_params(&params_copy);
+	TST_EXP_EQ_LI(TST_RET, -1);
+	check_errno(EFAULT);
 
+	tst_res(TINFO, "Testing rvec = -1");
 	params_copy = *sane_params;
-	tst_resm(TINFO, "test_iov_invalid - rvec");
 	params_copy.rvec = (void *)-1;
-	cma_test_params(&params_copy);
-	cma_check_ret(-1, TEST_RETURN);
-	cma_check_errno(EFAULT);
+	test_params(&params_copy);
+	TST_EXP_EQ_LI(TST_RET, -1);
+	check_errno(EFAULT);
 
-	cma_free_params(sane_params);
+	free_params(sane_params);
 }
 
-static void cma_test_invalid_pid(void)
+static void test_invalid_pid(void)
 {
 	pid_t invalid_pid = -1;
 	struct process_vm_params *params;
+	struct process_vm_params params_copy;
+
+	params = alloc_params();
+
+	tst_res(TINFO, "Testing invalid PID");
+	params_copy = *params;
+	params_copy.pid = invalid_pid;
+	test_params(&params_copy);
+	TST_EXP_EQ_LI(TST_RET, -1);
+	check_errno(ESRCH);
 
-	params = cma_alloc_sane_params();
-	tst_resm(TINFO, "test_invalid_pid");
-	params->pid = invalid_pid;
-	cma_test_params(params);
-	cma_check_ret(-1, TEST_RETURN);
-	cma_check_errno(ESRCH);
-	cma_free_params(params);
-
-	invalid_pid = tst_get_unused_pid(cleanup);
-
-	params = cma_alloc_sane_params();
-	params->pid = invalid_pid;
-	cma_test_params(params);
-	cma_check_ret(-1, TEST_RETURN);
-	cma_check_errno(ESRCH);
-	cma_free_params(params);
+	tst_res(TINFO, "Testing unused PID");
+	params_copy = *params;
+	invalid_pid = tst_get_unused_pid();
+	params_copy.pid = invalid_pid;
+	test_params(&params_copy);
+	TST_EXP_EQ_LI(TST_RET, -1);
+	check_errno(ESRCH);
+
+	free_params(params);
 }
 
-static void cma_test_invalid_perm(void)
+static void test_invalid_perm(void)
 {
 	char nobody_uid[] = "nobody";
 	struct passwd *ltpuser;
-	int status;
 	struct process_vm_params *params;
 	pid_t child_pid;
 	pid_t parent_pid;
-	int ret = 0;
+	int status;
+
+	tst_res(TINFO, "Testing invalid permissions on given PID");
 
-	tst_resm(TINFO, "test_invalid_perm");
 	parent_pid = getpid();
-	child_pid = fork();
-	switch (child_pid) {
-	case -1:
-		tst_brkm(TBROK | TERRNO, cleanup, "fork");
-		break;
-	case 0:
-		ltpuser = getpwnam(nobody_uid);
-		if (ltpuser == NULL)
-			tst_brkm(TBROK | TERRNO, NULL, "getpwnam failed");
-		SAFE_SETUID(NULL, ltpuser->pw_uid);
-
-		params = cma_alloc_sane_params();
+	child_pid = SAFE_FORK();
+	if (!child_pid) {
+		ltpuser = SAFE_GETPWNAM(nobody_uid);
+		SAFE_SETUID(ltpuser->pw_uid);
+
+		params = alloc_params();
 		params->pid = parent_pid;
-		cma_test_params(params);
-		ret |= cma_check_ret(-1, TEST_RETURN);
-		ret |= cma_check_errno(EPERM);
-		cma_free_params(params);
-		exit(ret);
-	default:
-		SAFE_WAITPID(cleanup, child_pid, &status, 0);
-		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
-			tst_resm(TFAIL, "child returns %d", status);
+		test_params(params);
+		TST_EXP_EQ_LI(TST_RET, -1);
+		check_errno(EPERM);
+		free_params(params);
+		return;
 	}
+
+	SAFE_WAITPID(child_pid, &status, 0);
 }
 
-static void cma_test_invalid_protection(void)
+static void test_invalid_protection(void)
 {
 	struct process_vm_params *sane_params;
 	struct process_vm_params params_copy;
-	void *p;
-
-	sane_params = cma_alloc_sane_params();
-	/* make a shallow copy we can 'damage' */
+	void *data;
+	int len;
 
-	p = mmap(NULL, getpagesize(), PROT_NONE,
-		 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
-	if (p == MAP_FAILED)
-		tst_brkm(TBROK | TERRNO, cleanup, "mmap");
+	len = getpagesize();
+	sane_params = alloc_params();
+	data = SAFE_MMAP(NULL, len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
 
+	tst_res(TINFO, "Testing data with invalid protection (lvec)");
 	params_copy = *sane_params;
-	params_copy.lvec->iov_base = p;
-	tst_resm(TINFO, "test_invalid_protection lvec");
-	cma_test_params(&params_copy);
-	cma_check_ret(-1, TEST_RETURN);
-	cma_check_errno(EFAULT);
+	params_copy.lvec->iov_base = data;
+	test_params(&params_copy);
+	TST_EXP_EQ_LI(TST_RET, -1);
+	check_errno(EFAULT);
 
+	tst_res(TINFO, "Testing data with invalid protection (rvec)");
 	params_copy = *sane_params;
-	params_copy.rvec->iov_base = p;
-	tst_resm(TINFO, "test_invalid_protection rvec");
-	cma_test_params(&params_copy);
-	cma_check_ret(-1, TEST_RETURN);
-	cma_check_errno(EFAULT);
+	params_copy.rvec->iov_base = data;
+	test_params(&params_copy);
+	TST_EXP_EQ_LI(TST_RET, -1);
+	check_errno(EFAULT);
 
-	SAFE_MUNMAP(cleanup, p, getpagesize());
+	SAFE_MUNMAP(data, len);
+	free_params(sane_params);
+}
 
-	cma_free_params(sane_params);
+static void run(void)
+{
+	test_sane_params();
+	test_flags();
+	test_iov_len_overflow();
+	test_iov_invalid();
+	test_invalid_pid();
+	test_invalid_perm();
+	test_invalid_protection();
 }
 
-static void cma_test_errnos(void)
+static void setup(void)
 {
-	cma_test_sane_params();
-	cma_test_flags();
-	cma_test_iov_len_overflow();
-	cma_test_iov_invalid();
-	cma_test_invalid_pid();
-	cma_test_invalid_perm();
-	cma_test_invalid_protection();
+	if (str_read) {
+		tst_res(TINFO, "Selected process_vm_readv");
+		test_params = test_readv;
+	} else {
+		tst_res(TINFO, "Selected process_vm_writev");
+		test_params = test_writev;
+	}
 }
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.forks_child = 1,
+	.needs_checkpoints = 1,
+	.needs_root = 1,
+	.options = (struct tst_option[]) {
+		{"r", &str_read, "Use process_vm_read instead of process_vm_write"},
+		{},
+	},
+};
-- 
2.35.3


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

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

* [LTP] [PATCH v1 2/3] Add process_madvise02 test
  2022-10-06 11:06 [LTP] [PATCH v1 0/3] Add process_madvise support Andrea Cervesato via ltp
  2022-10-06 11:06 ` [LTP] [PATCH v1 1/3] Add process_madvise01 test Andrea Cervesato via ltp
  2022-10-06 11:06 ` [LTP] [PATCH v1] Rewrite process_vm01 test using new LTP API Andrea Cervesato via ltp
@ 2022-10-06 11:06 ` Andrea Cervesato via ltp
  2022-10-18 12:24   ` Richard Palethorpe
  2022-10-06 11:06 ` [LTP] [PATCH v1 3/3] Add process_madvise03 test Andrea Cervesato via ltp
  3 siblings, 1 reply; 11+ messages in thread
From: Andrea Cervesato via ltp @ 2022-10-06 11:06 UTC (permalink / raw)
  To: ltp

Test for checking MADV_PAGEOUT functionality over anonymous memory in
process_madvise syscall.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 testcases/kernel/syscalls/cma/.gitignore      |   1 +
 .../kernel/syscalls/cma/process_madvise02.c   | 128 ++++++++++++++++++
 2 files changed, 129 insertions(+)
 create mode 100644 testcases/kernel/syscalls/cma/process_madvise02.c

diff --git a/testcases/kernel/syscalls/cma/.gitignore b/testcases/kernel/syscalls/cma/.gitignore
index 846704294..47ae3e445 100644
--- a/testcases/kernel/syscalls/cma/.gitignore
+++ b/testcases/kernel/syscalls/cma/.gitignore
@@ -3,3 +3,4 @@
 /process_vm_readv03
 /process_vm_writev02
 /process_madvise01
+/process_madvise02
diff --git a/testcases/kernel/syscalls/cma/process_madvise02.c b/testcases/kernel/syscalls/cma/process_madvise02.c
new file mode 100644
index 000000000..9f42dd48a
--- /dev/null
+++ b/testcases/kernel/syscalls/cma/process_madvise02.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * [Description]
+ *
+ * Spawn child inside cgroup and set max memory. Allocate anonymous memory
+ * pages inside child and reclaim it with MADV_PAGEOUT. Then check if memory
+ * pages have been swapped out.
+ *
+ * The advice might be ignored for some pages in the range when it is
+ * not applicable, so test passes if swap memory increases after
+ * reclaiming memory with MADV_PAGEOUT.
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/mman.h>
+#include "tst_test.h"
+#include "lapi/mmap.h"
+#include "lapi/syscalls.h"
+#include "cma.h"
+
+#define MEM_CHILD	(10 * 1024 * 1024)
+
+static void **data_ptr;
+
+static void child_alloc(void)
+{
+	char *ptr;
+	int freed = 1;
+	struct addr_mapping map_before;
+	struct addr_mapping map_after;
+
+	tst_res(TINFO, "Allocate memory");
+
+	*data_ptr = SAFE_MMAP(NULL, MEM_CHILD,
+			PROT_READ | PROT_WRITE,
+			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+	memset(*data_ptr, 'a', MEM_CHILD);
+
+	read_address_mapping((unsigned long)*data_ptr, &map_before);
+
+	TST_CHECKPOINT_WAKE_AND_WAIT(0);
+
+	for (ptr = *data_ptr; *ptr != '\0'; ptr++) {
+		if (*ptr == 'a') {
+			freed = 0;
+			break;
+		}
+	}
+
+	if (freed) {
+		tst_res(TFAIL, "Memory has been freed");
+		return;
+	}
+
+	read_address_mapping((unsigned long)*data_ptr, &map_after);
+
+	SAFE_MUNMAP(*data_ptr, MEM_CHILD);
+	*data_ptr = NULL;
+
+	if (map_before.swap < map_after.swap)
+		tst_res(TPASS, "Memory has been swapped out");
+	else
+		tst_res(TFAIL, "Swap memory has decreased");
+}
+
+static void setup(void)
+{
+	data_ptr = SAFE_MMAP(NULL, sizeof(void *),
+			PROT_READ | PROT_WRITE,
+			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+}
+
+static void cleanup(void)
+{
+	if (*data_ptr)
+		SAFE_MUNMAP(*data_ptr, MEM_CHILD);
+
+	if (data_ptr)
+		SAFE_MUNMAP(data_ptr, sizeof(void *));
+}
+
+static void run(void)
+{
+	int ret;
+	int pidfd;
+	pid_t pid_alloc;
+	struct iovec vec;
+
+	pid_alloc = SAFE_FORK();
+	if (!pid_alloc) {
+		child_alloc();
+		return;
+	}
+
+	TST_CHECKPOINT_WAIT(0);
+
+	tst_res(TINFO, "Apply MADV_PAGEOUT advise rule");
+
+	pidfd = SAFE_PIDFD_OPEN(pid_alloc, 0);
+
+	vec.iov_base = *data_ptr;
+	vec.iov_len = MEM_CHILD;
+
+	ret = tst_syscall(__NR_process_madvise, pidfd, &vec, 1UL,
+			MADV_PAGEOUT, 0UL);
+
+	if (ret == -1)
+		tst_brk(TBROK | TERRNO, "process_madvise failed");
+
+	if (ret != MEM_CHILD)
+		tst_brk(TBROK, "process_madvise reclaimed only %d bytes", ret);
+
+	TST_CHECKPOINT_WAKE(0);
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.cleanup = cleanup,
+	.test_all = run,
+	.forks_child = 1,
+	.min_kver = "5.10",
+	.needs_checkpoints = 1,
+};
-- 
2.35.3


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

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

* [LTP] [PATCH v1 3/3] Add process_madvise03 test
  2022-10-06 11:06 [LTP] [PATCH v1 0/3] Add process_madvise support Andrea Cervesato via ltp
                   ` (2 preceding siblings ...)
  2022-10-06 11:06 ` [LTP] [PATCH v1 2/3] Add process_madvise02 test Andrea Cervesato via ltp
@ 2022-10-06 11:06 ` Andrea Cervesato via ltp
  2022-10-18 12:29   ` Richard Palethorpe
  3 siblings, 1 reply; 11+ messages in thread
From: Andrea Cervesato via ltp @ 2022-10-06 11:06 UTC (permalink / raw)
  To: ltp

Test for checking MADV_PAGEOUT functionality over memory-mapped file
in process_madvise syscall.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 testcases/kernel/syscalls/cma/.gitignore      |   1 +
 .../kernel/syscalls/cma/process_madvise03.c   | 139 ++++++++++++++++++
 2 files changed, 140 insertions(+)
 create mode 100644 testcases/kernel/syscalls/cma/process_madvise03.c

diff --git a/testcases/kernel/syscalls/cma/.gitignore b/testcases/kernel/syscalls/cma/.gitignore
index 47ae3e445..147b03c48 100644
--- a/testcases/kernel/syscalls/cma/.gitignore
+++ b/testcases/kernel/syscalls/cma/.gitignore
@@ -4,3 +4,4 @@
 /process_vm_writev02
 /process_madvise01
 /process_madvise02
+/process_madvise03
diff --git a/testcases/kernel/syscalls/cma/process_madvise03.c b/testcases/kernel/syscalls/cma/process_madvise03.c
new file mode 100644
index 000000000..3f12ef530
--- /dev/null
+++ b/testcases/kernel/syscalls/cma/process_madvise03.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * [Description]
+ *
+ * Spawn child inside cgroup and set max memory. Allocate file-backed memory
+ * pages inside child and reclaim it with MADV_PAGEOUT. Then check if memory
+ * pages have been written back to the backing storage.
+ *
+ * The advice might be ignored for some pages in the range when it is
+ * not applicable, so test passes if pages mapped in RAM decrease after
+ * reclaiming memory with MADV_PAGEOUT and RAM doesn't contain
+ * reclaimed memory anymore.
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/mman.h>
+#include "tst_test.h"
+#include "lapi/mmap.h"
+#include "lapi/syscalls.h"
+#include "cma.h"
+
+#define MEM_CHILD	(10 * 1024 * 1024)
+
+static char *filename = "file.bin";
+static void **data_ptr;
+
+static void child_alloc(void)
+{
+	int fd;
+	char *ptr;
+	int freed = 1;
+	struct addr_mapping map_before;
+	struct addr_mapping map_after;
+
+	tst_res(TINFO, "Allocate file-backed memory");
+
+	fd = SAFE_OPEN(filename, O_CREAT | O_RDWR);
+	SAFE_FTRUNCATE(fd, MEM_CHILD);
+
+	*data_ptr = SAFE_MMAP(NULL, MEM_CHILD,
+			PROT_READ | PROT_WRITE,
+			MAP_SHARED, fd, 0);
+
+	tst_res(TINFO, "Dirty memory");
+	memset(*data_ptr, 'a', MEM_CHILD);
+
+	read_address_mapping((unsigned long)*data_ptr, &map_before);
+
+	TST_CHECKPOINT_WAKE_AND_WAIT(0);
+
+	for (ptr = *data_ptr; *ptr != '\0'; ptr++) {
+		if (*ptr == 'a') {
+			freed = 0;
+			break;
+		}
+	}
+
+	if (freed) {
+		tst_res(TFAIL, "Memory has been freed");
+		return;
+	}
+
+	read_address_mapping((unsigned long)*data_ptr, &map_after);
+
+	SAFE_MUNMAP(*data_ptr, MEM_CHILD);
+	*data_ptr = NULL;
+
+	SAFE_CLOSE(fd);
+
+	if (map_before.rss > map_after.rss)
+		tst_res(TPASS, "Memory has been reclaimed");
+	else
+		tst_res(TFAIL, "RAM has increased");
+}
+
+static void setup(void)
+{
+	data_ptr = SAFE_MMAP(NULL, sizeof(void *),
+			PROT_READ | PROT_WRITE,
+			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+}
+
+static void cleanup(void)
+{
+	if (*data_ptr)
+		SAFE_MUNMAP(*data_ptr, MEM_CHILD);
+
+	if (data_ptr)
+		SAFE_MUNMAP(data_ptr, sizeof(void *));
+}
+
+static void run(void)
+{
+	int ret;
+	int pidfd;
+	pid_t pid_alloc;
+	struct iovec vec;
+
+	pid_alloc = SAFE_FORK();
+	if (!pid_alloc) {
+		child_alloc();
+		return;
+	}
+
+	TST_CHECKPOINT_WAIT(0);
+
+	tst_res(TINFO, "Apply MADV_PAGEOUT advise rule");
+
+	pidfd = SAFE_PIDFD_OPEN(pid_alloc, 0);
+
+	vec.iov_base = *data_ptr;
+	vec.iov_len = MEM_CHILD;
+
+	ret = tst_syscall(__NR_process_madvise, pidfd, &vec, 1UL,
+			MADV_PAGEOUT, 0UL);
+
+	if (ret == -1)
+		tst_brk(TBROK | TERRNO, "process_madvise failed");
+
+	if (ret != MEM_CHILD)
+		tst_brk(TBROK, "process_madvise reclaimed only %d bytes", ret);
+
+	TST_CHECKPOINT_WAKE(0);
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.cleanup = cleanup,
+	.test_all = run,
+	.forks_child = 1,
+	.min_kver = "5.10",
+	.needs_tmpdir = 1,
+	.needs_checkpoints = 1,
+};
-- 
2.35.3


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

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

* Re: [LTP] [PATCH v1] Rewrite process_vm01 test using new LTP API
  2022-10-06 11:06 ` [LTP] [PATCH v1] Rewrite process_vm01 test using new LTP API Andrea Cervesato via ltp
@ 2022-10-06 11:10   ` Andrea Cervesato via ltp
  0 siblings, 0 replies; 11+ messages in thread
From: Andrea Cervesato via ltp @ 2022-10-06 11:10 UTC (permalink / raw)
  To: ltp

Hi,

this patch has been sent already. An accident using "git send-email" 
command.

Andrea

On 10/6/22 13:06, Andrea Cervesato wrote:
> Now test is run on process_vm_writev by default and process_vm_readv can
> be selected by passing -r command line option.
>
> Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
> ---
>   runtest/syscalls                             |   2 +-
>   testcases/kernel/syscalls/cma/process_vm01.c | 464 ++++++++-----------
>   2 files changed, 188 insertions(+), 278 deletions(-)
>
> diff --git a/runtest/syscalls b/runtest/syscalls
> index 3847e8af2..70f22fbd5 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -1031,7 +1031,7 @@ profil01 profil01
>   process_vm_readv01 process_vm01 -r
>   process_vm_readv02 process_vm_readv02
>   process_vm_readv03 process_vm_readv03
> -process_vm_writev01 process_vm01 -w
> +process_vm_writev01 process_vm01
>   process_vm_writev02 process_vm_writev02
>   
>   prot_hsymlinks prot_hsymlinks
> diff --git a/testcases/kernel/syscalls/cma/process_vm01.c b/testcases/kernel/syscalls/cma/process_vm01.c
> index 16f14d66b..bfd5c5acb 100644
> --- a/testcases/kernel/syscalls/cma/process_vm01.c
> +++ b/testcases/kernel/syscalls/cma/process_vm01.c
> @@ -1,47 +1,18 @@
> +// 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) Linux Test Project, 2012
> + * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
>    */
>   
> -/*
> - * errno tests shared by process_vm_readv, process_vm_writev tests.
> +/*\
> + * [Description]
> + *
> + * Test errno codes in process_vm_readv and process_vm_writev syscalls.
>    */
> -#include <sys/types.h>
> -#include <sys/stat.h>
> -#include <sys/syscall.h>
> -#include <sys/uio.h>
> -#include <sys/wait.h>
> -#include <sys/mman.h>
> -#include <errno.h>
> -#include <signal.h>
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <string.h>
> -#include <unistd.h>
> -#include <limits.h>
> +
>   #include <pwd.h>
> -#include "config.h"
> -#include "test.h"
> -#include "safe_macros.h"
> +#include <stdlib.h>
> +#include "tst_test.h"
>   #include "lapi/syscalls.h"
>   
>   struct process_vm_params {
> @@ -56,137 +27,27 @@ struct process_vm_params {
>   	unsigned long flags;
>   };
>   
> -static int rflag;
> -static int wflag;
> -
> -static option_t options[] = {
> -	{"r", &rflag, NULL},
> -	{"w", &wflag, NULL},
> -	{NULL, NULL, NULL}
> -};
> -
> -static char TCID_readv[] = "process_vm_readv";
> -static char TCID_writev[] = "process_vm_writev";
> -char *TCID = "cma01";
> -int TST_TOTAL = 1;
> -static void (*cma_test_params) (struct process_vm_params * params) = NULL;
> -
> -static void setup(char *argv[]);
> -static void cleanup(void);
> -static void help(void);
> -
> -static void cma_test_params_read(struct process_vm_params *params);
> -static void cma_test_params_write(struct process_vm_params *params);
> -static void cma_test_errnos(void);
> -
> -int main(int argc, char *argv[])
> -{
> -	int lc;
> -
> -	tst_parse_opts(argc, argv, options, &help);
> -
> -	setup(argv);
> -	for (lc = 0; TEST_LOOPING(lc); lc++) {
> -		tst_count = 0;
> -		cma_test_errnos();
> -	}
> -	cleanup();
> -	tst_exit();
> -}
> -
> -static void setup(char *argv[])
> -{
> -	tst_require_root();
> -
> -	if (rflag && wflag)
> -		tst_brkm(TBROK, NULL, "Parameters -r -w can not be used"
> -			 " at the same time.");
> -	else if (rflag) {
> -		TCID = TCID_readv;
> -		cma_test_params = cma_test_params_read;
> -	} else if (wflag) {
> -		TCID = TCID_writev;
> -		cma_test_params = cma_test_params_write;
> -	} else
> -		tst_brkm(TBROK, NULL, "Parameter missing, required -r or -w.");
> -	TEST_PAUSE;
> -}
> -
> -static void cleanup(void)
> -{
> -}
> -
> -static void help(void)
> -{
> -	printf("  -r      Use process_vm_readv\n");
> -	printf("  -w      Use process_vm_writev\n");
> -}
> -
> -static void cma_test_params_read(struct process_vm_params *params)
> -{
> -	TEST(tst_syscall(__NR_process_vm_readv,
> -			 params->pid,
> -			 params->lvec, params->liovcnt,
> -			 params->rvec, params->riovcnt,
> -			 params->flags));
> -}
> -
> -static void cma_test_params_write(struct process_vm_params *params)
> -{
> -	TEST(tst_syscall(__NR_process_vm_writev,
> -			 params->pid,
> -			 params->lvec, params->liovcnt,
> -			 params->rvec, params->riovcnt,
> -			 params->flags));
> -}
> -
> -static int cma_check_ret(long expected_ret, long act_ret)
> -{
> -	if (expected_ret == act_ret) {
> -		tst_resm(TPASS, "expected ret success - "
> -			 "returned value = %ld", act_ret);
> -	} else {
> -		tst_resm(TFAIL, "unexpected failure - "
> -			 "returned value = %ld, expected: %ld",
> -			 act_ret, expected_ret);
> -		return 1;
> -	}
> -	return 0;
> -}
> -
> -static int cma_check_errno(long expected_errno)
> -{
> -	if (TEST_ERRNO == expected_errno)
> -		tst_resm(TPASS | TTERRNO, "expected failure");
> -	else if (TEST_ERRNO == 0) {
> -		tst_resm(TFAIL, "call succeeded unexpectedly");
> -		return 1;
> -	} else {
> -		tst_resm(TFAIL | TTERRNO, "unexpected failure - "
> -			 "expected = %ld : %s, actual",
> -			 expected_errno, strerror(expected_errno));
> -		return 2;
> -	}
> -	return 0;
> -}
> +static char *str_read;
> +static void (*test_params)(struct process_vm_params *params);
>   
> -static struct process_vm_params *cma_alloc_sane_params(void)
> +static struct process_vm_params *alloc_params(void)
>   {
>   	struct process_vm_params *sane_params;
>   	int len;
>   
>   	len = getpagesize();
> -	sane_params = SAFE_MALLOC(NULL, sizeof(struct process_vm_params));
> +
> +	sane_params = SAFE_MALLOC(sizeof(struct process_vm_params));
>   	sane_params->len = len;
> -	sane_params->ldummy = SAFE_MALLOC(NULL, len);
> -	sane_params->rdummy = SAFE_MALLOC(NULL, len);
> +	sane_params->ldummy = SAFE_MALLOC(len);
> +	sane_params->rdummy = SAFE_MALLOC(len);
>   
> -	sane_params->lvec = SAFE_MALLOC(NULL, sizeof(struct iovec));
> +	sane_params->lvec = SAFE_MALLOC(sizeof(struct process_vm_params));
>   	sane_params->lvec->iov_base = sane_params->ldummy;
>   	sane_params->lvec->iov_len = len;
>   	sane_params->liovcnt = 1;
>   
> -	sane_params->rvec = SAFE_MALLOC(NULL, sizeof(struct iovec));
> +	sane_params->rvec = SAFE_MALLOC(sizeof(struct process_vm_params));
>   	sane_params->rvec->iov_base = sane_params->rdummy;
>   	sane_params->rvec->iov_len = len;
>   	sane_params->riovcnt = 1;
> @@ -197,7 +58,7 @@ static struct process_vm_params *cma_alloc_sane_params(void)
>   	return sane_params;
>   }
>   
> -static void cma_free_params(struct process_vm_params *params)
> +static void free_params(struct process_vm_params *params)
>   {
>   	if (params) {
>   		free(params->ldummy);
> @@ -208,195 +69,244 @@ static void cma_free_params(struct process_vm_params *params)
>   	}
>   }
>   
> -static void cma_test_sane_params(void)
> +static void test_readv(struct process_vm_params *params)
> +{
> +	TEST(tst_syscall(__NR_process_vm_readv,
> +		params->pid,
> +		params->lvec, params->liovcnt,
> +		params->rvec, params->riovcnt,
> +		params->flags));
> +}
> +
> +static void test_writev(struct process_vm_params *params)
> +{
> +	TEST(tst_syscall(__NR_process_vm_writev,
> +		params->pid,
> +		params->lvec, params->liovcnt,
> +		params->rvec, params->riovcnt,
> +		params->flags));
> +}
> +
> +static void check_errno(long expected_errno)
> +{
> +	if (TST_ERR == expected_errno)
> +		tst_res(TPASS | TTERRNO, "expected failure");
> +	else if (TST_ERR == 0)
> +		tst_res(TFAIL, "call succeeded unexpectedly");
> +	else
> +		tst_res(TFAIL | TTERRNO, "unexpected failure - "
> +			"expected = %ld : %s, actual",
> +			expected_errno, strerror(expected_errno));
> +}
> +
> +static void test_sane_params(void)
>   {
>   	struct process_vm_params *sane_params;
>   
> -	sane_params = cma_alloc_sane_params();
> -	tst_resm(TINFO, "test_sane_params");
> -	cma_test_params(sane_params);
> -	cma_check_ret(sane_params->len, TEST_RETURN);
> -	cma_free_params(sane_params);
> +	tst_res(TINFO, "Testing sane parameters");
> +
> +	sane_params = alloc_params();
> +	test_params(sane_params);
> +	TST_EXP_EQ_LI(TST_RET, sane_params->len);
> +	free_params(sane_params);
>   }
>   
> -static void cma_test_flags(void)
> +static void test_flags(void)
>   {
>   	struct process_vm_params *params;
>   	long flags[] = { -INT_MAX, -1, 1, INT_MAX, 0 };
> -	int flags_size = sizeof(flags) / sizeof(flags[0]);
> +	int flags_size = ARRAY_SIZE(flags) / sizeof(flags[0]);
>   	int i;
>   
> -	params = cma_alloc_sane_params();
> +	params = alloc_params();
> +
>   	for (i = 0; i < flags_size; i++) {
>   		params->flags = flags[i];
> -		tst_resm(TINFO, "test_flags, flags=%ld", flags[i]);
> -		cma_test_params(params);
> +
> +		tst_res(TINFO, "Testing flags=%ld", flags[i]);
> +		test_params(params);
> +
>   		/* atm. only flags == 0 is allowed, everything else
> -		 * should fail with EINVAL */
> +		 * should fail with EINVAL
> +		 */
>   		if (flags[i] != 0) {
> -			cma_check_ret(-1, TEST_RETURN);
> -			cma_check_errno(EINVAL);
> +			TST_EXP_EQ_LI(TST_RET, -1);
> +			check_errno(EINVAL);
>   		} else {
> -			cma_check_ret(params->len, TEST_RETURN);
> +			TST_EXP_EQ_LI(TST_RET, params->len);
>   		}
>   	}
> -	cma_free_params(params);
> +
> +	free_params(params);
>   }
>   
> -static void cma_test_iov_len_overflow(void)
> +static void test_iov_len_overflow(void)
>   {
>   	struct process_vm_params *params;
> -	ssize_t maxlen = -1;
> -	params = cma_alloc_sane_params();
> -
> -	params->lvec->iov_len = maxlen;
> -	params->rvec->iov_len = maxlen;
> -	tst_resm(TINFO, "test_iov_len_overflow");
> -	cma_test_params(params);
> -	cma_check_ret(-1, TEST_RETURN);
> -	cma_check_errno(EINVAL);
> -	cma_free_params(params);
> +
> +	tst_res(TINFO, "Testing iov_len = -1");
> +
> +	params = alloc_params();
> +	params->lvec->iov_len = -1;
> +	params->rvec->iov_len = -1;
> +	test_params(params);
> +	TST_EXP_EQ_LI(TST_RET, -1);
> +	check_errno(EINVAL);
> +	free_params(params);
>   }
>   
> -static void cma_test_iov_invalid(void)
> +static void test_iov_invalid(void)
>   {
>   	struct process_vm_params *sane_params;
>   	struct process_vm_params params_copy;
>   
> -	sane_params = cma_alloc_sane_params();
> -	/* make a shallow copy we can 'damage' */
> +	sane_params = alloc_params();
>   
> +	tst_res(TINFO, "Testing lvec->iov_base = -1");
>   	params_copy = *sane_params;
> -	tst_resm(TINFO, "test_iov_invalid - lvec->iov_base");
>   	params_copy.lvec->iov_base = (void *)-1;
> -	cma_test_params(&params_copy);
> -	cma_check_ret(-1, TEST_RETURN);
> -	cma_check_errno(EFAULT);
> +	test_params(&params_copy);
> +	TST_EXP_EQ_LI(TST_RET, -1);
> +	check_errno(EFAULT);
>   
> +	tst_res(TINFO, "Testing rvec->iov_base = -1");
>   	params_copy = *sane_params;
> -	tst_resm(TINFO, "test_iov_invalid - rvec->iov_base");
>   	params_copy.rvec->iov_base = (void *)-1;
> -	cma_test_params(&params_copy);
> -	cma_check_ret(-1, TEST_RETURN);
> -	cma_check_errno(EFAULT);
> +	test_params(&params_copy);
> +	TST_EXP_EQ_LI(TST_RET, -1);
> +	check_errno(EFAULT);
>   
> +	tst_res(TINFO, "Testing lvec = -1");
>   	params_copy = *sane_params;
> -	tst_resm(TINFO, "test_iov_invalid - lvec");
>   	params_copy.lvec = (void *)-1;
> -	cma_test_params(&params_copy);
> -	cma_check_ret(-1, TEST_RETURN);
> -	cma_check_errno(EFAULT);
> +	test_params(&params_copy);
> +	TST_EXP_EQ_LI(TST_RET, -1);
> +	check_errno(EFAULT);
>   
> +	tst_res(TINFO, "Testing rvec = -1");
>   	params_copy = *sane_params;
> -	tst_resm(TINFO, "test_iov_invalid - rvec");
>   	params_copy.rvec = (void *)-1;
> -	cma_test_params(&params_copy);
> -	cma_check_ret(-1, TEST_RETURN);
> -	cma_check_errno(EFAULT);
> +	test_params(&params_copy);
> +	TST_EXP_EQ_LI(TST_RET, -1);
> +	check_errno(EFAULT);
>   
> -	cma_free_params(sane_params);
> +	free_params(sane_params);
>   }
>   
> -static void cma_test_invalid_pid(void)
> +static void test_invalid_pid(void)
>   {
>   	pid_t invalid_pid = -1;
>   	struct process_vm_params *params;
> +	struct process_vm_params params_copy;
> +
> +	params = alloc_params();
> +
> +	tst_res(TINFO, "Testing invalid PID");
> +	params_copy = *params;
> +	params_copy.pid = invalid_pid;
> +	test_params(&params_copy);
> +	TST_EXP_EQ_LI(TST_RET, -1);
> +	check_errno(ESRCH);
>   
> -	params = cma_alloc_sane_params();
> -	tst_resm(TINFO, "test_invalid_pid");
> -	params->pid = invalid_pid;
> -	cma_test_params(params);
> -	cma_check_ret(-1, TEST_RETURN);
> -	cma_check_errno(ESRCH);
> -	cma_free_params(params);
> -
> -	invalid_pid = tst_get_unused_pid(cleanup);
> -
> -	params = cma_alloc_sane_params();
> -	params->pid = invalid_pid;
> -	cma_test_params(params);
> -	cma_check_ret(-1, TEST_RETURN);
> -	cma_check_errno(ESRCH);
> -	cma_free_params(params);
> +	tst_res(TINFO, "Testing unused PID");
> +	params_copy = *params;
> +	invalid_pid = tst_get_unused_pid();
> +	params_copy.pid = invalid_pid;
> +	test_params(&params_copy);
> +	TST_EXP_EQ_LI(TST_RET, -1);
> +	check_errno(ESRCH);
> +
> +	free_params(params);
>   }
>   
> -static void cma_test_invalid_perm(void)
> +static void test_invalid_perm(void)
>   {
>   	char nobody_uid[] = "nobody";
>   	struct passwd *ltpuser;
> -	int status;
>   	struct process_vm_params *params;
>   	pid_t child_pid;
>   	pid_t parent_pid;
> -	int ret = 0;
> +	int status;
> +
> +	tst_res(TINFO, "Testing invalid permissions on given PID");
>   
> -	tst_resm(TINFO, "test_invalid_perm");
>   	parent_pid = getpid();
> -	child_pid = fork();
> -	switch (child_pid) {
> -	case -1:
> -		tst_brkm(TBROK | TERRNO, cleanup, "fork");
> -		break;
> -	case 0:
> -		ltpuser = getpwnam(nobody_uid);
> -		if (ltpuser == NULL)
> -			tst_brkm(TBROK | TERRNO, NULL, "getpwnam failed");
> -		SAFE_SETUID(NULL, ltpuser->pw_uid);
> -
> -		params = cma_alloc_sane_params();
> +	child_pid = SAFE_FORK();
> +	if (!child_pid) {
> +		ltpuser = SAFE_GETPWNAM(nobody_uid);
> +		SAFE_SETUID(ltpuser->pw_uid);
> +
> +		params = alloc_params();
>   		params->pid = parent_pid;
> -		cma_test_params(params);
> -		ret |= cma_check_ret(-1, TEST_RETURN);
> -		ret |= cma_check_errno(EPERM);
> -		cma_free_params(params);
> -		exit(ret);
> -	default:
> -		SAFE_WAITPID(cleanup, child_pid, &status, 0);
> -		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
> -			tst_resm(TFAIL, "child returns %d", status);
> +		test_params(params);
> +		TST_EXP_EQ_LI(TST_RET, -1);
> +		check_errno(EPERM);
> +		free_params(params);
> +		return;
>   	}
> +
> +	SAFE_WAITPID(child_pid, &status, 0);
>   }
>   
> -static void cma_test_invalid_protection(void)
> +static void test_invalid_protection(void)
>   {
>   	struct process_vm_params *sane_params;
>   	struct process_vm_params params_copy;
> -	void *p;
> -
> -	sane_params = cma_alloc_sane_params();
> -	/* make a shallow copy we can 'damage' */
> +	void *data;
> +	int len;
>   
> -	p = mmap(NULL, getpagesize(), PROT_NONE,
> -		 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
> -	if (p == MAP_FAILED)
> -		tst_brkm(TBROK | TERRNO, cleanup, "mmap");
> +	len = getpagesize();
> +	sane_params = alloc_params();
> +	data = SAFE_MMAP(NULL, len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
>   
> +	tst_res(TINFO, "Testing data with invalid protection (lvec)");
>   	params_copy = *sane_params;
> -	params_copy.lvec->iov_base = p;
> -	tst_resm(TINFO, "test_invalid_protection lvec");
> -	cma_test_params(&params_copy);
> -	cma_check_ret(-1, TEST_RETURN);
> -	cma_check_errno(EFAULT);
> +	params_copy.lvec->iov_base = data;
> +	test_params(&params_copy);
> +	TST_EXP_EQ_LI(TST_RET, -1);
> +	check_errno(EFAULT);
>   
> +	tst_res(TINFO, "Testing data with invalid protection (rvec)");
>   	params_copy = *sane_params;
> -	params_copy.rvec->iov_base = p;
> -	tst_resm(TINFO, "test_invalid_protection rvec");
> -	cma_test_params(&params_copy);
> -	cma_check_ret(-1, TEST_RETURN);
> -	cma_check_errno(EFAULT);
> +	params_copy.rvec->iov_base = data;
> +	test_params(&params_copy);
> +	TST_EXP_EQ_LI(TST_RET, -1);
> +	check_errno(EFAULT);
>   
> -	SAFE_MUNMAP(cleanup, p, getpagesize());
> +	SAFE_MUNMAP(data, len);
> +	free_params(sane_params);
> +}
>   
> -	cma_free_params(sane_params);
> +static void run(void)
> +{
> +	test_sane_params();
> +	test_flags();
> +	test_iov_len_overflow();
> +	test_iov_invalid();
> +	test_invalid_pid();
> +	test_invalid_perm();
> +	test_invalid_protection();
>   }
>   
> -static void cma_test_errnos(void)
> +static void setup(void)
>   {
> -	cma_test_sane_params();
> -	cma_test_flags();
> -	cma_test_iov_len_overflow();
> -	cma_test_iov_invalid();
> -	cma_test_invalid_pid();
> -	cma_test_invalid_perm();
> -	cma_test_invalid_protection();
> +	if (str_read) {
> +		tst_res(TINFO, "Selected process_vm_readv");
> +		test_params = test_readv;
> +	} else {
> +		tst_res(TINFO, "Selected process_vm_writev");
> +		test_params = test_writev;
> +	}
>   }
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.setup = setup,
> +	.forks_child = 1,
> +	.needs_checkpoints = 1,
> +	.needs_root = 1,
> +	.options = (struct tst_option[]) {
> +		{"r", &str_read, "Use process_vm_read instead of process_vm_write"},
> +		{},
> +	},
> +};



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

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

* Re: [LTP] [PATCH v1 1/3] Add process_madvise01 test
  2022-10-06 11:06 ` [LTP] [PATCH v1 1/3] Add process_madvise01 test Andrea Cervesato via ltp
@ 2022-10-18 11:51   ` Richard Palethorpe
  0 siblings, 0 replies; 11+ messages in thread
From: Richard Palethorpe @ 2022-10-18 11:51 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: ltp

Hello,

Andrea Cervesato via ltp <ltp@lists.linux.it> writes:

> Test for checking MADV_COLD support in process_madvise syscall.
>
> Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
> ---
>  testcases/kernel/syscalls/cma/.gitignore      |   1 +
>  testcases/kernel/syscalls/cma/cma.h           | 101 ++++++++++++
>  .../kernel/syscalls/cma/process_madvise01.c   | 153
> ++++++++++++++++++

Needs to be added to a runtest file

>  3 files changed, 255 insertions(+)
>  create mode 100644 testcases/kernel/syscalls/cma/cma.h
>  create mode 100644 testcases/kernel/syscalls/cma/process_madvise01.c
>
> diff --git a/testcases/kernel/syscalls/cma/.gitignore b/testcases/kernel/syscalls/cma/.gitignore
> index 1ee39d93e..846704294 100644
> --- a/testcases/kernel/syscalls/cma/.gitignore
> +++ b/testcases/kernel/syscalls/cma/.gitignore
> @@ -2,3 +2,4 @@
>  /process_vm_readv02
>  /process_vm_readv03
>  /process_vm_writev02
> +/process_madvise01
> diff --git a/testcases/kernel/syscalls/cma/cma.h b/testcases/kernel/syscalls/cma/cma.h
> new file mode 100644
> index 000000000..08a0d9319
> --- /dev/null
> +++ b/testcases/kernel/syscalls/cma/cma.h
> @@ -0,0 +1,101 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
> + */
> +
> +#ifndef CMA_H__
> +#define CMA_H__
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include "tst_safe_stdio.h"
> +
> +struct addr_mapping {
> +	int size;
> +	int rss;
> +	int pss;
> +	int shared_clean;
> +	int shared_dirty;
> +	int private_clean;
> +	int private_dirty;
> +	int referenced;
> +	int anonymous;
> +	int anon_huge_pages;
> +	int shmem_huge_pages;
> +	int shmem_pmd_mapped;
> +	int swap;
> +	int kernel_page_size;
> +	int mmu_page_size;
> +	int locked;
> +	int protection_key;
> +};
> +
> +static inline void read_address_mapping(unsigned long address, struct addr_mapping *mapping)
> +{
> +	FILE *f;
> +	int found = 0;
> +	char label[BUFSIZ];
> +	char line[BUFSIZ];
> +	char smaps[BUFSIZ];
> +	char ptr_str[BUFSIZ];
> +	int value;
> +
> +	snprintf(smaps, BUFSIZ, "/proc/%i/smaps", getpid());
> +	snprintf(ptr_str, BUFSIZ, "%lx", address);
> +
> +	f = SAFE_FOPEN(smaps, "r");
> +
> +	while (fgets(line, BUFSIZ, f) != NULL) {
> +		if (strncmp(ptr_str, line, strlen(ptr_str)) == 0)
> +			found = 1;
> +
> +		if (!found)
> +			continue;
> +
> +		if (found && strcmp(line, "VmFlags") >= 0)
> +			break;
> +
> +		if (sscanf(line, "%31[^:]: %d", label, &value) > 0) {
> +			if (strcmp(label, "Size") == 0)
> +				mapping->size = value;
> +			else if (strcmp(label, "Rss") == 0)
> +				mapping->rss = value;
> +			else if (strcmp(label, "Pss") == 0)
> +				mapping->pss = value;
> +			else if (strcmp(label, "Shared_Clean") == 0)
> +				mapping->shared_clean = value;
> +			else if (strcmp(label, "Shared_Dirty") == 0)
> +				mapping->shared_dirty = value;
> +			else if (strcmp(label, "Private_Clean") == 0)
> +				mapping->private_clean = value;
> +			else if (strcmp(label, "Private_Dirty") == 0)
> +				mapping->private_dirty = value;
> +			else if (strcmp(label, "Referenced") == 0)
> +				mapping->referenced = value;
> +			else if (strcmp(label, "Anonymous") == 0)
> +				mapping->anonymous = value;
> +			else if (strcmp(label, "AnonHugePages") == 0)
> +				mapping->anon_huge_pages = value;
> +			else if (strcmp(label, "ShmemHugePages") == 0)
> +				mapping->shmem_huge_pages = value;
> +			else if (strcmp(label, "ShmemPmdMapped") == 0)
> +				mapping->shmem_pmd_mapped = value;
> +			else if (strcmp(label, "Swap") == 0)
> +				mapping->swap = value;
> +			else if (strcmp(label, "KernelPageSize") == 0)
> +				mapping->kernel_page_size = value;
> +			else if (strcmp(label, "MMUPageSize") == 0)
> +				mapping->mmu_page_size = value;
> +			else if (strcmp(label, "Locked") == 0)
> +				mapping->locked = value;
> +			else if (strcmp(label, "ProtectionKey") == 0)
> +				mapping->protection_key = value;
> +		}
> +	}
> +
> +	SAFE_FCLOSE(f);
> +}
> +
> +#endif
> diff --git a/testcases/kernel/syscalls/cma/process_madvise01.c b/testcases/kernel/syscalls/cma/process_madvise01.c
> new file mode 100644
> index 000000000..d907d982c
> --- /dev/null
> +++ b/testcases/kernel/syscalls/cma/process_madvise01.c
> @@ -0,0 +1,153 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
> + */
> +
> +/*\
> + * [Description]
> + *
> + * Spawn child inside cgroup and set max memory. Allocate anonymous memory
> + * pages inside child and deactivate them with MADV_COLD. Then apply memory
> + * pressure and check if memory pages have been swapped out.
> + *
> + * The advice might be ignored for some pages in the range when it is
> + * not applicable, so test passes if swap memory increases after
> + * reclaiming memory with MADV_COLD.
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <sys/mman.h>
> +#include "tst_test.h"
> +#include "lapi/mmap.h"
> +#include "lapi/syscalls.h"
> +#include "cma.h"
> +
> +#define MEM_LIMIT	(50 * 1024 * 1024)
> +#define MEM_CHILD	(10 * 1024 * 1024)
> +#define MEM_PRESS	MEM_LIMIT
> +
> +static void **data_ptr;
> +
> +static void child_alloc(void)
> +{
> +	char *ptr;
> +	char *data;
> +	size_t cmem;
> +	size_t cswap;
> +	int freed = 1;
> +	struct addr_mapping map_before;
> +	struct addr_mapping map_after;
> +
> +	tst_res(TINFO, "Set memory limit");
> +
> +	SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid());
> +	SAFE_CG_PRINTF(tst_cg, "memory.max", "%d", MEM_LIMIT);

This is a hard limit, memory.high would probably be better (for V1 that
could be mapped to soft_limit_in_bytes).

> +
> +	tst_res(TINFO, "Allocate memory");
> +
> +	*data_ptr = SAFE_MMAP(NULL, MEM_CHILD,
> +			PROT_READ | PROT_WRITE,
> +			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> +	memset(*data_ptr, 'a', MEM_CHILD);
> +
> +	read_address_mapping((unsigned long)*data_ptr, &map_before);
> +
> +	SAFE_CG_SCANF(tst_cg, "memory.current", "%zu", &cmem);
> +	tst_res(TINFO, "Allocated %lu / %d bytes", cmem, MEM_LIMIT);
> +
> +	TST_CHECKPOINT_WAKE_AND_WAIT(0);
> +
> +	tst_res(TINFO, "Apply memory pressure");
> +
> +	data = SAFE_MMAP(NULL, MEM_PRESS,
> +			PROT_READ | PROT_WRITE,
> +			MAP_SHARED | MAP_ANONYMOUS, -1, 0);

This should cause swap to increase in any case. On a system with no swap
it causes the process to be killed by OOM (Unless we use memory.high).

Thinking about it, it may be better to create two mappings, one with the
advice and one without. Then check that the one with the advice is
swapped more than the one without (after applying pressure).

However we shouldn't use more than memory.high in any case.

> +	memset(data, 'b', MEM_PRESS);
> +	SAFE_MUNMAP(data, MEM_PRESS);
> +
> +	SAFE_CG_SCANF(tst_cg, "memory.swap.current", "%zu", &cswap);
> +	tst_res(TINFO, "Swap now contains %lu bytes", cswap);
> +
> +	for (ptr = *data_ptr; *ptr != '\0'; ptr++) {
> +		if (*ptr == 'a') {
> +			freed = 0;
> +			break;
> +		}
> +	}
> +
> +	if (freed) {
> +		tst_res(TFAIL, "Memory has been freed");
> +		return;
> +	}
> +
> +	read_address_mapping((unsigned long)*data_ptr, &map_after);
> +
> +	SAFE_MUNMAP(*data_ptr, MEM_CHILD);
> +
> +	if (map_before.swap < map_after.swap)
> +		tst_res(TPASS, "Memory has been swapped out");
> +	else
> +		tst_res(TFAIL, "Swap memory has decreased");
> +}
> +
> +static void setup(void)
> +{

We need to check if the system has swap available here (see madvise06)
and/or create a device to use as swap (see swapon test/syscall).

I suppose this could be useful for other tests and metadata so could be
added to the test struct.

> +	data_ptr = SAFE_MMAP(NULL, sizeof(void *),
> +			PROT_READ | PROT_WRITE,
> +			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> +}
> +
> +static void cleanup(void)
> +{
> +	if (*data_ptr)
> +		SAFE_MUNMAP(*data_ptr, MEM_CHILD);
> +
> +	if (data_ptr)
> +		SAFE_MUNMAP(data_ptr, sizeof(void *));
> +}
> +
> +static void run(void)
> +{
> +	int ret;
> +	int pidfd;
> +	pid_t pid_alloc;
> +	struct iovec vec;
> +
> +	pid_alloc = SAFE_FORK();
> +	if (!pid_alloc) {
> +		child_alloc();
> +		return;
> +	}
> +
> +	TST_CHECKPOINT_WAIT(0);
> +
> +	tst_res(TINFO, "Apply MADV_COLD advise rule");
> +
> +	pidfd = SAFE_PIDFD_OPEN(pid_alloc, 0);
> +
> +	vec.iov_base = *data_ptr;
> +	vec.iov_len = MEM_CHILD;
> +
> +	ret = tst_syscall(__NR_process_madvise, pidfd, &vec, 1UL,
> +			MADV_COLD, 0UL);
> +
> +	if (ret == -1)
> +		tst_brk(TBROK | TERRNO, "process_madvise failed");
> +
> +	if (ret != MEM_CHILD)
> +		tst_brk(TBROK, "process_madvise reclaimed only %d bytes", ret);
> +
> +	TST_CHECKPOINT_WAKE(0);
> +}
> +
> +static struct tst_test test = {
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.test_all = run,
> +	.forks_child = 1,
> +	.min_kver = "5.10",
> +	.needs_checkpoints = 1,
> +	.needs_cgroup_ver = TST_CG_V2,
> +	.needs_cgroup_ctrls = (const char *const []){ "memory", NULL },
> +};
> -- 
> 2.35.3


-- 
Thank you,
Richard.

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

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

* Re: [LTP] [PATCH v1 2/3] Add process_madvise02 test
  2022-10-06 11:06 ` [LTP] [PATCH v1 2/3] Add process_madvise02 test Andrea Cervesato via ltp
@ 2022-10-18 12:24   ` Richard Palethorpe
  2022-10-26  7:50     ` Andrea Cervesato via ltp
  0 siblings, 1 reply; 11+ messages in thread
From: Richard Palethorpe @ 2022-10-18 12:24 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: ltp

Hello,

Looks like largely the same problems as with the previous test. Let's
get that one merged then lessons learned from that can be applied to
this.

Andrea Cervesato via ltp <ltp@lists.linux.it> writes:

> Test for checking MADV_PAGEOUT functionality over anonymous memory in
> process_madvise syscall.
>
> Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
> ---
>  testcases/kernel/syscalls/cma/.gitignore      |   1 +
>  .../kernel/syscalls/cma/process_madvise02.c   | 128 ++++++++++++++++++
>  2 files changed, 129 insertions(+)
>  create mode 100644 testcases/kernel/syscalls/cma/process_madvise02.c
>
> diff --git a/testcases/kernel/syscalls/cma/.gitignore b/testcases/kernel/syscalls/cma/.gitignore
> index 846704294..47ae3e445 100644
> --- a/testcases/kernel/syscalls/cma/.gitignore
> +++ b/testcases/kernel/syscalls/cma/.gitignore
> @@ -3,3 +3,4 @@
>  /process_vm_readv03
>  /process_vm_writev02
>  /process_madvise01
> +/process_madvise02
> diff --git a/testcases/kernel/syscalls/cma/process_madvise02.c b/testcases/kernel/syscalls/cma/process_madvise02.c
> new file mode 100644
> index 000000000..9f42dd48a
> --- /dev/null
> +++ b/testcases/kernel/syscalls/cma/process_madvise02.c
> @@ -0,0 +1,128 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
> + */
> +
> +/*\
> + * [Description]
> + *
> + * Spawn child inside cgroup and set max memory. Allocate anonymous memory
> + * pages inside child and reclaim it with MADV_PAGEOUT. Then check if memory
> + * pages have been swapped out.
> + *
> + * The advice might be ignored for some pages in the range when it is
> + * not applicable, so test passes if swap memory increases after
> + * reclaiming memory with MADV_PAGEOUT.
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <sys/mman.h>
> +#include "tst_test.h"
> +#include "lapi/mmap.h"
> +#include "lapi/syscalls.h"
> +#include "cma.h"
> +
> +#define MEM_CHILD	(10 * 1024 * 1024)
> +
> +static void **data_ptr;
> +
> +static void child_alloc(void)
> +{
> +	char *ptr;
> +	int freed = 1;
> +	struct addr_mapping map_before;
> +	struct addr_mapping map_after;
> +
> +	tst_res(TINFO, "Allocate memory");
> +
> +	*data_ptr = SAFE_MMAP(NULL, MEM_CHILD,
> +			PROT_READ | PROT_WRITE,
> +			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> +	memset(*data_ptr, 'a', MEM_CHILD);
> +
> +	read_address_mapping((unsigned long)*data_ptr, &map_before);
> +
> +	TST_CHECKPOINT_WAKE_AND_WAIT(0);
> +
> +	for (ptr = *data_ptr; *ptr != '\0'; ptr++) {
> +		if (*ptr == 'a') {
> +			freed = 0;
> +			break;
> +		}
> +	}
> +
> +	if (freed) {
> +		tst_res(TFAIL, "Memory has been freed");
> +		return;
> +	}
> +
> +	read_address_mapping((unsigned long)*data_ptr, &map_after);
> +
> +	SAFE_MUNMAP(*data_ptr, MEM_CHILD);
> +	*data_ptr = NULL;
> +
> +	if (map_before.swap < map_after.swap)
> +		tst_res(TPASS, "Memory has been swapped out");
> +	else
> +		tst_res(TFAIL, "Swap memory has decreased");
> +}
> +
> +static void setup(void)
> +{
> +	data_ptr = SAFE_MMAP(NULL, sizeof(void *),
> +			PROT_READ | PROT_WRITE,
> +			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> +}
> +
> +static void cleanup(void)
> +{
> +	if (*data_ptr)
> +		SAFE_MUNMAP(*data_ptr, MEM_CHILD);
> +
> +	if (data_ptr)
> +		SAFE_MUNMAP(data_ptr, sizeof(void *));
> +}
> +
> +static void run(void)
> +{
> +	int ret;
> +	int pidfd;
> +	pid_t pid_alloc;
> +	struct iovec vec;
> +
> +	pid_alloc = SAFE_FORK();
> +	if (!pid_alloc) {
> +		child_alloc();
> +		return;
> +	}
> +
> +	TST_CHECKPOINT_WAIT(0);
> +
> +	tst_res(TINFO, "Apply MADV_PAGEOUT advise rule");
> +
> +	pidfd = SAFE_PIDFD_OPEN(pid_alloc, 0);
> +
> +	vec.iov_base = *data_ptr;
> +	vec.iov_len = MEM_CHILD;
> +
> +	ret = tst_syscall(__NR_process_madvise, pidfd, &vec, 1UL,
> +			MADV_PAGEOUT, 0UL);
> +
> +	if (ret == -1)
> +		tst_brk(TBROK | TERRNO, "process_madvise failed");
> +
> +	if (ret != MEM_CHILD)
> +		tst_brk(TBROK, "process_madvise reclaimed only %d bytes", ret);
> +
> +	TST_CHECKPOINT_WAKE(0);
> +}
> +
> +static struct tst_test test = {
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.test_all = run,
> +	.forks_child = 1,
> +	.min_kver = "5.10",
> +	.needs_checkpoints = 1,
> +};
> -- 
> 2.35.3


-- 
Thank you,
Richard.

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

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

* Re: [LTP] [PATCH v1 3/3] Add process_madvise03 test
  2022-10-06 11:06 ` [LTP] [PATCH v1 3/3] Add process_madvise03 test Andrea Cervesato via ltp
@ 2022-10-18 12:29   ` Richard Palethorpe
  2022-10-18 12:49     ` Richard Palethorpe
  0 siblings, 1 reply; 11+ messages in thread
From: Richard Palethorpe @ 2022-10-18 12:29 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: ltp

Hello,

Andrea Cervesato via ltp <ltp@lists.linux.it> writes:

> Test for checking MADV_PAGEOUT functionality over memory-mapped file
> in process_madvise syscall.

So this one doesn't need swap, but it has some other issues.

>
> Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
> ---
>  testcases/kernel/syscalls/cma/.gitignore      |   1 +
>  .../kernel/syscalls/cma/process_madvise03.c   | 139 ++++++++++++++++++
>  2 files changed, 140 insertions(+)
>  create mode 100644 testcases/kernel/syscalls/cma/process_madvise03.c
>
> diff --git a/testcases/kernel/syscalls/cma/.gitignore b/testcases/kernel/syscalls/cma/.gitignore
> index 47ae3e445..147b03c48 100644
> --- a/testcases/kernel/syscalls/cma/.gitignore
> +++ b/testcases/kernel/syscalls/cma/.gitignore
> @@ -4,3 +4,4 @@
>  /process_vm_writev02
>  /process_madvise01
>  /process_madvise02
> +/process_madvise03
> diff --git a/testcases/kernel/syscalls/cma/process_madvise03.c b/testcases/kernel/syscalls/cma/process_madvise03.c
> new file mode 100644
> index 000000000..3f12ef530
> --- /dev/null
> +++ b/testcases/kernel/syscalls/cma/process_madvise03.c
> @@ -0,0 +1,139 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
> + */
> +
> +/*\
> + * [Description]
> + *
> + * Spawn child inside cgroup and set max memory. Allocate file-backed memory
> + * pages inside child and reclaim it with MADV_PAGEOUT. Then check if memory
> + * pages have been written back to the backing storage.
> + *
> + * The advice might be ignored for some pages in the range when it is
> + * not applicable, so test passes if pages mapped in RAM decrease after
> + * reclaiming memory with MADV_PAGEOUT and RAM doesn't contain
> + * reclaimed memory anymore.
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <sys/mman.h>
> +#include "tst_test.h"
> +#include "lapi/mmap.h"
> +#include "lapi/syscalls.h"
> +#include "cma.h"
> +
> +#define MEM_CHILD	(10 * 1024 * 1024)
> +
> +static char *filename = "file.bin";
> +static void **data_ptr;
> +
> +static void child_alloc(void)
> +{
> +	int fd;
> +	char *ptr;
> +	int freed = 1;
> +	struct addr_mapping map_before;
> +	struct addr_mapping map_after;
> +
> +	tst_res(TINFO, "Allocate file-backed memory");
> +
> +	fd = SAFE_OPEN(filename, O_CREAT | O_RDWR);
> +	SAFE_FTRUNCATE(fd, MEM_CHILD);
> +
> +	*data_ptr = SAFE_MMAP(NULL, MEM_CHILD,
> +			PROT_READ | PROT_WRITE,
> +			MAP_SHARED, fd, 0);
> +
> +	tst_res(TINFO, "Dirty memory");
> +	memset(*data_ptr, 'a', MEM_CHILD);
> +
> +	read_address_mapping((unsigned long)*data_ptr, &map_before);
> +
> +	TST_CHECKPOINT_WAKE_AND_WAIT(0);
> +
> +	for (ptr = *data_ptr; *ptr != '\0'; ptr++) {
> +		if (*ptr == 'a') {
> +			freed = 0;
> +			break;
> +		}
> +	}

This will loop once, or?

> +
> +	if (freed) {
> +		tst_res(TFAIL, "Memory has been freed");

We'll probably get a segfault or sigbus if its unmapped somehow. I guess
you could do a memcmp on the range to test that it didn't randomly
change though.

Otherwise this one looks good.

-- 
Thank you,
Richard.

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

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

* Re: [LTP] [PATCH v1 3/3] Add process_madvise03 test
  2022-10-18 12:29   ` Richard Palethorpe
@ 2022-10-18 12:49     ` Richard Palethorpe
  0 siblings, 0 replies; 11+ messages in thread
From: Richard Palethorpe @ 2022-10-18 12:49 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: ltp


Richard Palethorpe <rpalethorpe@suse.de> writes:

> Hello,
>
> Andrea Cervesato via ltp <ltp@lists.linux.it> writes:
>
>> Test for checking MADV_PAGEOUT functionality over memory-mapped file
>> in process_madvise syscall.
>
> So this one doesn't need swap, but it has some other issues.
>
>>
>> Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
>> ---
>>  testcases/kernel/syscalls/cma/.gitignore      |   1 +
>>  .../kernel/syscalls/cma/process_madvise03.c   | 139 ++++++++++++++++++
>>  2 files changed, 140 insertions(+)
>>  create mode 100644 testcases/kernel/syscalls/cma/process_madvise03.c
>>
>> diff --git a/testcases/kernel/syscalls/cma/.gitignore b/testcases/kernel/syscalls/cma/.gitignore
>> index 47ae3e445..147b03c48 100644
>> --- a/testcases/kernel/syscalls/cma/.gitignore
>> +++ b/testcases/kernel/syscalls/cma/.gitignore
>> @@ -4,3 +4,4 @@
>>  /process_vm_writev02
>>  /process_madvise01
>>  /process_madvise02
>> +/process_madvise03
>> diff --git a/testcases/kernel/syscalls/cma/process_madvise03.c b/testcases/kernel/syscalls/cma/process_madvise03.c
>> new file mode 100644
>> index 000000000..3f12ef530
>> --- /dev/null
>> +++ b/testcases/kernel/syscalls/cma/process_madvise03.c
>> @@ -0,0 +1,139 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
>> + */
>> +
>> +/*\
>> + * [Description]
>> + *
>> + * Spawn child inside cgroup and set max memory. Allocate file-backed memory
>> + * pages inside child and reclaim it with MADV_PAGEOUT. Then check if memory
>> + * pages have been written back to the backing storage.

Actually, one more thing. You don't check if it has been written to the
backing store and it's quite hard to check for this.

At best you could reopen the file in the parent and check the contents
are correct. Otherwise it requires checking the page cache has been
discarded using a side channel (e.g. timing loads).

So I would just not bother for this test.

Also process_madvise returns the number of bytes *advised* not what was
actually reclaimed. Even that is not guaranteed to be the same as the
amount requested.

-- 
Thank you,
Richard.

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

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

* Re: [LTP] [PATCH v1 2/3] Add process_madvise02 test
  2022-10-18 12:24   ` Richard Palethorpe
@ 2022-10-26  7:50     ` Andrea Cervesato via ltp
  0 siblings, 0 replies; 11+ messages in thread
From: Andrea Cervesato via ltp @ 2022-10-26  7:50 UTC (permalink / raw)
  To: rpalethorpe; +Cc: ltp

Hi!

On 10/18/22 14:24, Richard Palethorpe wrote:
> Hello,
>
> Looks like largely the same problems as with the previous test. Let's
> get that one merged then lessons learned from that can be applied to
> this.
Besides the "memory.high" change I see a big difference from MADV_COLD 
test. That is MADV_PAGEOUT will swap pages when advice is applied and so 
it's easier to check if advice worked properly or not.
> Andrea Cervesato via ltp <ltp@lists.linux.it> writes:
>
>> Test for checking MADV_PAGEOUT functionality over anonymous memory in
>> process_madvise syscall.
>>
>> Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
>> ---
>>   testcases/kernel/syscalls/cma/.gitignore      |   1 +
>>   .../kernel/syscalls/cma/process_madvise02.c   | 128 ++++++++++++++++++
>>   2 files changed, 129 insertions(+)
>>   create mode 100644 testcases/kernel/syscalls/cma/process_madvise02.c
>>
>> diff --git a/testcases/kernel/syscalls/cma/.gitignore b/testcases/kernel/syscalls/cma/.gitignore
>> index 846704294..47ae3e445 100644
>> --- a/testcases/kernel/syscalls/cma/.gitignore
>> +++ b/testcases/kernel/syscalls/cma/.gitignore
>> @@ -3,3 +3,4 @@
>>   /process_vm_readv03
>>   /process_vm_writev02
>>   /process_madvise01
>> +/process_madvise02
>> diff --git a/testcases/kernel/syscalls/cma/process_madvise02.c b/testcases/kernel/syscalls/cma/process_madvise02.c
>> new file mode 100644
>> index 000000000..9f42dd48a
>> --- /dev/null
>> +++ b/testcases/kernel/syscalls/cma/process_madvise02.c
>> @@ -0,0 +1,128 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Copyright (C) 2022 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
>> + */
>> +
>> +/*\
>> + * [Description]
>> + *
>> + * Spawn child inside cgroup and set max memory. Allocate anonymous memory
>> + * pages inside child and reclaim it with MADV_PAGEOUT. Then check if memory
>> + * pages have been swapped out.
>> + *
>> + * The advice might be ignored for some pages in the range when it is
>> + * not applicable, so test passes if swap memory increases after
>> + * reclaiming memory with MADV_PAGEOUT.
>> + */
>> +
>> +#define _GNU_SOURCE
>> +
>> +#include <sys/mman.h>
>> +#include "tst_test.h"
>> +#include "lapi/mmap.h"
>> +#include "lapi/syscalls.h"
>> +#include "cma.h"
>> +
>> +#define MEM_CHILD	(10 * 1024 * 1024)
>> +
>> +static void **data_ptr;
>> +
>> +static void child_alloc(void)
>> +{
>> +	char *ptr;
>> +	int freed = 1;
>> +	struct addr_mapping map_before;
>> +	struct addr_mapping map_after;
>> +
>> +	tst_res(TINFO, "Allocate memory");
>> +
>> +	*data_ptr = SAFE_MMAP(NULL, MEM_CHILD,
>> +			PROT_READ | PROT_WRITE,
>> +			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
>> +	memset(*data_ptr, 'a', MEM_CHILD);
>> +
>> +	read_address_mapping((unsigned long)*data_ptr, &map_before);
>> +
>> +	TST_CHECKPOINT_WAKE_AND_WAIT(0);
>> +
>> +	for (ptr = *data_ptr; *ptr != '\0'; ptr++) {
>> +		if (*ptr == 'a') {
>> +			freed = 0;
>> +			break;
>> +		}
>> +	}
>> +
>> +	if (freed) {
>> +		tst_res(TFAIL, "Memory has been freed");
>> +		return;
>> +	}
>> +
>> +	read_address_mapping((unsigned long)*data_ptr, &map_after);
>> +
>> +	SAFE_MUNMAP(*data_ptr, MEM_CHILD);
>> +	*data_ptr = NULL;
>> +
>> +	if (map_before.swap < map_after.swap)
>> +		tst_res(TPASS, "Memory has been swapped out");
>> +	else
>> +		tst_res(TFAIL, "Swap memory has decreased");
>> +}
>> +
>> +static void setup(void)
>> +{
>> +	data_ptr = SAFE_MMAP(NULL, sizeof(void *),
>> +			PROT_READ | PROT_WRITE,
>> +			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
>> +}
>> +
>> +static void cleanup(void)
>> +{
>> +	if (*data_ptr)
>> +		SAFE_MUNMAP(*data_ptr, MEM_CHILD);
>> +
>> +	if (data_ptr)
>> +		SAFE_MUNMAP(data_ptr, sizeof(void *));
>> +}
>> +
>> +static void run(void)
>> +{
>> +	int ret;
>> +	int pidfd;
>> +	pid_t pid_alloc;
>> +	struct iovec vec;
>> +
>> +	pid_alloc = SAFE_FORK();
>> +	if (!pid_alloc) {
>> +		child_alloc();
>> +		return;
>> +	}
>> +
>> +	TST_CHECKPOINT_WAIT(0);
>> +
>> +	tst_res(TINFO, "Apply MADV_PAGEOUT advise rule");
>> +
>> +	pidfd = SAFE_PIDFD_OPEN(pid_alloc, 0);
>> +
>> +	vec.iov_base = *data_ptr;
>> +	vec.iov_len = MEM_CHILD;
>> +
>> +	ret = tst_syscall(__NR_process_madvise, pidfd, &vec, 1UL,
>> +			MADV_PAGEOUT, 0UL);
>> +
>> +	if (ret == -1)
>> +		tst_brk(TBROK | TERRNO, "process_madvise failed");
>> +
>> +	if (ret != MEM_CHILD)
>> +		tst_brk(TBROK, "process_madvise reclaimed only %d bytes", ret);
>> +
>> +	TST_CHECKPOINT_WAKE(0);
>> +}
>> +
>> +static struct tst_test test = {
>> +	.setup = setup,
>> +	.cleanup = cleanup,
>> +	.test_all = run,
>> +	.forks_child = 1,
>> +	.min_kver = "5.10",
>> +	.needs_checkpoints = 1,
>> +};
>> -- 
>> 2.35.3
>
Andrea


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

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

end of thread, other threads:[~2022-10-26  7:52 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-06 11:06 [LTP] [PATCH v1 0/3] Add process_madvise support Andrea Cervesato via ltp
2022-10-06 11:06 ` [LTP] [PATCH v1 1/3] Add process_madvise01 test Andrea Cervesato via ltp
2022-10-18 11:51   ` Richard Palethorpe
2022-10-06 11:06 ` [LTP] [PATCH v1] Rewrite process_vm01 test using new LTP API Andrea Cervesato via ltp
2022-10-06 11:10   ` Andrea Cervesato via ltp
2022-10-06 11:06 ` [LTP] [PATCH v1 2/3] Add process_madvise02 test Andrea Cervesato via ltp
2022-10-18 12:24   ` Richard Palethorpe
2022-10-26  7:50     ` Andrea Cervesato via ltp
2022-10-06 11:06 ` [LTP] [PATCH v1 3/3] Add process_madvise03 test Andrea Cervesato via ltp
2022-10-18 12:29   ` Richard Palethorpe
2022-10-18 12:49     ` Richard Palethorpe

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.