drm/panel: panel-himax-hx83102: support for csot-pna957qt1-1 MIPI-DSI panel
[drm/drm-misc.git] / tools / testing / selftests / mm / mrelease_test.c
blob100370a7111df58eae8c188170f64f12ad6e7bb6
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright 2022 Google LLC
4 */
5 #define _GNU_SOURCE
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/syscall.h>
11 #include <sys/wait.h>
12 #include <unistd.h>
13 #include <asm-generic/unistd.h>
14 #include "vm_util.h"
15 #include "../kselftest.h"
17 #define MB(x) (x << 20)
18 #define MAX_SIZE_MB 1024
20 static int alloc_noexit(unsigned long nr_pages, int pipefd)
22 int ppid = getppid();
23 int timeout = 10; /* 10sec timeout to get killed */
24 unsigned long i;
25 char *buf;
27 buf = (char *)mmap(NULL, nr_pages * psize(), PROT_READ | PROT_WRITE,
28 MAP_PRIVATE | MAP_ANON, 0, 0);
29 if (buf == MAP_FAILED)
30 ksft_exit_fail_msg("mmap failed, halting the test: %s\n", strerror(errno));
32 for (i = 0; i < nr_pages; i++)
33 *((unsigned long *)(buf + (i * psize()))) = i;
35 /* Signal the parent that the child is ready */
36 if (write(pipefd, "", 1) < 0)
37 ksft_exit_fail_msg("write: %s\n", strerror(errno));
39 /* Wait to be killed (when reparenting happens) */
40 while (getppid() == ppid && timeout > 0) {
41 sleep(1);
42 timeout--;
45 munmap(buf, nr_pages * psize());
47 return (timeout > 0) ? KSFT_PASS : KSFT_FAIL;
50 /* The process_mrelease calls in this test are expected to fail */
51 static void run_negative_tests(int pidfd)
53 /* Test invalid flags. Expect to fail with EINVAL error code. */
54 if (!syscall(__NR_process_mrelease, pidfd, (unsigned int)-1) ||
55 errno != EINVAL) {
56 ksft_exit_fail_msg("process_mrelease with wrong flags: %s\n", strerror(errno));
59 * Test reaping while process is alive with no pending SIGKILL.
60 * Expect to fail with EINVAL error code.
62 if (!syscall(__NR_process_mrelease, pidfd, 0) || errno != EINVAL)
63 ksft_exit_fail_msg("process_mrelease on a live process: %s\n", strerror(errno));
66 static int child_main(int pipefd[], size_t size)
68 int res;
70 /* Allocate and fault-in memory and wait to be killed */
71 close(pipefd[0]);
72 res = alloc_noexit(MB(size) / psize(), pipefd[1]);
73 close(pipefd[1]);
74 return res;
77 int main(void)
79 int pipefd[2], pidfd;
80 bool success, retry;
81 size_t size;
82 pid_t pid;
83 char byte;
84 int res;
86 ksft_print_header();
87 ksft_set_plan(1);
89 /* Test a wrong pidfd */
90 if (!syscall(__NR_process_mrelease, -1, 0) || errno != EBADF) {
91 if (errno == ENOSYS) {
92 ksft_test_result_skip("process_mrelease not implemented\n");
93 ksft_finished();
94 } else {
95 ksft_exit_fail_msg("process_mrelease with wrong pidfd: %s",
96 strerror(errno));
100 /* Start the test with 1MB child memory allocation */
101 size = 1;
102 retry:
104 * Pipe for the child to signal when it's done allocating
105 * memory
107 if (pipe(pipefd))
108 ksft_exit_fail_msg("pipe: %s\n", strerror(errno));
110 pid = fork();
111 if (pid < 0) {
112 close(pipefd[0]);
113 close(pipefd[1]);
114 ksft_exit_fail_msg("fork: %s\n", strerror(errno));
117 if (pid == 0) {
118 /* Child main routine */
119 res = child_main(pipefd, size);
120 exit(res);
124 * Parent main routine:
125 * Wait for the child to finish allocations, then kill and reap
127 close(pipefd[1]);
128 /* Block until the child is ready */
129 res = read(pipefd[0], &byte, 1);
130 close(pipefd[0]);
131 if (res < 0) {
132 if (!kill(pid, SIGKILL))
133 waitpid(pid, NULL, 0);
134 ksft_exit_fail_msg("read: %s\n", strerror(errno));
137 pidfd = syscall(__NR_pidfd_open, pid, 0);
138 if (pidfd < 0) {
139 if (!kill(pid, SIGKILL))
140 waitpid(pid, NULL, 0);
141 ksft_exit_fail_msg("pidfd_open: %s\n", strerror(errno));
144 /* Run negative tests which require a live child */
145 run_negative_tests(pidfd);
147 if (kill(pid, SIGKILL))
148 ksft_exit_fail_msg("kill: %s\n", strerror(errno));
150 success = (syscall(__NR_process_mrelease, pidfd, 0) == 0);
151 if (!success) {
153 * If we failed to reap because the child exited too soon,
154 * before we could call process_mrelease. Double child's memory
155 * which causes it to spend more time on cleanup and increases
156 * our chances of reaping its memory before it exits.
157 * Retry until we succeed or reach MAX_SIZE_MB.
159 if (errno == ESRCH) {
160 retry = (size <= MAX_SIZE_MB);
161 } else {
162 waitpid(pid, NULL, 0);
163 ksft_exit_fail_msg("process_mrelease: %s\n", strerror(errno));
167 /* Cleanup to prevent zombies */
168 if (waitpid(pid, NULL, 0) < 0)
169 ksft_exit_fail_msg("waitpid: %s\n", strerror(errno));
171 close(pidfd);
173 if (!success) {
174 if (retry) {
175 size *= 2;
176 goto retry;
178 ksft_exit_fail_msg("All process_mrelease attempts failed!\n");
181 ksft_test_result_pass("Success reaping a child with %zuMB of memory allocations\n",
182 size);
183 ksft_finished();