0001
0002
0003
0004
0005 #define _GNU_SOURCE
0006 #include <errno.h>
0007 #include <stdbool.h>
0008 #include <stdio.h>
0009 #include <stdlib.h>
0010 #include <sys/wait.h>
0011 #include <unistd.h>
0012
0013 #include "util.h"
0014
0015 #include "../kselftest.h"
0016
0017 #ifndef __NR_pidfd_open
0018 #define __NR_pidfd_open -1
0019 #endif
0020
0021 #ifndef __NR_process_mrelease
0022 #define __NR_process_mrelease -1
0023 #endif
0024
0025 #define MB(x) (x << 20)
0026 #define MAX_SIZE_MB 1024
0027
0028 static int alloc_noexit(unsigned long nr_pages, int pipefd)
0029 {
0030 int ppid = getppid();
0031 int timeout = 10;
0032 unsigned long i;
0033 char *buf;
0034
0035 buf = (char *)mmap(NULL, nr_pages * PAGE_SIZE, PROT_READ | PROT_WRITE,
0036 MAP_PRIVATE | MAP_ANON, 0, 0);
0037 if (buf == MAP_FAILED) {
0038 perror("mmap failed, halting the test");
0039 return KSFT_FAIL;
0040 }
0041
0042 for (i = 0; i < nr_pages; i++)
0043 *((unsigned long *)(buf + (i * PAGE_SIZE))) = i;
0044
0045
0046 if (write(pipefd, "", 1) < 0) {
0047 perror("write");
0048 return KSFT_FAIL;
0049 }
0050
0051
0052 while (getppid() == ppid && timeout > 0) {
0053 sleep(1);
0054 timeout--;
0055 }
0056
0057 munmap(buf, nr_pages * PAGE_SIZE);
0058
0059 return (timeout > 0) ? KSFT_PASS : KSFT_FAIL;
0060 }
0061
0062
0063 static void run_negative_tests(int pidfd)
0064 {
0065 int res;
0066
0067 if (!syscall(__NR_process_mrelease, pidfd, (unsigned int)-1) ||
0068 errno != EINVAL) {
0069 res = (errno == ENOSYS ? KSFT_SKIP : KSFT_FAIL);
0070 perror("process_mrelease with wrong flags");
0071 exit(res);
0072 }
0073
0074
0075
0076
0077 if (!syscall(__NR_process_mrelease, pidfd, 0) || errno != EINVAL) {
0078 res = (errno == ENOSYS ? KSFT_SKIP : KSFT_FAIL);
0079 perror("process_mrelease on a live process");
0080 exit(res);
0081 }
0082 }
0083
0084 static int child_main(int pipefd[], size_t size)
0085 {
0086 int res;
0087
0088
0089 close(pipefd[0]);
0090 res = alloc_noexit(MB(size) / PAGE_SIZE, pipefd[1]);
0091 close(pipefd[1]);
0092 return res;
0093 }
0094
0095 int main(void)
0096 {
0097 int pipefd[2], pidfd;
0098 bool success, retry;
0099 size_t size;
0100 pid_t pid;
0101 char byte;
0102 int res;
0103
0104
0105 if (!syscall(__NR_process_mrelease, -1, 0) || errno != EBADF) {
0106 res = (errno == ENOSYS ? KSFT_SKIP : KSFT_FAIL);
0107 perror("process_mrelease with wrong pidfd");
0108 exit(res);
0109 }
0110
0111
0112 size = 1;
0113 retry:
0114
0115
0116
0117
0118 if (pipe(pipefd)) {
0119 perror("pipe");
0120 exit(KSFT_FAIL);
0121 }
0122 pid = fork();
0123 if (pid < 0) {
0124 perror("fork");
0125 close(pipefd[0]);
0126 close(pipefd[1]);
0127 exit(KSFT_FAIL);
0128 }
0129
0130 if (pid == 0) {
0131
0132 res = child_main(pipefd, size);
0133 exit(res);
0134 }
0135
0136
0137
0138
0139
0140 close(pipefd[1]);
0141
0142 res = read(pipefd[0], &byte, 1);
0143 close(pipefd[0]);
0144 if (res < 0) {
0145 perror("read");
0146 if (!kill(pid, SIGKILL))
0147 waitpid(pid, NULL, 0);
0148 exit(KSFT_FAIL);
0149 }
0150
0151 pidfd = syscall(__NR_pidfd_open, pid, 0);
0152 if (pidfd < 0) {
0153 perror("pidfd_open");
0154 if (!kill(pid, SIGKILL))
0155 waitpid(pid, NULL, 0);
0156 exit(KSFT_FAIL);
0157 }
0158
0159
0160 run_negative_tests(pidfd);
0161
0162 if (kill(pid, SIGKILL)) {
0163 res = (errno == ENOSYS ? KSFT_SKIP : KSFT_FAIL);
0164 perror("kill");
0165 exit(res);
0166 }
0167
0168 success = (syscall(__NR_process_mrelease, pidfd, 0) == 0);
0169 if (!success) {
0170
0171
0172
0173
0174
0175
0176
0177 if (errno == ESRCH) {
0178 retry = (size <= MAX_SIZE_MB);
0179 } else {
0180 res = (errno == ENOSYS ? KSFT_SKIP : KSFT_FAIL);
0181 perror("process_mrelease");
0182 waitpid(pid, NULL, 0);
0183 exit(res);
0184 }
0185 }
0186
0187
0188 if (waitpid(pid, NULL, 0) < 0) {
0189 perror("waitpid");
0190 exit(KSFT_FAIL);
0191 }
0192 close(pidfd);
0193
0194 if (!success) {
0195 if (retry) {
0196 size *= 2;
0197 goto retry;
0198 }
0199 printf("All process_mrelease attempts failed!\n");
0200 exit(KSFT_FAIL);
0201 }
0202
0203 printf("Success reaping a child with %zuMB of memory allocations\n",
0204 size);
0205 return KSFT_PASS;
0206 }