Commit | Line | Data |
---|---|---|
cc6b488e KM |
1 | /* |
2 | * Copyright (c) 1990 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
dbf0c423 | 5 | * %sccs.include.redist.c% |
cc6b488e | 6 | * |
a4128336 | 7 | * @(#)fifo_vnops.c 7.5 (Berkeley) %G% |
cc6b488e KM |
8 | */ |
9 | ||
10 | #include "param.h" | |
11 | #include "time.h" | |
12 | #include "namei.h" | |
13 | #include "vnode.h" | |
14 | #include "socket.h" | |
15 | #include "socketvar.h" | |
16 | #include "stat.h" | |
17 | #include "ioctl.h" | |
18 | #include "file.h" | |
19 | #include "errno.h" | |
20 | #include "malloc.h" | |
21 | ||
22 | /* | |
23 | * This structure is associated with the FIFO vnode and stores | |
24 | * the state associated with the FIFO. | |
25 | */ | |
26 | struct fifoinfo { | |
27 | struct socket *fi_readsock; | |
28 | struct socket *fi_writesock; | |
29 | long fi_readers; | |
30 | long fi_writers; | |
31 | }; | |
32 | ||
33 | int fifo_lookup(), | |
34 | fifo_open(), | |
35 | fifo_read(), | |
36 | fifo_write(), | |
37 | fifo_strategy(), | |
38 | fifo_bmap(), | |
39 | fifo_ioctl(), | |
40 | fifo_select(), | |
41 | fifo_lock(), | |
42 | fifo_unlock(), | |
43 | fifo_close(), | |
44 | fifo_print(), | |
a4128336 | 45 | fifo_advlock(), |
cc6b488e KM |
46 | fifo_ebadf(), |
47 | fifo_badop(), | |
48 | fifo_nullop(); | |
49 | ||
50 | struct vnodeops fifo_vnodeops = { | |
51 | fifo_lookup, /* lookup */ | |
52 | fifo_badop, /* create */ | |
53 | fifo_badop, /* mknod */ | |
54 | fifo_open, /* open */ | |
55 | fifo_close, /* close */ | |
56 | fifo_ebadf, /* access */ | |
57 | fifo_ebadf, /* getattr */ | |
58 | fifo_ebadf, /* setattr */ | |
59 | fifo_read, /* read */ | |
60 | fifo_write, /* write */ | |
61 | fifo_ioctl, /* ioctl */ | |
62 | fifo_select, /* select */ | |
63 | fifo_badop, /* mmap */ | |
64 | fifo_nullop, /* fsync */ | |
65 | fifo_badop, /* seek */ | |
66 | fifo_badop, /* remove */ | |
67 | fifo_badop, /* link */ | |
68 | fifo_badop, /* rename */ | |
69 | fifo_badop, /* mkdir */ | |
70 | fifo_badop, /* rmdir */ | |
71 | fifo_badop, /* symlink */ | |
72 | fifo_badop, /* readdir */ | |
73 | fifo_badop, /* readlink */ | |
74 | fifo_badop, /* abortop */ | |
75 | fifo_nullop, /* inactive */ | |
76 | fifo_nullop, /* reclaim */ | |
77 | fifo_lock, /* lock */ | |
78 | fifo_unlock, /* unlock */ | |
79 | fifo_bmap, /* bmap */ | |
80 | fifo_badop, /* strategy */ | |
81 | fifo_print, /* print */ | |
82 | fifo_nullop, /* islocked */ | |
a4128336 | 83 | fifo_advlock, /* advlock */ |
cc6b488e KM |
84 | }; |
85 | ||
86 | /* | |
87 | * Trivial lookup routine that always fails. | |
88 | */ | |
89 | fifo_lookup(vp, ndp) | |
90 | struct vnode *vp; | |
91 | struct nameidata *ndp; | |
92 | { | |
93 | ||
94 | ndp->ni_dvp = vp; | |
95 | ndp->ni_vp = NULL; | |
96 | return (ENOTDIR); | |
97 | } | |
98 | ||
99 | /* | |
100 | * Open called to set up a new instance of a fifo or | |
101 | * to find an active instance of a fifo. | |
102 | */ | |
103 | /* ARGSUSED */ | |
104 | fifo_open(vp, mode, cred) | |
105 | register struct vnode *vp; | |
106 | int mode; | |
107 | struct ucred *cred; | |
108 | { | |
109 | register struct fifoinfo *fip; | |
110 | struct socket *rso, *wso; | |
111 | int error; | |
bcc829cc | 112 | static char openstr[] = "fifo"; |
cc6b488e KM |
113 | |
114 | if ((mode & (FREAD|FWRITE)) == (FREAD|FWRITE)) | |
115 | return (EINVAL); | |
116 | if ((fip = vp->v_fifoinfo) == NULL) { | |
117 | MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK); | |
118 | vp->v_fifoinfo = fip; | |
ed89f575 KM |
119 | if (error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0)) { |
120 | free(fip, M_VNODE); | |
121 | vp->v_fifoinfo = NULL; | |
cc6b488e | 122 | return (error); |
ed89f575 | 123 | } |
cc6b488e KM |
124 | fip->fi_readsock = rso; |
125 | if (error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0)) { | |
126 | (void)soclose(rso); | |
ed89f575 KM |
127 | free(fip, M_VNODE); |
128 | vp->v_fifoinfo = NULL; | |
cc6b488e KM |
129 | return (error); |
130 | } | |
131 | fip->fi_writesock = wso; | |
132 | if (error = unp_connect2(wso, rso)) { | |
133 | (void)soclose(wso); | |
134 | (void)soclose(rso); | |
ed89f575 KM |
135 | free(fip, M_VNODE); |
136 | vp->v_fifoinfo = NULL; | |
cc6b488e KM |
137 | return (error); |
138 | } | |
139 | wso->so_state |= SS_CANTRCVMORE; | |
140 | rso->so_state |= SS_CANTSENDMORE; | |
141 | } | |
142 | error = 0; | |
143 | if (mode & FREAD) { | |
144 | fip->fi_readers++; | |
145 | if (fip->fi_readers == 1) { | |
146 | fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; | |
147 | if (fip->fi_writers > 0) | |
148 | wakeup((caddr_t)&fip->fi_writers); | |
149 | } | |
150 | if (mode & O_NONBLOCK) | |
151 | return (0); | |
152 | while (fip->fi_writers == 0) | |
bcc829cc MK |
153 | if (error = tsleep((caddr_t)&fip->fi_readers, PSOCK, |
154 | openstr, 0)) | |
cc6b488e KM |
155 | break; |
156 | } else { | |
157 | fip->fi_writers++; | |
158 | if (fip->fi_readers == 0 && (mode & O_NONBLOCK)) { | |
159 | error = ENXIO; | |
160 | } else { | |
161 | if (fip->fi_writers == 1) { | |
162 | fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; | |
163 | if (fip->fi_readers > 0) | |
164 | wakeup((caddr_t)&fip->fi_readers); | |
165 | } | |
166 | while (fip->fi_readers == 0) | |
bcc829cc MK |
167 | if (error = tsleep((caddr_t)&fip->fi_writers, |
168 | PSOCK, openstr, 0)) | |
cc6b488e KM |
169 | break; |
170 | } | |
171 | } | |
172 | if (error) | |
173 | fifo_close(vp, mode, cred); | |
174 | return (error); | |
175 | } | |
176 | ||
177 | /* | |
178 | * Vnode op for read | |
179 | */ | |
180 | /* ARGSUSED */ | |
181 | fifo_read(vp, uio, ioflag, cred) | |
182 | struct vnode *vp; | |
183 | register struct uio *uio; | |
184 | int ioflag; | |
185 | struct ucred *cred; | |
186 | { | |
187 | register struct socket *rso = vp->v_fifoinfo->fi_readsock; | |
188 | int error, startresid; | |
189 | ||
190 | if (uio->uio_rw != UIO_READ) | |
191 | panic("fifo_read mode"); | |
192 | if (uio->uio_resid == 0) | |
193 | return (0); | |
194 | if (ioflag & IO_NDELAY) | |
195 | rso->so_state |= SS_NBIO; | |
196 | startresid = uio->uio_resid; | |
197 | VOP_UNLOCK(vp); | |
198 | error = soreceive(rso, (struct mbuf **)0, uio, (int *)0, | |
199 | (struct mbuf **)0, (struct mbuf **)0); | |
200 | VOP_LOCK(vp); | |
201 | /* | |
202 | * Clear EOF indication after first such return. | |
203 | */ | |
204 | if (uio->uio_resid == startresid) | |
205 | rso->so_state &= ~SS_CANTRCVMORE; | |
206 | if (ioflag & IO_NDELAY) | |
207 | rso->so_state &= ~SS_NBIO; | |
208 | return (error); | |
209 | } | |
210 | ||
211 | /* | |
212 | * Vnode op for write | |
213 | */ | |
214 | /* ARGSUSED */ | |
215 | fifo_write(vp, uio, ioflag, cred) | |
216 | struct vnode *vp; | |
217 | register struct uio *uio; | |
218 | int ioflag; | |
219 | struct ucred *cred; | |
220 | { | |
221 | struct socket *wso = vp->v_fifoinfo->fi_writesock; | |
222 | int error; | |
223 | ||
224 | if (uio->uio_rw != UIO_WRITE) | |
225 | panic("fifo_write mode"); | |
226 | if (ioflag & IO_NDELAY) | |
227 | wso->so_state |= SS_NBIO; | |
228 | VOP_UNLOCK(vp); | |
229 | error = sosend(wso, (struct mbuf *)0, uio, 0, (struct mbuf *)0); | |
230 | VOP_LOCK(vp); | |
231 | if (ioflag & IO_NDELAY) | |
232 | wso->so_state &= ~SS_NBIO; | |
233 | return (error); | |
234 | } | |
235 | ||
236 | /* | |
237 | * Device ioctl operation. | |
238 | */ | |
239 | /* ARGSUSED */ | |
240 | fifo_ioctl(vp, com, data, fflag, cred) | |
241 | struct vnode *vp; | |
242 | int com; | |
243 | caddr_t data; | |
244 | int fflag; | |
245 | struct ucred *cred; | |
246 | { | |
247 | struct file filetmp; | |
248 | int error; | |
249 | ||
250 | if (com == FIONBIO) | |
251 | return (0); | |
252 | if (fflag & FREAD) | |
253 | filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_readsock; | |
254 | else | |
255 | filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_writesock; | |
256 | return (soo_ioctl(&filetmp, com, data)); | |
257 | } | |
258 | ||
259 | /* ARGSUSED */ | |
260 | fifo_select(vp, which, fflag, cred) | |
261 | struct vnode *vp; | |
262 | int which, fflag; | |
263 | struct ucred *cred; | |
264 | { | |
265 | struct file filetmp; | |
266 | int error; | |
267 | ||
268 | if (fflag & FREAD) | |
269 | filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_readsock; | |
270 | else | |
271 | filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_writesock; | |
272 | return (soo_select(&filetmp, which)); | |
273 | } | |
274 | ||
275 | /* | |
276 | * This is a noop, simply returning what one has been given. | |
277 | */ | |
278 | fifo_bmap(vp, bn, vpp, bnp) | |
279 | struct vnode *vp; | |
280 | daddr_t bn; | |
281 | struct vnode **vpp; | |
282 | daddr_t *bnp; | |
283 | { | |
284 | ||
285 | if (vpp != NULL) | |
286 | *vpp = vp; | |
287 | if (bnp != NULL) | |
288 | *bnp = bn; | |
289 | return (0); | |
290 | } | |
291 | ||
292 | /* | |
293 | * At the moment we do not do any locking. | |
294 | */ | |
295 | /* ARGSUSED */ | |
296 | fifo_lock(vp) | |
297 | struct vnode *vp; | |
298 | { | |
299 | ||
300 | return (0); | |
301 | } | |
302 | ||
303 | /* ARGSUSED */ | |
304 | fifo_unlock(vp) | |
305 | struct vnode *vp; | |
306 | { | |
307 | ||
308 | return (0); | |
309 | } | |
310 | ||
311 | /* | |
312 | * Device close routine | |
313 | */ | |
314 | /* ARGSUSED */ | |
315 | fifo_close(vp, fflag, cred) | |
316 | register struct vnode *vp; | |
317 | int fflag; | |
318 | struct ucred *cred; | |
319 | { | |
320 | register struct fifoinfo *fip = vp->v_fifoinfo; | |
321 | int error1, error2; | |
322 | ||
323 | if (fflag & FWRITE) { | |
324 | fip->fi_writers--; | |
325 | if (fip->fi_writers == 0) | |
326 | socantrcvmore(fip->fi_readsock); | |
327 | } else { | |
328 | fip->fi_readers--; | |
329 | if (fip->fi_readers == 0) | |
330 | socantsendmore(fip->fi_writesock); | |
331 | } | |
332 | if (vp->v_usecount > 1) | |
333 | return (0); | |
334 | error1 = soclose(fip->fi_readsock); | |
335 | error2 = soclose(fip->fi_writesock); | |
336 | FREE(fip, M_VNODE); | |
337 | vp->v_fifoinfo = NULL; | |
338 | if (error1) | |
339 | return (error1); | |
340 | return (error2); | |
341 | } | |
342 | ||
343 | /* | |
344 | * Print out the contents of a fifo vnode. | |
345 | */ | |
346 | fifo_print(vp) | |
347 | struct vnode *vp; | |
348 | { | |
349 | ||
350 | printf("tag VT_NON"); | |
351 | fifo_printinfo(vp); | |
352 | printf("\n"); | |
353 | } | |
354 | ||
355 | /* | |
356 | * Print out internal contents of a fifo vnode. | |
357 | */ | |
358 | fifo_printinfo(vp) | |
359 | struct vnode *vp; | |
360 | { | |
361 | register struct fifoinfo *fip = vp->v_fifoinfo; | |
362 | ||
363 | printf(", fifo with %d readers and %d writers", | |
364 | fip->fi_readers, fip->fi_writers); | |
365 | } | |
366 | ||
367 | /* | |
368 | * Fifo failed operation | |
369 | */ | |
370 | fifo_ebadf() | |
371 | { | |
372 | ||
373 | return (EBADF); | |
374 | } | |
375 | ||
a4128336 KM |
376 | /* |
377 | * Fifo advisory byte-level locks. | |
378 | */ | |
379 | fifo_advlock(vp, id, op, fl, flags) | |
380 | struct vnode *vp; | |
381 | caddr_t id; | |
382 | int op; | |
383 | struct flock *fl; | |
384 | int flags; | |
385 | { | |
386 | ||
387 | return (EOPNOTSUPP); | |
388 | } | |
389 | ||
cc6b488e KM |
390 | /* |
391 | * Fifo bad operation | |
392 | */ | |
393 | fifo_badop() | |
394 | { | |
395 | ||
396 | panic("fifo_badop called"); | |
397 | /* NOTREACHED */ | |
398 | } | |
399 | ||
400 | /* | |
401 | * Fifo null operation | |
402 | */ | |
403 | fifo_nullop() | |
404 | { | |
405 | ||
406 | return (0); | |
407 | } |