t_fdrestart.c revision 1.2 1 /* $NetBSD: t_fdrestart.c,v 1.2 2023/10/15 14:30:51 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2023 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define _KMEMUSER /* ERESTART */
30
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: t_fdrestart.c,v 1.2 2023/10/15 14:30:51 riastradh Exp $");
33
34 #include <sys/socket.h>
35 #include <sys/un.h>
36
37 #include <atf-c.h>
38 #include <errno.h>
39 #include <pthread.h>
40 #include <unistd.h>
41
42 #include <rump/rump.h>
43 #include <rump/rump_syscalls.h>
44
45 #include "h_macros.h"
46
47 struct fdrestart {
48 void (*op)(struct fdrestart *);
49 int fd;
50 pthread_barrier_t barrier;
51 };
52
53 static void
54 doread(struct fdrestart *F)
55 {
56 char c;
57 ssize_t nread;
58 int error;
59
60 nread = rump_sys_read(F->fd, &c, sizeof(c));
61 ATF_REQUIRE_EQ_MSG(nread, -1, "nread=%zd", nread);
62 error = errno;
63 ATF_REQUIRE_EQ_MSG(error, ERESTART, "errno=%d (%s)", error,
64 strerror(error));
65
66 nread = rump_sys_read(F->fd, &c, sizeof(c));
67 ATF_REQUIRE_EQ_MSG(nread, -1, "nread=%zd", nread);
68 error = errno;
69 ATF_REQUIRE_EQ_MSG(error, EBADF, "errno=%d (%s)", error,
70 strerror(error));
71 }
72
73 static void
74 dowrite(struct fdrestart *F)
75 {
76 static const char buf[1024*1024]; /* XXX >BIG_PIPE_SIZE */
77 ssize_t nwrit;
78 int error;
79
80 nwrit = rump_sys_write(F->fd, buf, sizeof(buf));
81 if (nwrit != -1) /* filled buffer, try again */
82 nwrit = rump_sys_write(F->fd, buf, sizeof(buf));
83 ATF_REQUIRE_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit);
84 error = errno;
85 ATF_REQUIRE_EQ_MSG(error, ERESTART, "errno=%d (%s)", error,
86 strerror(error));
87
88 nwrit = rump_sys_write(F->fd, buf, sizeof(buf));
89 ATF_REQUIRE_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit);
90 error = errno;
91 ATF_REQUIRE_EQ_MSG(error, EBADF, "errno=%d (%s)", error,
92 strerror(error));
93 }
94
95 static void
96 waitforbarrier(struct fdrestart *F, const char *caller)
97 {
98 int error;
99
100 error = pthread_barrier_wait(&F->barrier);
101 switch (error) {
102 case 0:
103 case PTHREAD_BARRIER_SERIAL_THREAD:
104 break;
105 default:
106 atf_tc_fail("%s: pthread_barrier_wait: %d, %s", caller, error,
107 strerror(error));
108 }
109 }
110
111 static void *
112 doit(void *cookie)
113 {
114 struct fdrestart *F = cookie;
115
116 waitforbarrier(F, "user");
117 (*F->op)(F);
118
119 return NULL;
120 }
121
122 static void
123 on_sigalrm(int signo)
124 {
125
126 atf_tc_fail("timed out");
127 }
128
129 static void
130 testfdrestart(struct fdrestart *F)
131 {
132 pthread_t t;
133
134 ATF_REQUIRE_MSG(signal(SIGALRM, &on_sigalrm) != SIG_ERR,
135 "errno=%d (%s)", errno, strerror(errno));
136
137 RZ(pthread_barrier_init(&F->barrier, NULL, 2));
138 RZ(pthread_create(&t, NULL, &doit, F));
139 waitforbarrier(F, "closer"); /* wait for thread to start */
140 (void)sleep(1); /* wait for op to start */
141 (void)alarm(1);
142 RL(rump_sys_close(F->fd));
143 RZ(pthread_join(t, NULL));
144 }
145
146 ATF_TC(pipe_read);
147 ATF_TC_HEAD(pipe_read, tc)
148 {
149 atf_tc_set_md_var(tc, "descr", "Test pipe read fails on close");
150 }
151 ATF_TC_BODY(pipe_read, tc)
152 {
153 struct fdrestart fdrestart, *F = &fdrestart;
154 int fd[2];
155
156 rump_init();
157
158 RL(rump_sys_pipe(fd));
159
160 memset(F, 0, sizeof(*F));
161 F->op = &doread;
162 F->fd = fd[0];
163 atf_tc_expect_fail("PR kern/57659");
164 testfdrestart(F);
165 }
166
167 ATF_TC(pipe_write);
168 ATF_TC_HEAD(pipe_write, tc)
169 {
170 atf_tc_set_md_var(tc, "descr", "Test pipe write fails on close");
171 }
172 ATF_TC_BODY(pipe_write, tc)
173 {
174 struct fdrestart fdrestart, *F = &fdrestart;
175 int fd[2];
176
177 rump_init();
178
179 RL(rump_sys_pipe(fd));
180
181 memset(F, 0, sizeof(*F));
182 F->op = &dowrite;
183 F->fd = fd[1];
184 atf_tc_expect_fail("PR kern/57659");
185 testfdrestart(F);
186 }
187
188 ATF_TC(socketpair_read);
189 ATF_TC_HEAD(socketpair_read, tc)
190 {
191 atf_tc_set_md_var(tc, "descr", "Test socketpair read fails on close");
192 }
193 ATF_TC_BODY(socketpair_read, tc)
194 {
195 struct fdrestart fdrestart, *F = &fdrestart;
196 int fd[2];
197
198 rump_init();
199
200 RL(rump_sys_socketpair(AF_LOCAL, SOCK_STREAM, 0, fd));
201
202 memset(F, 0, sizeof(*F));
203 F->op = &doread;
204 F->fd = fd[0];
205 atf_tc_expect_fail("PR kern/57659");
206 testfdrestart(F);
207 }
208
209 ATF_TC(socketpair_write);
210 ATF_TC_HEAD(socketpair_write, tc)
211 {
212 atf_tc_set_md_var(tc, "descr", "Test socketpair write fails on close");
213 }
214 ATF_TC_BODY(socketpair_write, tc)
215 {
216 struct fdrestart fdrestart, *F = &fdrestart;
217 int fd[2];
218
219 rump_init();
220
221 RL(rump_sys_socketpair(AF_LOCAL, SOCK_STREAM, 0, fd));
222
223 memset(F, 0, sizeof(*F));
224 F->op = &dowrite;
225 F->fd = fd[0];
226 atf_tc_expect_fail("PR kern/57659");
227 testfdrestart(F);
228 }
229
230 ATF_TP_ADD_TCS(tp)
231 {
232
233 ATF_TP_ADD_TC(tp, pipe_read);
234 ATF_TP_ADD_TC(tp, pipe_write);
235 ATF_TP_ADD_TC(tp, socketpair_read);
236 ATF_TP_ADD_TC(tp, socketpair_write);
237
238 return atf_no_error();
239 }
240