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 | * |
ea67b335 | 7 | * @(#)fifo_vnops.c 7.13 (Berkeley) %G% |
cc6b488e KM |
8 | */ |
9 | ||
10 | #include "param.h" | |
063b2136 | 11 | #include "proc.h" |
cc6b488e KM |
12 | #include "time.h" |
13 | #include "namei.h" | |
14 | #include "vnode.h" | |
15 | #include "socket.h" | |
16 | #include "socketvar.h" | |
17 | #include "stat.h" | |
8429d022 | 18 | #include "systm.h" |
cc6b488e KM |
19 | #include "ioctl.h" |
20 | #include "file.h" | |
81b4c293 | 21 | #include "fifo.h" |
cc6b488e KM |
22 | #include "errno.h" |
23 | #include "malloc.h" | |
24 | ||
25 | /* | |
26 | * This structure is associated with the FIFO vnode and stores | |
27 | * the state associated with the FIFO. | |
28 | */ | |
29 | struct fifoinfo { | |
30 | struct socket *fi_readsock; | |
31 | struct socket *fi_writesock; | |
32 | long fi_readers; | |
33 | long fi_writers; | |
34 | }; | |
35 | ||
9342689a JH |
36 | int (**fifo_vnodeop_p)(); |
37 | struct vnodeopv_entry_desc fifo_vnodeop_entries[] = { | |
38 | { &vop_default_desc, vn_default_error }, | |
39 | { &vop_lookup_desc, fifo_lookup }, /* lookup */ | |
40 | { &vop_create_desc, fifo_create }, /* create */ | |
41 | { &vop_mknod_desc, fifo_mknod }, /* mknod */ | |
42 | { &vop_open_desc, fifo_open }, /* open */ | |
43 | { &vop_close_desc, fifo_close }, /* close */ | |
44 | { &vop_access_desc, fifo_access }, /* access */ | |
45 | { &vop_getattr_desc, fifo_getattr }, /* getattr */ | |
46 | { &vop_setattr_desc, fifo_setattr }, /* setattr */ | |
47 | { &vop_read_desc, fifo_read }, /* read */ | |
48 | { &vop_write_desc, fifo_write }, /* write */ | |
49 | { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ | |
50 | { &vop_select_desc, fifo_select }, /* select */ | |
51 | { &vop_mmap_desc, fifo_mmap }, /* mmap */ | |
52 | { &vop_fsync_desc, fifo_fsync }, /* fsync */ | |
53 | { &vop_seek_desc, fifo_seek }, /* seek */ | |
54 | { &vop_remove_desc, fifo_remove }, /* remove */ | |
55 | { &vop_link_desc, fifo_link }, /* link */ | |
56 | { &vop_rename_desc, fifo_rename }, /* rename */ | |
57 | { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ | |
58 | { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ | |
59 | { &vop_symlink_desc, fifo_symlink }, /* symlink */ | |
60 | { &vop_readdir_desc, fifo_readdir }, /* readdir */ | |
61 | { &vop_readlink_desc, fifo_readlink }, /* readlink */ | |
62 | { &vop_abortop_desc, fifo_abortop }, /* abortop */ | |
63 | { &vop_inactive_desc, fifo_inactive }, /* inactive */ | |
64 | { &vop_reclaim_desc, fifo_reclaim }, /* reclaim */ | |
65 | { &vop_lock_desc, fifo_lock }, /* lock */ | |
66 | { &vop_unlock_desc, fifo_unlock }, /* unlock */ | |
67 | { &vop_bmap_desc, fifo_bmap }, /* bmap */ | |
68 | { &vop_strategy_desc, fifo_strategy }, /* strategy */ | |
69 | { &vop_print_desc, fifo_print }, /* print */ | |
70 | { &vop_islocked_desc, fifo_islocked }, /* islocked */ | |
71 | { &vop_advlock_desc, fifo_advlock }, /* advlock */ | |
72 | { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ | |
73 | { &vop_vget_desc, fifo_vget }, /* vget */ | |
74 | { &vop_valloc_desc, fifo_valloc }, /* valloc */ | |
75 | { &vop_vfree_desc, fifo_vfree }, /* vfree */ | |
76 | { &vop_truncate_desc, fifo_truncate }, /* truncate */ | |
77 | { &vop_update_desc, fifo_update }, /* update */ | |
78 | { &vop_bwrite_desc, fifo_bwrite }, /* bwrite */ | |
79 | { (struct vnodeop_desc*)NULL, (int(*)())NULL } | |
cc6b488e | 80 | }; |
9342689a JH |
81 | struct vnodeopv_desc fifo_vnodeop_opv_desc = |
82 | { &fifo_vnodeop_p, fifo_vnodeop_entries }; | |
cc6b488e KM |
83 | |
84 | /* | |
85 | * Trivial lookup routine that always fails. | |
86 | */ | |
81b4c293 | 87 | /* ARGSUSED */ |
9342689a JH |
88 | fifo_lookup (ap) |
89 | struct vop_lookup_args *ap; | |
90 | #define dvp (ap->a_dvp) | |
91 | #define vpp (ap->a_vpp) | |
92 | #define cnp (ap->a_cnp) | |
cc6b488e | 93 | { |
085e9ab7 JH |
94 | |
95 | *vpp = NULL; | |
cc6b488e KM |
96 | return (ENOTDIR); |
97 | } | |
9342689a JH |
98 | #undef dvp |
99 | #undef vpp | |
100 | #undef cnp | |
cc6b488e KM |
101 | |
102 | /* | |
103 | * Open called to set up a new instance of a fifo or | |
104 | * to find an active instance of a fifo. | |
105 | */ | |
106 | /* ARGSUSED */ | |
9342689a JH |
107 | fifo_open (ap) |
108 | struct vop_open_args *ap; | |
109 | #define vp (ap->a_vp) | |
110 | #define mode (ap->a_mode) | |
111 | #define cred (ap->a_cred) | |
112 | #define p (ap->a_p) | |
cc6b488e | 113 | { |
9342689a JH |
114 | USES_VOP_CLOSE; |
115 | USES_VOP_LOCK; | |
116 | USES_VOP_UNLOCK; | |
cc6b488e KM |
117 | register struct fifoinfo *fip; |
118 | struct socket *rso, *wso; | |
119 | int error; | |
bcc829cc | 120 | static char openstr[] = "fifo"; |
cc6b488e KM |
121 | |
122 | if ((mode & (FREAD|FWRITE)) == (FREAD|FWRITE)) | |
123 | return (EINVAL); | |
124 | if ((fip = vp->v_fifoinfo) == NULL) { | |
125 | MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK); | |
126 | vp->v_fifoinfo = fip; | |
ed89f575 KM |
127 | if (error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0)) { |
128 | free(fip, M_VNODE); | |
129 | vp->v_fifoinfo = NULL; | |
cc6b488e | 130 | return (error); |
ed89f575 | 131 | } |
cc6b488e KM |
132 | fip->fi_readsock = rso; |
133 | if (error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0)) { | |
134 | (void)soclose(rso); | |
ed89f575 KM |
135 | free(fip, M_VNODE); |
136 | vp->v_fifoinfo = NULL; | |
cc6b488e KM |
137 | return (error); |
138 | } | |
139 | fip->fi_writesock = wso; | |
140 | if (error = unp_connect2(wso, rso)) { | |
141 | (void)soclose(wso); | |
142 | (void)soclose(rso); | |
ed89f575 KM |
143 | free(fip, M_VNODE); |
144 | vp->v_fifoinfo = NULL; | |
cc6b488e KM |
145 | return (error); |
146 | } | |
80c4c463 | 147 | fip->fi_readers = fip->fi_writers = 0; |
cc6b488e KM |
148 | wso->so_state |= SS_CANTRCVMORE; |
149 | rso->so_state |= SS_CANTSENDMORE; | |
150 | } | |
151 | error = 0; | |
152 | if (mode & FREAD) { | |
153 | fip->fi_readers++; | |
154 | if (fip->fi_readers == 1) { | |
155 | fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; | |
156 | if (fip->fi_writers > 0) | |
157 | wakeup((caddr_t)&fip->fi_writers); | |
158 | } | |
159 | if (mode & O_NONBLOCK) | |
160 | return (0); | |
80c4c463 KM |
161 | while (fip->fi_writers == 0) { |
162 | VOP_UNLOCK(vp); | |
163 | error = tsleep((caddr_t)&fip->fi_readers, PSOCK, | |
164 | openstr, 0); | |
165 | VOP_LOCK(vp); | |
166 | if (error) | |
cc6b488e | 167 | break; |
80c4c463 | 168 | } |
cc6b488e KM |
169 | } else { |
170 | fip->fi_writers++; | |
171 | if (fip->fi_readers == 0 && (mode & O_NONBLOCK)) { | |
172 | error = ENXIO; | |
173 | } else { | |
174 | if (fip->fi_writers == 1) { | |
175 | fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; | |
176 | if (fip->fi_readers > 0) | |
177 | wakeup((caddr_t)&fip->fi_readers); | |
178 | } | |
80c4c463 KM |
179 | while (fip->fi_readers == 0) { |
180 | VOP_UNLOCK(vp); | |
181 | error = tsleep((caddr_t)&fip->fi_writers, | |
182 | PSOCK, openstr, 0); | |
183 | VOP_LOCK(vp); | |
184 | if (error) | |
cc6b488e | 185 | break; |
80c4c463 | 186 | } |
cc6b488e KM |
187 | } |
188 | } | |
189 | if (error) | |
9342689a | 190 | VOP_CLOSE(vp, mode, cred, p); |
cc6b488e KM |
191 | return (error); |
192 | } | |
9342689a JH |
193 | #undef vp |
194 | #undef mode | |
195 | #undef cred | |
196 | #undef p | |
cc6b488e KM |
197 | |
198 | /* | |
199 | * Vnode op for read | |
200 | */ | |
201 | /* ARGSUSED */ | |
9342689a JH |
202 | fifo_read (ap) |
203 | struct vop_read_args *ap; | |
204 | #define vp (ap->a_vp) | |
205 | #define uio (ap->a_uio) | |
206 | #define ioflag (ap->a_ioflag) | |
207 | #define cred (ap->a_cred) | |
cc6b488e | 208 | { |
9342689a JH |
209 | USES_VOP_LOCK; |
210 | USES_VOP_UNLOCK; | |
cc6b488e KM |
211 | register struct socket *rso = vp->v_fifoinfo->fi_readsock; |
212 | int error, startresid; | |
213 | ||
81b4c293 | 214 | #ifdef DIAGNOSTIC |
cc6b488e KM |
215 | if (uio->uio_rw != UIO_READ) |
216 | panic("fifo_read mode"); | |
81b4c293 | 217 | #endif |
cc6b488e KM |
218 | if (uio->uio_resid == 0) |
219 | return (0); | |
220 | if (ioflag & IO_NDELAY) | |
221 | rso->so_state |= SS_NBIO; | |
222 | startresid = uio->uio_resid; | |
223 | VOP_UNLOCK(vp); | |
224 | error = soreceive(rso, (struct mbuf **)0, uio, (int *)0, | |
225 | (struct mbuf **)0, (struct mbuf **)0); | |
226 | VOP_LOCK(vp); | |
227 | /* | |
228 | * Clear EOF indication after first such return. | |
229 | */ | |
230 | if (uio->uio_resid == startresid) | |
231 | rso->so_state &= ~SS_CANTRCVMORE; | |
232 | if (ioflag & IO_NDELAY) | |
233 | rso->so_state &= ~SS_NBIO; | |
234 | return (error); | |
235 | } | |
9342689a JH |
236 | #undef vp |
237 | #undef uio | |
238 | #undef ioflag | |
239 | #undef cred | |
cc6b488e KM |
240 | |
241 | /* | |
242 | * Vnode op for write | |
243 | */ | |
244 | /* ARGSUSED */ | |
9342689a JH |
245 | fifo_write (ap) |
246 | struct vop_write_args *ap; | |
247 | #define vp (ap->a_vp) | |
248 | #define uio (ap->a_uio) | |
249 | #define ioflag (ap->a_ioflag) | |
250 | #define cred (ap->a_cred) | |
cc6b488e | 251 | { |
9342689a JH |
252 | USES_VOP_LOCK; |
253 | USES_VOP_UNLOCK; | |
cc6b488e KM |
254 | struct socket *wso = vp->v_fifoinfo->fi_writesock; |
255 | int error; | |
256 | ||
81b4c293 | 257 | #ifdef DIAGNOSTIC |
cc6b488e KM |
258 | if (uio->uio_rw != UIO_WRITE) |
259 | panic("fifo_write mode"); | |
81b4c293 | 260 | #endif |
cc6b488e KM |
261 | if (ioflag & IO_NDELAY) |
262 | wso->so_state |= SS_NBIO; | |
263 | VOP_UNLOCK(vp); | |
4032098c | 264 | error = sosend(wso, (struct mbuf *)0, uio, 0, (struct mbuf *)0, 0); |
cc6b488e KM |
265 | VOP_LOCK(vp); |
266 | if (ioflag & IO_NDELAY) | |
267 | wso->so_state &= ~SS_NBIO; | |
268 | return (error); | |
269 | } | |
9342689a JH |
270 | #undef vp |
271 | #undef uio | |
272 | #undef ioflag | |
273 | #undef cred | |
cc6b488e KM |
274 | |
275 | /* | |
276 | * Device ioctl operation. | |
277 | */ | |
278 | /* ARGSUSED */ | |
9342689a JH |
279 | fifo_ioctl (ap) |
280 | struct vop_ioctl_args *ap; | |
281 | #define vp (ap->a_vp) | |
282 | #define com (ap->a_command) | |
283 | #define data (ap->a_data) | |
284 | #define fflag (ap->a_fflag) | |
285 | #define cred (ap->a_cred) | |
286 | #define p (ap->a_p) | |
cc6b488e KM |
287 | { |
288 | struct file filetmp; | |
289 | int error; | |
290 | ||
291 | if (com == FIONBIO) | |
292 | return (0); | |
293 | if (fflag & FREAD) | |
294 | filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_readsock; | |
295 | else | |
296 | filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_writesock; | |
81b4c293 | 297 | return (soo_ioctl(&filetmp, com, data, p)); |
cc6b488e | 298 | } |
9342689a JH |
299 | #undef vp |
300 | #undef com | |
301 | #undef data | |
302 | #undef fflag | |
303 | #undef cred | |
304 | #undef p | |
cc6b488e KM |
305 | |
306 | /* ARGSUSED */ | |
9342689a JH |
307 | fifo_select (ap) |
308 | struct vop_select_args *ap; | |
309 | #define vp (ap->a_vp) | |
310 | #define which (ap->a_which) | |
311 | #define fflag (ap->a_fflags) | |
312 | #define cred (ap->a_cred) | |
313 | #define p (ap->a_p) | |
cc6b488e KM |
314 | { |
315 | struct file filetmp; | |
316 | int error; | |
317 | ||
318 | if (fflag & FREAD) | |
319 | filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_readsock; | |
320 | else | |
321 | filetmp.f_data = (caddr_t)vp->v_fifoinfo->fi_writesock; | |
81b4c293 | 322 | return (soo_select(&filetmp, which, p)); |
cc6b488e | 323 | } |
9342689a JH |
324 | #undef vp |
325 | #undef which | |
326 | #undef fflag | |
327 | #undef cred | |
328 | #undef p | |
cc6b488e KM |
329 | |
330 | /* | |
331 | * This is a noop, simply returning what one has been given. | |
332 | */ | |
9342689a JH |
333 | fifo_bmap (ap) |
334 | struct vop_bmap_args *ap; | |
335 | #define vp (ap->a_vp) | |
336 | #define bn (ap->a_bn) | |
337 | #define vpp (ap->a_vpp) | |
338 | #define bnp (ap->a_bnp) | |
cc6b488e KM |
339 | { |
340 | ||
341 | if (vpp != NULL) | |
342 | *vpp = vp; | |
343 | if (bnp != NULL) | |
344 | *bnp = bn; | |
345 | return (0); | |
346 | } | |
9342689a JH |
347 | #undef vp |
348 | #undef bn | |
349 | #undef vpp | |
350 | #undef bnp | |
cc6b488e KM |
351 | |
352 | /* | |
353 | * At the moment we do not do any locking. | |
354 | */ | |
355 | /* ARGSUSED */ | |
9342689a JH |
356 | fifo_lock (ap) |
357 | struct vop_lock_args *ap; | |
358 | #define vp (ap->a_vp) | |
cc6b488e KM |
359 | { |
360 | ||
361 | return (0); | |
362 | } | |
9342689a | 363 | #undef vp |
cc6b488e KM |
364 | |
365 | /* ARGSUSED */ | |
9342689a JH |
366 | fifo_unlock (ap) |
367 | struct vop_unlock_args *ap; | |
368 | #define vp (ap->a_vp) | |
cc6b488e KM |
369 | { |
370 | ||
371 | return (0); | |
372 | } | |
9342689a | 373 | #undef vp |
cc6b488e KM |
374 | |
375 | /* | |
376 | * Device close routine | |
377 | */ | |
378 | /* ARGSUSED */ | |
9342689a JH |
379 | fifo_close (ap) |
380 | struct vop_close_args *ap; | |
381 | #define vp (ap->a_vp) | |
382 | #define fflag (ap->a_fflag) | |
383 | #define cred (ap->a_cred) | |
384 | #define p (ap->a_p) | |
cc6b488e KM |
385 | { |
386 | register struct fifoinfo *fip = vp->v_fifoinfo; | |
387 | int error1, error2; | |
388 | ||
389 | if (fflag & FWRITE) { | |
390 | fip->fi_writers--; | |
391 | if (fip->fi_writers == 0) | |
392 | socantrcvmore(fip->fi_readsock); | |
393 | } else { | |
394 | fip->fi_readers--; | |
395 | if (fip->fi_readers == 0) | |
396 | socantsendmore(fip->fi_writesock); | |
397 | } | |
398 | if (vp->v_usecount > 1) | |
399 | return (0); | |
400 | error1 = soclose(fip->fi_readsock); | |
401 | error2 = soclose(fip->fi_writesock); | |
402 | FREE(fip, M_VNODE); | |
403 | vp->v_fifoinfo = NULL; | |
404 | if (error1) | |
405 | return (error1); | |
406 | return (error2); | |
407 | } | |
9342689a JH |
408 | #undef vp |
409 | #undef fflag | |
410 | #undef cred | |
411 | #undef p | |
cc6b488e KM |
412 | |
413 | /* | |
414 | * Print out the contents of a fifo vnode. | |
415 | */ | |
9342689a JH |
416 | fifo_print (ap) |
417 | struct vop_print_args *ap; | |
418 | #define vp (ap->a_vp) | |
cc6b488e KM |
419 | { |
420 | ||
421 | printf("tag VT_NON"); | |
422 | fifo_printinfo(vp); | |
423 | printf("\n"); | |
424 | } | |
9342689a | 425 | #undef vp |
cc6b488e KM |
426 | |
427 | /* | |
428 | * Print out internal contents of a fifo vnode. | |
429 | */ | |
430 | fifo_printinfo(vp) | |
431 | struct vnode *vp; | |
432 | { | |
433 | register struct fifoinfo *fip = vp->v_fifoinfo; | |
434 | ||
435 | printf(", fifo with %d readers and %d writers", | |
436 | fip->fi_readers, fip->fi_writers); | |
437 | } | |
438 | ||
439 | /* | |
440 | * Fifo failed operation | |
441 | */ | |
442 | fifo_ebadf() | |
443 | { | |
444 | ||
445 | return (EBADF); | |
446 | } | |
447 | ||
a4128336 KM |
448 | /* |
449 | * Fifo advisory byte-level locks. | |
450 | */ | |
81b4c293 | 451 | /* ARGSUSED */ |
9342689a JH |
452 | fifo_advlock (ap) |
453 | struct vop_advlock_args *ap; | |
454 | #define vp (ap->a_vp) | |
455 | #define id (ap->a_id) | |
456 | #define op (ap->a_op) | |
457 | #define fl (ap->a_fl) | |
458 | #define flags (ap->a_flags) | |
a4128336 KM |
459 | { |
460 | ||
461 | return (EOPNOTSUPP); | |
462 | } | |
9342689a JH |
463 | #undef vp |
464 | #undef id | |
465 | #undef op | |
466 | #undef fl | |
467 | #undef flags | |
a4128336 | 468 | |
cc6b488e KM |
469 | /* |
470 | * Fifo bad operation | |
471 | */ | |
472 | fifo_badop() | |
473 | { | |
474 | ||
475 | panic("fifo_badop called"); | |
476 | /* NOTREACHED */ | |
477 | } |