Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/fifofs/fifo_vnops.c
39507 views
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
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
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
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
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
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
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
356