1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2022 Oxide Computer Company
14 */
15
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <fcntl.h>
20 #include <dirent.h>
21 #include <port.h>
22 #include <err.h>
23 #include <assert.h>
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/param.h>
28 #include <sys/poll.h>
29
30 /*
31 * Attempt to trigger the #15036 regression. This depends on a subsequent
32 * allocation in the same slab setting a bit at a specific offset, so reliable
33 * detection of the issue is a challenge. This test uses brute force in its
34 * attempt, but cannot guarantee to trigger the behavior on a system affected by
35 * the issue.
36 */
37
38 /*
39 * We need regular files on a regular filesystem for fs_poll to be called.
40 * Assume that we can find some in our own tests dir.
41 *
42 * As for repetitions, this is not especially consistent, so really hammer
43 * things out of brute force.
44 */
45 #define FILE_SRC "/opt/os-tests/tests"
46 #define FILE_COUNT 10
47 #define TEST_REPEAT 10000
48
49 static uint_t
find_test_files(const char * dir,uint_t count,int * result_fds)50 find_test_files(const char *dir, uint_t count, int *result_fds)
51 {
52 assert(count > 0);
53
54 DIR *dirp;
55
56 dirp = opendir(dir);
57 if (dirp == NULL) {
58 return (0);
59 }
60
61 dirent_t *de;
62 uint_t nvalid = 0;
63 while ((de = readdir(dirp)) != NULL) {
64 char path[MAXPATHLEN];
65 struct stat st;
66
67 (void) snprintf(path, sizeof (path), "%s/%s", dir, de->d_name);
68 if (lstat(path, &st) != 0 || (st.st_mode & S_IFREG) == 0) {
69 continue;
70 }
71 result_fds[nvalid] = open(path, O_RDONLY, 0);
72 if (result_fds[nvalid] < 0) {
73 continue;
74 }
75
76 nvalid++;
77 if (nvalid == count) {
78 break;
79 }
80 }
81
82 (void) closedir(dirp);
83 return (nvalid);
84 }
85
86 int
main(int argc,char * argv[])87 main(int argc, char *argv[])
88 {
89 int poll_fds[FILE_COUNT];
90
91 if (find_test_files(FILE_SRC, FILE_COUNT, poll_fds) != FILE_COUNT) {
92 errx(EXIT_FAILURE, "FAIL - count not open test files to poll");
93 }
94
95 for (uint_t i = 0; i < TEST_REPEAT; i++) {
96 int port_fds[FILE_COUNT];
97
98 for (uint_t j = 0; j < FILE_COUNT; j++) {
99 port_fds[j] = port_create();
100 if (port_fds[j] < 0) {
101 err(EXIT_FAILURE, "FAIL - port_create()");
102 }
103
104 int res = port_associate(port_fds[j], PORT_SOURCE_FD,
105 (uintptr_t)poll_fds[j], POLLIN, NULL);
106 if (res != 0) {
107 err(EXIT_FAILURE, "FAIL - port_associate()");
108 }
109 }
110
111 for (uint_t j = 0; j < FILE_COUNT; j++) {
112 int res = port_dissociate(port_fds[j], PORT_SOURCE_FD,
113 (uintptr_t)poll_fds[j]);
114 if (res != 0) {
115 err(EXIT_FAILURE, "FAIL - port_dissociate()");
116 }
117 (void) close(port_fds[j]);
118 }
119 }
120
121 (void) printf("PASS\n");
122 return (EXIT_SUCCESS);
123 }
124