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