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