Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'core-process-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux

Pull pidfd/waitid updates from Christian Brauner:
"This contains two features and various tests.

First, it adds support for waiting on process through pidfds by adding
the P_PIDFD type to the waitid() syscall. This completes the basic
functionality of the pidfd api (cf. [1]). In the meantime we also have
a new adition to the userspace projects that make use of the pidfd
api. The qt project was nice enough to send a mail pointing out that
they have a pr up to switch to the pidfd api (cf. [2]).

Second, this tag contains an extension to the waitid() syscall to make
it possible to wait on the current process group in a race free manner
(even though the actual problem is very unlikely) by specifing 0
together with the P_PGID type. This extension traces back to a
discussion on the glibc development mailing list.

There are also a range of tests for the features above. Additionally,
the test-suite which detected the pidfd-polling race we fixed in [3]
is included in this tag"

[1] https://lwn.net/Articles/794707/
[2] https://codereview.qt-project.org/c/qt/qtbase/+/108456
[3] commit b191d6491be6 ("pidfd: fix a poll race when setting exit_state")

* tag 'core-process-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux:
waitid: Add support for waiting for the current process group
tests: add pidfd poll tests
tests: move common definitions and functions into pidfd.h
pidfd: add pidfd_wait tests
pidfd: add P_PIDFD to waitid()

