1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1990, 1993, 1995
5 * The Regents of the University of California.
6 * Copyright (c) 2005 Robert N. M. Watson
7 * Copyright (c) 2012 Giovanni Trematerra
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/param.h>
36 #include <sys/event.h>
37 #include <sys/file.h>
38 #include <sys/filedesc.h>
39 #include <sys/filio.h>
40 #include <sys/fcntl.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/mutex.h>
44 #include <sys/malloc.h>
45 #include <sys/selinfo.h>
46 #include <sys/pipe.h>
47 #include <sys/proc.h>
48 #include <sys/signalvar.h>
49 #include <sys/sx.h>
50 #include <sys/systm.h>
51 #include <sys/un.h>
52 #include <sys/unistd.h>
53 #include <sys/vnode.h>
54
55 /*
56 * This structure is associated with the FIFO vnode and stores
57 * the state associated with the FIFO.
58 * Notes about locking:
59 * - fi_pipe is invariant since init time.
60 * - fi_readers and fi_writers are protected by the vnode lock.
61 */
62 struct fifoinfo {
63 struct pipe *fi_pipe;
64 long fi_readers;
65 long fi_writers;
66 u_int fi_rgen;
67 u_int fi_wgen;
68 };
69
70 static vop_print_t fifo_print;
71 static vop_open_t fifo_open;
72 static vop_close_t fifo_close;
73 static vop_advlock_t fifo_advlock;
74
75 struct vop_vector fifo_specops = {
76 .vop_default = &default_vnodeops,
77
78 .vop_advlock = fifo_advlock,
79 .vop_close = fifo_close,
80 .vop_create = VOP_PANIC,
81 .vop_getattr = VOP_EBADF,
82 .vop_ioctl = VOP_PANIC,
83 .vop_link = VOP_PANIC,
84 .vop_mkdir = VOP_PANIC,
85 .vop_mknod = VOP_PANIC,
86 .vop_open = fifo_open,
87 .vop_pathconf = VOP_PANIC,
88 .vop_print = fifo_print,
89 .vop_read = VOP_PANIC,
90 .vop_readdir = VOP_PANIC,
91 .vop_readlink = VOP_PANIC,
92 .vop_reallocblks = VOP_PANIC,
93 .vop_reclaim = VOP_NULL,
94 .vop_remove = VOP_PANIC,
95 .vop_rename = VOP_PANIC,
96 .vop_rmdir = VOP_PANIC,
97 .vop_setattr = VOP_EBADF,
98 .vop_symlink = VOP_PANIC,
99 .vop_write = VOP_PANIC,
100 };
101 VFS_VOP_VECTOR_REGISTER(fifo_specops);
102
103 /*
104 * Dispose of fifo resources.
105 */
106 static void
fifo_cleanup(struct vnode * vp)107 fifo_cleanup(struct vnode *vp)
108 {
109 struct fifoinfo *fip;
110
111 ASSERT_VOP_ELOCKED(vp, "fifo_cleanup");
112 fip = vp->v_fifoinfo;
113 if (fip->fi_readers == 0 && fip->fi_writers == 0) {
114 vp->v_fifoinfo = NULL;
115 pipe_dtor(fip->fi_pipe);
116 free(fip, M_VNODE);
117 }
118 }
119
120 /*
121 * Open called to set up a new instance of a fifo or
122 * to find an active instance of a fifo.
123 */
124 /* ARGSUSED */
125 static int
fifo_open(struct vop_open_args * ap)126 fifo_open(struct vop_open_args *ap)
127 {
128 struct vnode *vp;
129 struct file *fp;
130 struct thread *td;
131 struct fifoinfo *fip;
132 struct pipe *fpipe;
133 u_int gen;
134 int error, stops_deferred;
135
136 vp = ap->a_vp;
137 fp = ap->a_fp;
138 td = ap->a_td;
139 ASSERT_VOP_ELOCKED(vp, "fifo_open");
140 if (fp == NULL || (ap->a_mode & FEXEC) != 0)
141 return (EINVAL);
142 if ((fip = vp->v_fifoinfo) == NULL) {
143 error = pipe_named_ctor(&fpipe, td);
144 if (error != 0)
145 return (error);
146 fip = malloc(sizeof(*fip), M_VNODE, M_WAITOK | M_ZERO);
147 fip->fi_pipe = fpipe;
148 fpipe->pipe_wgen = 0;
149 KASSERT(vp->v_fifoinfo == NULL, ("fifo_open: v_fifoinfo race"));
150 vp->v_fifoinfo = fip;
151 }
152 fpipe = fip->fi_pipe;
153 KASSERT(fpipe != NULL, ("fifo_open: pipe is NULL"));
154
155 /*
156 * Use the pipe mutex here, in addition to the vnode lock,
157 * in order to allow vnode lock dropping before msleep() calls
158 * and still avoiding missed wakeups.
159 */
160 PIPE_LOCK(fpipe);
161 if (ap->a_mode & FREAD) {
162 fip->fi_readers++;
163 fip->fi_rgen++;
164 if (fip->fi_readers == 1) {
165 fpipe->pipe_state &= ~PIPE_EOF;
166 if (fip->fi_writers > 0) {
167 wakeup(&fip->fi_writers);
168 pipeselwakeup(fpipe);
169 }
170 }
171 fp->f_pipegen = fpipe->pipe_wgen - fip->fi_writers;
172 }
173 if (ap->a_mode & FWRITE) {
174 if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) {
175 PIPE_UNLOCK(fpipe);
176 if (fip->fi_writers == 0)
177 fifo_cleanup(vp);
178 return (ENXIO);
179 }
180 fip->fi_writers++;
181 fip->fi_wgen++;
182 if (fip->fi_writers == 1) {
183 fpipe->pipe_state &= ~PIPE_EOF;
184 if (fip->fi_readers > 0) {
185 wakeup(&fip->fi_readers);
186 pipeselwakeup(fpipe);
187 }
188 }
189 }
190 if ((ap->a_mode & O_NONBLOCK) == 0) {
191 if ((ap->a_mode & FREAD) && fip->fi_writers == 0) {
192 gen = fip->fi_wgen;
193 VOP_UNLOCK(vp);
194 stops_deferred = sigdeferstop(SIGDEFERSTOP_OFF);
195 error = msleep(&fip->fi_readers, PIPE_MTX(fpipe),
196 PDROP | PCATCH | PSOCK, "fifoor", 0);
197 sigallowstop(stops_deferred);
198 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
199 if (error != 0 && gen == fip->fi_wgen) {
200 fip->fi_readers--;
201 if (fip->fi_readers == 0) {
202 PIPE_LOCK(fpipe);
203 fpipe->pipe_state |= PIPE_EOF;
204 if (fpipe->pipe_state & PIPE_WANTW)
205 wakeup(fpipe);
206 pipeselwakeup(fpipe);
207 PIPE_UNLOCK(fpipe);
208 fifo_cleanup(vp);
209 }
210 return (error);
211 }
212 PIPE_LOCK(fpipe);
213 /*
214 * We must have got woken up because we had a writer.
215 * That (and not still having one) is the condition
216 * that we must wait for.
217 */
218 }
219 if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) {
220 gen = fip->fi_rgen;
221 VOP_UNLOCK(vp);
222 stops_deferred = sigdeferstop(SIGDEFERSTOP_OFF);
223 error = msleep(&fip->fi_writers, PIPE_MTX(fpipe),
224 PDROP | PCATCH | PSOCK, "fifoow", 0);
225 sigallowstop(stops_deferred);
226 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
227 if (error != 0 && gen == fip->fi_rgen) {
228 fip->fi_writers--;
229 if (fip->fi_writers == 0) {
230 PIPE_LOCK(fpipe);
231 fpipe->pipe_state |= PIPE_EOF;
232 if (fpipe->pipe_state & PIPE_WANTR)
233 wakeup(fpipe);
234 fpipe->pipe_wgen++;
235 pipeselwakeup(fpipe);
236 PIPE_UNLOCK(fpipe);
237 fifo_cleanup(vp);
238 }
239 return (error);
240 }
241 /*
242 * We must have got woken up because we had
243 * a reader. That (and not still having one)
244 * is the condition that we must wait for.
245 */
246 PIPE_LOCK(fpipe);
247 }
248 }
249 PIPE_UNLOCK(fpipe);
250 KASSERT(fp != NULL, ("can't fifo/vnode bypass"));
251 KASSERT(fp->f_ops == &badfileops, ("not badfileops in fifo_open"));
252 finit(fp, fp->f_flag, DTYPE_FIFO, fpipe, &pipeops);
253 return (0);
254 }
255
256 /*
257 * Device close routine
258 */
259 /* ARGSUSED */
260 static int
fifo_close(struct vop_close_args * ap)261 fifo_close(struct vop_close_args *ap)
262 {
263 struct vnode *vp;
264 struct fifoinfo *fip;
265 struct pipe *cpipe;
266
267 vp = ap->a_vp;
268 ASSERT_VOP_ELOCKED(vp, "fifo_close");
269 fip = vp->v_fifoinfo;
270
271 /*
272 * During open, it is possible that the fifo vnode is relocked
273 * after the vnode is instantiated but before VOP_OPEN() is
274 * done. For instance, vn_open_vnode() might need to upgrade
275 * vnode lock, or ffs_vput_pair() needs to unlock vp to sync
276 * dvp. In this case, reclaim can observe us with v_fifoinfo
277 * equal to NULL.
278 */
279 if (fip == NULL)
280 return (0);
281
282 cpipe = fip->fi_pipe;
283 if (ap->a_fflag & FREAD) {
284 fip->fi_readers--;
285 if (fip->fi_readers == 0) {
286 PIPE_LOCK(cpipe);
287 cpipe->pipe_state |= PIPE_EOF;
288 if ((cpipe->pipe_state & PIPE_WANTW)) {
289 cpipe->pipe_state &= ~PIPE_WANTW;
290 wakeup(cpipe);
291 }
292 pipeselwakeup(cpipe);
293 PIPE_UNLOCK(cpipe);
294 }
295 }
296 if (ap->a_fflag & FWRITE) {
297 fip->fi_writers--;
298 if (fip->fi_writers == 0) {
299 PIPE_LOCK(cpipe);
300 cpipe->pipe_state |= PIPE_EOF;
301 if ((cpipe->pipe_state & PIPE_WANTR)) {
302 cpipe->pipe_state &= ~PIPE_WANTR;
303 wakeup(cpipe);
304 }
305 cpipe->pipe_wgen++;
306 pipeselwakeup(cpipe);
307 PIPE_UNLOCK(cpipe);
308 }
309 }
310 fifo_cleanup(vp);
311 return (0);
312 }
313
314 /*
315 * Print out internal contents of a fifo vnode.
316 */
317 int
fifo_printinfo(struct vnode * vp)318 fifo_printinfo(struct vnode *vp)
319 {
320 struct fifoinfo *fip = vp->v_fifoinfo;
321
322 if (fip == NULL){
323 printf(", NULL v_fifoinfo");
324 return (0);
325 }
326 printf(", fifo with %ld readers and %ld writers",
327 fip->fi_readers, fip->fi_writers);
328 return (0);
329 }
330
331 /*
332 * Print out the contents of a fifo vnode.
333 */
334 static int
fifo_print(struct vop_print_args * ap)335 fifo_print(struct vop_print_args *ap)
336 {
337 printf(" ");
338 fifo_printinfo(ap->a_vp);
339 printf("\n");
340 return (0);
341 }
342
343 /*
344 * Fifo advisory byte-level locks.
345 */
346 /* ARGSUSED */
347 static int
fifo_advlock(struct vop_advlock_args * ap)348 fifo_advlock(struct vop_advlock_args *ap)
349 {
350
351 if ((ap->a_flags & F_FLOCK) == 0)
352 return (EINVAL);
353 return (vop_stdadvlock(ap));
354 }
355