1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright 2022 Google LLC
10 #include <sys/syscall.h>
13 #include <asm-generic/unistd.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
)
23 int timeout
= 10; /* 10sec timeout to get killed */
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) {
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) ||
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
)
70 /* Allocate and fault-in memory and wait to be killed */
72 res
= alloc_noexit(MB(size
) / psize(), pipefd
[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");
95 ksft_exit_fail_msg("process_mrelease with wrong pidfd: %s",
100 /* Start the test with 1MB child memory allocation */
104 * Pipe for the child to signal when it's done allocating
108 ksft_exit_fail_msg("pipe: %s\n", strerror(errno
));
114 ksft_exit_fail_msg("fork: %s\n", strerror(errno
));
118 /* Child main routine */
119 res
= child_main(pipefd
, size
);
124 * Parent main routine:
125 * Wait for the child to finish allocations, then kill and reap
128 /* Block until the child is ready */
129 res
= read(pipefd
[0], &byte
, 1);
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);
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);
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
);
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
));
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",