+473 -26
+4
include/linux/pid.h
··· 72 72 73 73 extern const struct file_operations pidfd_fops; 74 74 75 + struct file; 76 + 77 + extern struct pid *pidfd_pid(const struct file *file); 78 + 75 79 static inline struct pid *get_pid(struct pid *pid) 76 80 { 77 81 if (pid)
+1
include/uapi/linux/wait.h
··· 17 17 #define P_ALL 0 18 18 #define P_PID 1 19 19 #define P_PGID 2 20 + #define P_PIDFD 3 20 21 21 22 22 23 #endif /* _UAPI_LINUX_WAIT_H */
+34 -4
kernel/exit.c
··· 1554 1554 return retval; 1555 1555 } 1556 1556 1557 + static struct pid *pidfd_get_pid(unsigned int fd) 1558 + { 1559 + struct fd f; 1560 + struct pid *pid; 1561 + 1562 + f = fdget(fd); 1563 + if (!f.file) 1564 + return ERR_PTR(-EBADF); 1565 + 1566 + pid = pidfd_pid(f.file); 1567 + if (!IS_ERR(pid)) 1568 + get_pid(pid); 1569 + 1570 + fdput(f); 1571 + return pid; 1572 + } 1573 + 1557 1574 static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop, 1558 1575 int options, struct rusage *ru) 1559 1576 { ··· 1593 1576 type = PIDTYPE_PID; 1594 1577 if (upid <= 0) 1595 1578 return -EINVAL; 1579 + 1580 + pid = find_get_pid(upid); 1596 1581 break; 1597 1582 case P_PGID: 1598 1583 type = PIDTYPE_PGID; 1599 - if (upid <= 0) 1584 + if (upid < 0) 1600 1585 return -EINVAL; 1586 + 1587 + if (upid) 1588 + pid = find_get_pid(upid); 1589 + else 1590 + pid = get_task_pid(current, PIDTYPE_PGID); 1591 + break; 1592 + case P_PIDFD: 1593 + type = PIDTYPE_PID; 1594 + if (upid < 0) 1595 + return -EINVAL; 1596 + 1597 + pid = pidfd_get_pid(upid); 1598 + if (IS_ERR(pid)) 1599 + return PTR_ERR(pid); 1601 1600 break; 1602 1601 default: 1603 1602 return -EINVAL; 1604 1603 } 1605 - 1606 - if (type < PIDTYPE_MAX) 1607 - pid = find_get_pid(upid); 1608 1604 1609 1605 wo.wo_type = type; 1610 1606 wo.wo_pid = pid;
+8
kernel/fork.c
··· 1690 1690 #endif /* #ifdef CONFIG_TASKS_RCU */ 1691 1691 } 1692 1692 1693 + struct pid *pidfd_pid(const struct file *file) 1694 + { 1695 + if (file->f_op == &pidfd_fops) 1696 + return file->private_data; 1697 + 1698 + return ERR_PTR(-EBADF); 1699 + } 1700 + 1693 1701 static int pidfd_release(struct inode *inode, struct file *file) 1694 1702 { 1695 1703 struct pid *pid = file->private_data;
+5 -2
kernel/signal.c
··· 3678 3678 3679 3679 static struct pid *pidfd_to_pid(const struct file *file) 3680 3680 { 3681 - if (file->f_op == &pidfd_fops) 3682 - return file->private_data; 3681 + struct pid *pid; 3682 + 3683 + pid = pidfd_pid(file); 3684 + if (!IS_ERR(pid)) 3685 + return pid; 3683 3686 3684 3687 return tgid_pidfd_to_pid(file); 3685 3688 }
+2
tools/testing/selftests/pidfd/.gitignore
··· 1 1 pidfd_open_test 2 + pidfd_poll_test 2 3 pidfd_test 4 + pidfd_wait
+1 -1
tools/testing/selftests/pidfd/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 CFLAGS += -g -I../../../../usr/include/ -lpthread 3 3 4 - TEST_GEN_PROGS := pidfd_test pidfd_open_test 4 + TEST_GEN_PROGS := pidfd_test pidfd_open_test pidfd_poll_test pidfd_wait 5 5 6 6 include ../lib.mk 7 7
+30
tools/testing/selftests/pidfd/pidfd.h
··· 16 16 17 17 #include "../kselftest.h" 18 18 19 + #ifndef P_PIDFD 20 + #define P_PIDFD 3 21 + #endif 22 + 23 + #ifndef CLONE_PIDFD 24 + #define CLONE_PIDFD 0x00001000 25 + #endif 26 + 27 + #ifndef __NR_pidfd_open 28 + #define __NR_pidfd_open -1 29 + #endif 30 + 31 + #ifndef __NR_pidfd_send_signal 32 + #define __NR_pidfd_send_signal -1 33 + #endif 34 + 35 + #ifndef __NR_clone3 36 + #define __NR_clone3 -1 37 + #endif 38 + 19 39 /* 20 40 * The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c 21 41 * That means, when it wraps around any pid < 300 will be skipped. ··· 73 53 return WEXITSTATUS(status); 74 54 } 75 55 56 + static inline int sys_pidfd_open(pid_t pid, unsigned int flags) 57 + { 58 + return syscall(__NR_pidfd_open, pid, flags); 59 + } 60 + 61 + static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, 62 + unsigned int flags) 63 + { 64 + return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); 65 + } 76 66 77 67 #endif /* __PIDFD_H */
-5
tools/testing/selftests/pidfd/pidfd_open_test.c
··· 22 22 #include "pidfd.h" 23 23 #include "../kselftest.h" 24 24 25 - static inline int sys_pidfd_open(pid_t pid, unsigned int flags) 26 - { 27 - return syscall(__NR_pidfd_open, pid, flags); 28 - } 29 - 30 25 static int safe_int(const char *numstr, int *converted) 31 26 { 32 27 char *err = NULL;
+117
tools/testing/selftests/pidfd/pidfd_poll_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #define _GNU_SOURCE 4 + #include <errno.h> 5 + #include <linux/types.h> 6 + #include <linux/wait.h> 7 + #include <poll.h> 8 + #include <signal.h> 9 + #include <stdbool.h> 10 + #include <stdio.h> 11 + #include <stdlib.h> 12 + #include <string.h> 13 + #include <syscall.h> 14 + #include <sys/wait.h> 15 + #include <unistd.h> 16 + 17 + #include "pidfd.h" 18 + #include "../kselftest.h" 19 + 20 + static bool timeout; 21 + 22 + static void handle_alarm(int sig) 23 + { 24 + timeout = true; 25 + } 26 + 27 + int main(int argc, char **argv) 28 + { 29 + struct pollfd fds; 30 + int iter, nevents; 31 + int nr_iterations = 10000; 32 + 33 + fds.events = POLLIN; 34 + 35 + if (argc > 2) 36 + ksft_exit_fail_msg("Unexpected command line argument\n"); 37 + 38 + if (argc == 2) { 39 + nr_iterations = atoi(argv[1]); 40 + if (nr_iterations <= 0) 41 + ksft_exit_fail_msg("invalid input parameter %s\n", 42 + argv[1]); 43 + } 44 + 45 + ksft_print_msg("running pidfd poll test for %d iterations\n", 46 + nr_iterations); 47 + 48 + for (iter = 0; iter < nr_iterations; iter++) { 49 + int pidfd; 50 + int child_pid = fork(); 51 + 52 + if (child_pid < 0) { 53 + if (errno == EAGAIN) { 54 + iter--; 55 + continue; 56 + } 57 + ksft_exit_fail_msg( 58 + "%s - failed to fork a child process\n", 59 + strerror(errno)); 60 + } 61 + 62 + if (child_pid == 0) { 63 + /* Child process just sleeps for a min and exits */ 64 + sleep(60); 65 + exit(EXIT_SUCCESS); 66 + } 67 + 68 + /* Parent kills the child and waits for its death */ 69 + pidfd = sys_pidfd_open(child_pid, 0); 70 + if (pidfd < 0) 71 + ksft_exit_fail_msg("%s - pidfd_open failed\n", 72 + strerror(errno)); 73 + 74 + /* Setup 3 sec alarm - plenty of time */ 75 + if (signal(SIGALRM, handle_alarm) == SIG_ERR) 76 + ksft_exit_fail_msg("%s - signal failed\n", 77 + strerror(errno)); 78 + alarm(3); 79 + 80 + /* Send SIGKILL to the child */ 81 + if (sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0)) 82 + ksft_exit_fail_msg("%s - pidfd_send_signal failed\n", 83 + strerror(errno)); 84 + 85 + /* Wait for the death notification */ 86 + fds.fd = pidfd; 87 + nevents = poll(&fds, 1, -1); 88 + 89 + /* Check for error conditions */ 90 + if (nevents < 0) 91 + ksft_exit_fail_msg("%s - poll failed\n", 92 + strerror(errno)); 93 + 94 + if (nevents != 1) 95 + ksft_exit_fail_msg("unexpected poll result: %d\n", 96 + nevents); 97 + 98 + if (!(fds.revents & POLLIN)) 99 + ksft_exit_fail_msg( 100 + "unexpected event type received: 0x%x\n", 101 + fds.revents); 102 + 103 + if (timeout) 104 + ksft_exit_fail_msg( 105 + "death notification wait timeout\n"); 106 + 107 + close(pidfd); 108 + /* Wait for child to prevent zombies */ 109 + if (waitpid(child_pid, NULL, 0) < 0) 110 + ksft_exit_fail_msg("%s - waitpid failed\n", 111 + strerror(errno)); 112 + 113 + } 114 + 115 + ksft_test_result_pass("pidfd poll test: pass\n"); 116 + return ksft_exit_pass(); 117 + }
-14
tools/testing/selftests/pidfd/pidfd_test.c
··· 21 21 #include "pidfd.h" 22 22 #include "../kselftest.h" 23 23 24 - #ifndef __NR_pidfd_send_signal 25 - #define __NR_pidfd_send_signal -1 26 - #endif 27 - 28 24 #define str(s) _str(s) 29 25 #define _str(s) #s 30 26 #define CHILD_THREAD_MIN_WAIT 3 /* seconds */ 31 27 32 28 #define MAX_EVENTS 5 33 - 34 - #ifndef CLONE_PIDFD 35 - #define CLONE_PIDFD 0x00001000 36 - #endif 37 29 38 30 static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *)) 39 31 { ··· 37 45 #else 38 46 return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd); 39 47 #endif 40 - } 41 - 42 - static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, 43 - unsigned int flags) 44 - { 45 - return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); 46 48 } 47 49 48 50 static int signal_received;
+271
tools/testing/selftests/pidfd/pidfd_wait.c
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #define _GNU_SOURCE 4 + #include <errno.h> 5 + #include <linux/sched.h> 6 + #include <linux/types.h> 7 + #include <signal.h> 8 + #include <stdint.h> 9 + #include <stdio.h> 10 + #include <stdlib.h> 11 + #include <sched.h> 12 + #include <string.h> 13 + #include <sys/resource.h> 14 + #include <sys/time.h> 15 + #include <sys/types.h> 16 + #include <sys/wait.h> 17 + #include <unistd.h> 18 + 19 + #include "pidfd.h" 20 + #include "../kselftest.h" 21 + 22 + #define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr))) 23 + 24 + static pid_t sys_clone3(struct clone_args *args) 25 + { 26 + return syscall(__NR_clone3, args, sizeof(struct clone_args)); 27 + } 28 + 29 + static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options, 30 + struct rusage *ru) 31 + { 32 + return syscall(__NR_waitid, which, pid, info, options, ru); 33 + } 34 + 35 + static int test_pidfd_wait_simple(void) 36 + { 37 + const char *test_name = "pidfd wait simple"; 38 + int pidfd = -1, status = 0; 39 + pid_t parent_tid = -1; 40 + struct clone_args args = { 41 + .parent_tid = ptr_to_u64(&parent_tid), 42 + .pidfd = ptr_to_u64(&pidfd), 43 + .flags = CLONE_PIDFD | CLONE_PARENT_SETTID, 44 + .exit_signal = SIGCHLD, 45 + }; 46 + int ret; 47 + pid_t pid; 48 + siginfo_t info = { 49 + .si_signo = 0, 50 + }; 51 + 52 + pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC); 53 + if (pidfd < 0) 54 + ksft_exit_fail_msg("%s test: failed to open /proc/self %s\n", 55 + test_name, strerror(errno)); 56 + 57 + pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 58 + if (pid == 0) 59 + ksft_exit_fail_msg( 60 + "%s test: succeeded to wait on invalid pidfd %s\n", 61 + test_name, strerror(errno)); 62 + close(pidfd); 63 + pidfd = -1; 64 + 65 + pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC); 66 + if (pidfd == 0) 67 + ksft_exit_fail_msg("%s test: failed to open /dev/null %s\n", 68 + test_name, strerror(errno)); 69 + 70 + pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 71 + if (pid == 0) 72 + ksft_exit_fail_msg( 73 + "%s test: succeeded to wait on invalid pidfd %s\n", 74 + test_name, strerror(errno)); 75 + close(pidfd); 76 + pidfd = -1; 77 + 78 + pid = sys_clone3(&args); 79 + if (pid < 0) 80 + ksft_exit_fail_msg("%s test: failed to create new process %s\n", 81 + test_name, strerror(errno)); 82 + 83 + if (pid == 0) 84 + exit(EXIT_SUCCESS); 85 + 86 + pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 87 + if (pid < 0) 88 + ksft_exit_fail_msg( 89 + "%s test: failed to wait on process with pid %d and pidfd %d: %s\n", 90 + test_name, parent_tid, pidfd, strerror(errno)); 91 + 92 + if (!WIFEXITED(info.si_status) || WEXITSTATUS(info.si_status)) 93 + ksft_exit_fail_msg( 94 + "%s test: unexpected status received after waiting on process with pid %d and pidfd %d: %s\n", 95 + test_name, parent_tid, pidfd, strerror(errno)); 96 + close(pidfd); 97 + 98 + if (info.si_signo != SIGCHLD) 99 + ksft_exit_fail_msg( 100 + "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n", 101 + test_name, info.si_signo, parent_tid, pidfd, 102 + strerror(errno)); 103 + 104 + if (info.si_code != CLD_EXITED) 105 + ksft_exit_fail_msg( 106 + "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n", 107 + test_name, info.si_code, parent_tid, pidfd, 108 + strerror(errno)); 109 + 110 + if (info.si_pid != parent_tid) 111 + ksft_exit_fail_msg( 112 + "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n", 113 + test_name, info.si_pid, parent_tid, pidfd, 114 + strerror(errno)); 115 + 116 + ksft_test_result_pass("%s test: Passed\n", test_name); 117 + return 0; 118 + } 119 + 120 + static int test_pidfd_wait_states(void) 121 + { 122 + const char *test_name = "pidfd wait states"; 123 + int pidfd = -1, status = 0; 124 + pid_t parent_tid = -1; 125 + struct clone_args args = { 126 + .parent_tid = ptr_to_u64(&parent_tid), 127 + .pidfd = ptr_to_u64(&pidfd), 128 + .flags = CLONE_PIDFD | CLONE_PARENT_SETTID, 129 + .exit_signal = SIGCHLD, 130 + }; 131 + int ret; 132 + pid_t pid; 133 + siginfo_t info = { 134 + .si_signo = 0, 135 + }; 136 + 137 + pid = sys_clone3(&args); 138 + if (pid < 0) 139 + ksft_exit_fail_msg("%s test: failed to create new process %s\n", 140 + test_name, strerror(errno)); 141 + 142 + if (pid == 0) { 143 + kill(getpid(), SIGSTOP); 144 + kill(getpid(), SIGSTOP); 145 + exit(EXIT_SUCCESS); 146 + } 147 + 148 + ret = sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL); 149 + if (ret < 0) 150 + ksft_exit_fail_msg( 151 + "%s test: failed to wait on WSTOPPED process with pid %d and pidfd %d: %s\n", 152 + test_name, parent_tid, pidfd, strerror(errno)); 153 + 154 + if (info.si_signo != SIGCHLD) 155 + ksft_exit_fail_msg( 156 + "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n", 157 + test_name, info.si_signo, parent_tid, pidfd, 158 + strerror(errno)); 159 + 160 + if (info.si_code != CLD_STOPPED) 161 + ksft_exit_fail_msg( 162 + "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n", 163 + test_name, info.si_code, parent_tid, pidfd, 164 + strerror(errno)); 165 + 166 + if (info.si_pid != parent_tid) 167 + ksft_exit_fail_msg( 168 + "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n", 169 + test_name, info.si_pid, parent_tid, pidfd, 170 + strerror(errno)); 171 + 172 + ret = sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0); 173 + if (ret < 0) 174 + ksft_exit_fail_msg( 175 + "%s test: failed to send signal to process with pid %d and pidfd %d: %s\n", 176 + test_name, parent_tid, pidfd, strerror(errno)); 177 + 178 + ret = sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL); 179 + if (ret < 0) 180 + ksft_exit_fail_msg( 181 + "%s test: failed to wait WCONTINUED on process with pid %d and pidfd %d: %s\n", 182 + test_name, parent_tid, pidfd, strerror(errno)); 183 + 184 + if (info.si_signo != SIGCHLD) 185 + ksft_exit_fail_msg( 186 + "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n", 187 + test_name, info.si_signo, parent_tid, pidfd, 188 + strerror(errno)); 189 + 190 + if (info.si_code != CLD_CONTINUED) 191 + ksft_exit_fail_msg( 192 + "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n", 193 + test_name, info.si_code, parent_tid, pidfd, 194 + strerror(errno)); 195 + 196 + if (info.si_pid != parent_tid) 197 + ksft_exit_fail_msg( 198 + "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n", 199 + test_name, info.si_pid, parent_tid, pidfd, 200 + strerror(errno)); 201 + 202 + ret = sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL); 203 + if (ret < 0) 204 + ksft_exit_fail_msg( 205 + "%s test: failed to wait on WUNTRACED process with pid %d and pidfd %d: %s\n", 206 + test_name, parent_tid, pidfd, strerror(errno)); 207 + 208 + if (info.si_signo != SIGCHLD) 209 + ksft_exit_fail_msg( 210 + "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n", 211 + test_name, info.si_signo, parent_tid, pidfd, 212 + strerror(errno)); 213 + 214 + if (info.si_code != CLD_STOPPED) 215 + ksft_exit_fail_msg( 216 + "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n", 217 + test_name, info.si_code, parent_tid, pidfd, 218 + strerror(errno)); 219 + 220 + if (info.si_pid != parent_tid) 221 + ksft_exit_fail_msg( 222 + "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n", 223 + test_name, info.si_pid, parent_tid, pidfd, 224 + strerror(errno)); 225 + 226 + ret = sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0); 227 + if (ret < 0) 228 + ksft_exit_fail_msg( 229 + "%s test: failed to send SIGKILL to process with pid %d and pidfd %d: %s\n", 230 + test_name, parent_tid, pidfd, strerror(errno)); 231 + 232 + ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 233 + if (ret < 0) 234 + ksft_exit_fail_msg( 235 + "%s test: failed to wait on WEXITED process with pid %d and pidfd %d: %s\n", 236 + test_name, parent_tid, pidfd, strerror(errno)); 237 + 238 + if (info.si_signo != SIGCHLD) 239 + ksft_exit_fail_msg( 240 + "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n", 241 + test_name, info.si_signo, parent_tid, pidfd, 242 + strerror(errno)); 243 + 244 + if (info.si_code != CLD_KILLED) 245 + ksft_exit_fail_msg( 246 + "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n", 247 + test_name, info.si_code, parent_tid, pidfd, 248 + strerror(errno)); 249 + 250 + if (info.si_pid != parent_tid) 251 + ksft_exit_fail_msg( 252 + "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n", 253 + test_name, info.si_pid, parent_tid, pidfd, 254 + strerror(errno)); 255 + 256 + close(pidfd); 257 + 258 + ksft_test_result_pass("%s test: Passed\n", test_name); 259 + return 0; 260 + } 261 + 262 + int main(int argc, char **argv) 263 + { 264 + ksft_print_header(); 265 + ksft_set_plan(2); 266 + 267 + test_pidfd_wait_simple(); 268 + test_pidfd_wait_states(); 269 + 270 + return ksft_exit_pass(); 271 + }