]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/specfs/spec_vnops.c
5391c20aacaad1ec8fe3b588422dc6d583eed749
[apple/xnu.git] / bsd / miscfs / specfs / spec_vnops.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23 /*
24 * Copyright (c) 1989, 1993, 1995
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 *
55 * @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95
56 */
57
58 #include <sys/param.h>
59 #include <sys/proc.h>
60 #include <sys/systm.h>
61 #include <sys/kernel.h>
62 #include <sys/conf.h>
63 #include <sys/buf.h>
64 #include <sys/mount.h>
65 #include <sys/namei.h>
66 #include <sys/vnode.h>
67 #include <sys/stat.h>
68 #include <sys/errno.h>
69 #include <sys/ioctl.h>
70 #include <sys/file.h>
71 #include <sys/malloc.h>
72 #include <dev/disk.h>
73 #include <miscfs/specfs/specdev.h>
74 #include <vfs/vfs_support.h>
75
76
77 struct vnode *speclisth[SPECHSZ];
78
79 /* symbolic sleep message strings for devices */
80 char devopn[] = "devopn";
81 char devio[] = "devio";
82 char devwait[] = "devwait";
83 char devin[] = "devin";
84 char devout[] = "devout";
85 char devioc[] = "devioc";
86 char devcls[] = "devcls";
87
88 #define VOPFUNC int (*)(void *)
89
90 int (**spec_vnodeop_p)(void *);
91 struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
92 { &vop_default_desc, (VOPFUNC)vn_default_error },
93 { &vop_lookup_desc, (VOPFUNC)spec_lookup }, /* lookup */
94 { &vop_create_desc, (VOPFUNC)err_create }, /* create */
95 { &vop_mknod_desc, (VOPFUNC)err_mknod }, /* mknod */
96 { &vop_open_desc, (VOPFUNC)spec_open }, /* open */
97 { &vop_close_desc, (VOPFUNC)spec_close }, /* close */
98 { &vop_access_desc, (VOPFUNC)spec_access }, /* access */
99 { &vop_getattr_desc, (VOPFUNC)spec_getattr }, /* getattr */
100 { &vop_setattr_desc, (VOPFUNC)spec_setattr }, /* setattr */
101 { &vop_read_desc, (VOPFUNC)spec_read }, /* read */
102 { &vop_write_desc, (VOPFUNC)spec_write }, /* write */
103 { &vop_lease_desc, (VOPFUNC)nop_lease }, /* lease */
104 { &vop_ioctl_desc, (VOPFUNC)spec_ioctl }, /* ioctl */
105 { &vop_select_desc, (VOPFUNC)spec_select }, /* select */
106 { &vop_revoke_desc, (VOPFUNC)nop_revoke }, /* revoke */
107 { &vop_mmap_desc, (VOPFUNC)err_mmap }, /* mmap */
108 { &vop_fsync_desc, (VOPFUNC)spec_fsync }, /* fsync */
109 { &vop_seek_desc, (VOPFUNC)err_seek }, /* seek */
110 { &vop_remove_desc, (VOPFUNC)err_remove }, /* remove */
111 { &vop_link_desc, (VOPFUNC)err_link }, /* link */
112 { &vop_rename_desc, (VOPFUNC)err_rename }, /* rename */
113 { &vop_mkdir_desc, (VOPFUNC)err_mkdir }, /* mkdir */
114 { &vop_rmdir_desc, (VOPFUNC)err_rmdir }, /* rmdir */
115 { &vop_symlink_desc, (VOPFUNC)err_symlink }, /* symlink */
116 { &vop_readdir_desc, (VOPFUNC)err_readdir }, /* readdir */
117 { &vop_readlink_desc, (VOPFUNC)err_readlink }, /* readlink */
118 { &vop_abortop_desc, (VOPFUNC)err_abortop }, /* abortop */
119 { &vop_inactive_desc, (VOPFUNC)nop_inactive }, /* inactive */
120 { &vop_reclaim_desc, (VOPFUNC)nop_reclaim }, /* reclaim */
121 { &vop_lock_desc, (VOPFUNC)nop_lock }, /* lock */
122 { &vop_unlock_desc, (VOPFUNC)nop_unlock }, /* unlock */
123 { &vop_bmap_desc, (VOPFUNC)spec_bmap }, /* bmap */
124 { &vop_strategy_desc, (VOPFUNC)spec_strategy }, /* strategy */
125 { &vop_print_desc, (VOPFUNC)spec_print }, /* print */
126 { &vop_islocked_desc, (VOPFUNC)nop_islocked }, /* islocked */
127 { &vop_pathconf_desc, (VOPFUNC)spec_pathconf }, /* pathconf */
128 { &vop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */
129 { &vop_blkatoff_desc, (VOPFUNC)err_blkatoff }, /* blkatoff */
130 { &vop_valloc_desc, (VOPFUNC)err_valloc }, /* valloc */
131 { &vop_vfree_desc, (VOPFUNC)err_vfree }, /* vfree */
132 { &vop_truncate_desc, (VOPFUNC)nop_truncate }, /* truncate */
133 { &vop_update_desc, (VOPFUNC)nop_update }, /* update */
134 { &vop_bwrite_desc, (VOPFUNC)spec_bwrite }, /* bwrite */
135 { &vop_devblocksize_desc, (VOPFUNC)spec_devblocksize }, /* devblocksize */
136 { &vop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */
137 { &vop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */
138 { &vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */
139 { &vop_blktooff_desc, (VOPFUNC)spec_blktooff }, /* blktooff */
140 { &vop_offtoblk_desc, (VOPFUNC)spec_offtoblk }, /* offtoblk */
141 { &vop_cmap_desc, (VOPFUNC)spec_cmap }, /* cmap */
142 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
143 };
144 struct vnodeopv_desc spec_vnodeop_opv_desc =
145 { &spec_vnodeop_p, spec_vnodeop_entries };
146
147 /*
148 * Trivial lookup routine that always fails.
149 */
150 int
151 spec_lookup(ap)
152 struct vop_lookup_args /* {
153 struct vnode *a_dvp;
154 struct vnode **a_vpp;
155 struct componentname *a_cnp;
156 } */ *ap;
157 {
158
159 *ap->a_vpp = NULL;
160 return (ENOTDIR);
161 }
162
163 void
164 set_blocksize(struct vnode *vp, dev_t dev)
165 {
166 int (*size)();
167 int rsize;
168
169 if ((major(dev) < nblkdev) && (size = bdevsw[major(dev)].d_psize)) {
170 rsize = (*size)(dev);
171 if (rsize <= 0) /* did size fail? */
172 vp->v_specsize = DEV_BSIZE;
173 else
174 vp->v_specsize = rsize;
175 }
176 else
177 vp->v_specsize = DEV_BSIZE;
178 }
179
180 void
181 set_fsblocksize(struct vnode *vp)
182 {
183
184 if (vp->v_type == VBLK) {
185 dev_t dev = (dev_t)vp->v_rdev;
186 int maj = major(dev);
187
188 if ((u_int)maj >= nblkdev)
189 return;
190
191 set_blocksize(vp, dev);
192 }
193
194 }
195
196
197 /*
198 * Open a special file.
199 */
200 /* ARGSUSED */
201 spec_open(ap)
202 struct vop_open_args /* {
203 struct vnode *a_vp;
204 int a_mode;
205 struct ucred *a_cred;
206 struct proc *a_p;
207 } */ *ap;
208 {
209 struct proc *p = ap->a_p;
210 struct vnode *bvp, *vp = ap->a_vp;
211 dev_t bdev, dev = (dev_t)vp->v_rdev;
212 int maj = major(dev);
213 int error;
214
215 /*
216 * Don't allow open if fs is mounted -nodev.
217 */
218 if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
219 return (ENXIO);
220
221 switch (vp->v_type) {
222
223 case VCHR:
224 if ((u_int)maj >= nchrdev)
225 return (ENXIO);
226 if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) {
227 /*
228 * When running in very secure mode, do not allow
229 * opens for writing of any disk character devices.
230 */
231 if (securelevel >= 2 && isdisk(dev, VCHR))
232 return (EPERM);
233 /*
234 * When running in secure mode, do not allow opens
235 * for writing of /dev/mem, /dev/kmem, or character
236 * devices whose corresponding block devices are
237 * currently mounted.
238 */
239 if (securelevel >= 1) {
240 if ((bdev = chrtoblk(dev)) != NODEV &&
241 vfinddev(bdev, VBLK, &bvp) &&
242 bvp->v_usecount > 0 &&
243 (error = vfs_mountedon(bvp)))
244 return (error);
245 if (iskmemdev(dev))
246 return (EPERM);
247 }
248 }
249 if (cdevsw[maj].d_type == D_TTY)
250 vp->v_flag |= VISTTY;
251 VOP_UNLOCK(vp, 0, p);
252 error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, p);
253 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
254 return (error);
255
256 case VBLK:
257 if ((u_int)maj >= nblkdev)
258 return (ENXIO);
259 /*
260 * When running in very secure mode, do not allow
261 * opens for writing of any disk block devices.
262 */
263 if (securelevel >= 2 && ap->a_cred != FSCRED &&
264 (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK)
265 return (EPERM);
266 /*
267 * Do not allow opens of block devices that are
268 * currently mounted.
269 */
270 if (error = vfs_mountedon(vp))
271 return (error);
272 error = (*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, p);
273 if (!error) {
274 set_blocksize(vp, dev);
275 }
276 return(error);
277 }
278 return (0);
279 }
280
281 /*
282 * Vnode op for read
283 */
284 /* ARGSUSED */
285 spec_read(ap)
286 struct vop_read_args /* {
287 struct vnode *a_vp;
288 struct uio *a_uio;
289 int a_ioflag;
290 struct ucred *a_cred;
291 } */ *ap;
292 {
293 register struct vnode *vp = ap->a_vp;
294 register struct uio *uio = ap->a_uio;
295 struct proc *p = uio->uio_procp;
296 struct buf *bp;
297 daddr_t bn, nextbn;
298 long bsize, bscale;
299 int devBlockSize=0;
300 int n, on, majordev, (*ioctl)();
301 int error = 0;
302 dev_t dev;
303
304 #if DIAGNOSTIC
305 if (uio->uio_rw != UIO_READ)
306 panic("spec_read mode");
307 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != current_proc())
308 panic("spec_read proc");
309 #endif
310 if (uio->uio_resid == 0)
311 return (0);
312
313 switch (vp->v_type) {
314
315 case VCHR:
316 VOP_UNLOCK(vp, 0, p);
317 error = (*cdevsw[major(vp->v_rdev)].d_read)
318 (vp->v_rdev, uio, ap->a_ioflag);
319 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
320 return (error);
321
322 case VBLK:
323 if (uio->uio_offset < 0)
324 return (EINVAL);
325
326 dev = vp->v_rdev;
327
328 devBlockSize = vp->v_specsize;
329
330 if (devBlockSize > PAGE_SIZE)
331 return (EINVAL);
332
333 bscale = PAGE_SIZE / devBlockSize;
334 bsize = bscale * devBlockSize;
335
336 do {
337 on = uio->uio_offset % bsize;
338
339 bn = (uio->uio_offset / devBlockSize) &~ (bscale - 1);
340
341 if (vp->v_lastr + bscale == bn) {
342 nextbn = bn + bscale;
343 error = breadn(vp, bn, (int)bsize, &nextbn,
344 (int *)&bsize, 1, NOCRED, &bp);
345 } else
346 error = bread(vp, bn, (int)bsize, NOCRED, &bp);
347
348 vp->v_lastr = bn;
349 n = bsize - bp->b_resid;
350 if ((on > n) || error) {
351 if (!error)
352 error = EINVAL;
353 brelse(bp);
354 return (error);
355 }
356 n = min((unsigned)(n - on), uio->uio_resid);
357
358 error = uiomove((char *)bp->b_data + on, n, uio);
359 if (n + on == bsize)
360 bp->b_flags |= B_AGE;
361 brelse(bp);
362 } while (error == 0 && uio->uio_resid > 0 && n != 0);
363 return (error);
364
365 default:
366 panic("spec_read type");
367 }
368 /* NOTREACHED */
369 }
370
371 /*
372 * Vnode op for write
373 */
374 /* ARGSUSED */
375 spec_write(ap)
376 struct vop_write_args /* {
377 struct vnode *a_vp;
378 struct uio *a_uio;
379 int a_ioflag;
380 struct ucred *a_cred;
381 } */ *ap;
382 {
383 register struct vnode *vp = ap->a_vp;
384 register struct uio *uio = ap->a_uio;
385 struct proc *p = uio->uio_procp;
386 struct buf *bp;
387 daddr_t bn;
388 int bsize, blkmask, bscale;
389 register int io_sync;
390 register int io_size;
391 int devBlockSize=0;
392 register int n, on;
393 int error = 0;
394 dev_t dev;
395
396 #if DIAGNOSTIC
397 if (uio->uio_rw != UIO_WRITE)
398 panic("spec_write mode");
399 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != current_proc())
400 panic("spec_write proc");
401 #endif
402
403 switch (vp->v_type) {
404
405 case VCHR:
406 VOP_UNLOCK(vp, 0, p);
407 error = (*cdevsw[major(vp->v_rdev)].d_write)
408 (vp->v_rdev, uio, ap->a_ioflag);
409 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
410 return (error);
411
412 case VBLK:
413 if (uio->uio_resid == 0)
414 return (0);
415 if (uio->uio_offset < 0)
416 return (EINVAL);
417
418 io_sync = (ap->a_ioflag & IO_SYNC);
419 io_size = uio->uio_resid;
420
421 dev = (vp->v_rdev);
422
423 devBlockSize = vp->v_specsize;
424 if (devBlockSize > PAGE_SIZE)
425 return(EINVAL);
426
427 bscale = PAGE_SIZE / devBlockSize;
428 blkmask = bscale - 1;
429 bsize = bscale * devBlockSize;
430
431
432 do {
433 bn = (uio->uio_offset / devBlockSize) &~ blkmask;
434 on = uio->uio_offset % bsize;
435
436 n = min((unsigned)(bsize - on), uio->uio_resid);
437
438 if (n == bsize)
439 bp = getblk(vp, bn, bsize, 0, 0, BLK_WRITE);
440 else
441 error = bread(vp, bn, bsize, NOCRED, &bp);
442
443 if (error) {
444 brelse(bp);
445 return (error);
446 }
447 n = min(n, bsize - bp->b_resid);
448
449 error = uiomove((char *)bp->b_data + on, n, uio);
450
451 bp->b_flags |= B_AGE;
452
453 if (io_sync)
454 bwrite(bp);
455 else {
456 if ((n + on) == bsize)
457 bawrite(bp);
458 else
459 bdwrite(bp);
460 }
461 } while (error == 0 && uio->uio_resid > 0 && n != 0);
462 return (error);
463
464 default:
465 panic("spec_write type");
466 }
467 /* NOTREACHED */
468 }
469
470 /*
471 * Device ioctl operation.
472 */
473 /* ARGSUSED */
474 spec_ioctl(ap)
475 struct vop_ioctl_args /* {
476 struct vnode *a_vp;
477 int a_command;
478 caddr_t a_data;
479 int a_fflag;
480 struct ucred *a_cred;
481 struct proc *a_p;
482 } */ *ap;
483 {
484 dev_t dev = ap->a_vp->v_rdev;
485
486 switch (ap->a_vp->v_type) {
487
488 case VCHR:
489 return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
490 ap->a_fflag, ap->a_p));
491
492 case VBLK:
493 if (ap->a_command == 0 && (int)ap->a_data == B_TAPE)
494 if (bdevsw[major(dev)].d_type == D_TAPE)
495 return (0);
496 else
497 return (1);
498 return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
499 ap->a_fflag, ap->a_p));
500
501 default:
502 panic("spec_ioctl");
503 /* NOTREACHED */
504 }
505 }
506
507 /* ARGSUSED */
508 spec_select(ap)
509 struct vop_select_args /* {
510 struct vnode *a_vp;
511 int a_which;
512 int a_fflags;
513 struct ucred *a_cred;
514 struct proc *a_p;
515 } */ *ap;
516 {
517 register dev_t dev;
518
519 switch (ap->a_vp->v_type) {
520
521 default:
522 return (1); /* XXX */
523
524 case VCHR:
525 dev = ap->a_vp->v_rdev;
526 return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p);
527 }
528 }
529 /*
530 * Synch buffers associated with a block device
531 */
532 /* ARGSUSED */
533 int
534 spec_fsync(ap)
535 struct vop_fsync_args /* {
536 struct vnode *a_vp;
537 struct ucred *a_cred;
538 int a_waitfor;
539 struct proc *a_p;
540 } */ *ap;
541 {
542 register struct vnode *vp = ap->a_vp;
543 register struct buf *bp;
544 struct buf *nbp;
545 int s;
546
547 if (vp->v_type == VCHR)
548 return (0);
549 /*
550 * Flush all dirty buffers associated with a block device.
551 */
552 loop:
553 s = splbio();
554 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
555 nbp = bp->b_vnbufs.le_next;
556 if ((bp->b_flags & B_BUSY))
557 continue;
558 if ((bp->b_flags & B_DELWRI) == 0)
559 panic("spec_fsync: not dirty");
560 bremfree(bp);
561 bp->b_flags |= B_BUSY;
562 splx(s);
563 bawrite(bp);
564 goto loop;
565 }
566 if (ap->a_waitfor == MNT_WAIT) {
567 while (vp->v_numoutput) {
568 vp->v_flag |= VBWAIT;
569 tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "spec_fsync", 0);
570 }
571 #if DIAGNOSTIC
572 if (vp->v_dirtyblkhd.lh_first) {
573 vprint("spec_fsync: dirty", vp);
574 splx(s);
575 goto loop;
576 }
577 #endif
578 }
579 splx(s);
580 return (0);
581 }
582
583 /*
584 * Just call the device strategy routine
585 */
586 spec_strategy(ap)
587 struct vop_strategy_args /* {
588 struct buf *a_bp;
589 } */ *ap;
590 {
591 (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp);
592 return (0);
593 }
594
595 /*
596 * This is a noop, simply returning what one has been given.
597 */
598 spec_bmap(ap)
599 struct vop_bmap_args /* {
600 struct vnode *a_vp;
601 daddr_t a_bn;
602 struct vnode **a_vpp;
603 daddr_t *a_bnp;
604 int *a_runp;
605 } */ *ap;
606 {
607
608 if (ap->a_vpp != NULL)
609 *ap->a_vpp = ap->a_vp;
610 if (ap->a_bnp != NULL)
611 *ap->a_bnp = ap->a_bn * (PAGE_SIZE / ap->a_vp->v_specsize);
612 if (ap->a_runp != NULL)
613 *ap->a_runp = (MAXPHYSIO / PAGE_SIZE) - 1;
614 return (0);
615 }
616
617 /*
618 * This is a noop, simply returning what one has been given.
619 */
620 spec_cmap(ap)
621 struct vop_cmap_args /* {
622 struct vnode *a_vp;
623 off_t a_offset;
624 size_t a_size;
625 daddr_t *a_bpn;
626 size_t *a_run;
627 void *a_poff;
628 } */ *ap;
629 {
630 return (EOPNOTSUPP);
631 }
632
633
634 /*
635 * Device close routine
636 */
637 /* ARGSUSED */
638 spec_close(ap)
639 struct vop_close_args /* {
640 struct vnode *a_vp;
641 int a_fflag;
642 struct ucred *a_cred;
643 struct proc *a_p;
644 } */ *ap;
645 {
646 register struct vnode *vp = ap->a_vp;
647 dev_t dev = vp->v_rdev;
648 int (*devclose) __P((dev_t, int, int, struct proc *));
649 int mode, error;
650
651 switch (vp->v_type) {
652
653 case VCHR:
654 /*
655 * Hack: a tty device that is a controlling terminal
656 * has a reference from the session structure.
657 * We cannot easily tell that a character device is
658 * a controlling terminal, unless it is the closing
659 * process' controlling terminal. In that case,
660 * if the reference count is 2 (this last descriptor
661 * plus the session), release the reference from the session.
662 */
663 if (vcount(vp) == 2 && ap->a_p &&
664 vp == ap->a_p->p_session->s_ttyvp) {
665 vrele(vp);
666 ap->a_p->p_session->s_ttyvp = NULL;
667 }
668 /*
669 * If the vnode is locked, then we are in the midst
670 * of forcably closing the device, otherwise we only
671 * close on last reference.
672 */
673 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
674 return (0);
675 devclose = cdevsw[major(dev)].d_close;
676 mode = S_IFCHR;
677 break;
678
679 case VBLK:
680 /*
681 * On last close of a block device (that isn't mounted)
682 * we must invalidate any in core blocks, so that
683 * we can, for instance, change floppy disks.
684 */
685 if (error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0))
686 return (error);
687 /*
688 * We do not want to really close the device if it
689 * is still in use unless we are trying to close it
690 * forcibly. Since every use (buffer, vnode, swap, cmap)
691 * holds a reference to the vnode, and because we mark
692 * any other vnodes that alias this device, when the
693 * sum of the reference counts on all the aliased
694 * vnodes descends to one, we are on last close.
695 */
696 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
697 return (0);
698 devclose = bdevsw[major(dev)].d_close;
699 mode = S_IFBLK;
700 break;
701
702 default:
703 panic("spec_close: not special");
704 }
705
706 return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p));
707 }
708
709 /*
710 * Print out the contents of a special device vnode.
711 */
712 spec_print(ap)
713 struct vop_print_args /* {
714 struct vnode *a_vp;
715 } */ *ap;
716 {
717
718 printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
719 minor(ap->a_vp->v_rdev));
720 }
721
722 /*
723 * Return POSIX pathconf information applicable to special devices.
724 */
725 spec_pathconf(ap)
726 struct vop_pathconf_args /* {
727 struct vnode *a_vp;
728 int a_name;
729 int *a_retval;
730 } */ *ap;
731 {
732
733 switch (ap->a_name) {
734 case _PC_LINK_MAX:
735 *ap->a_retval = LINK_MAX;
736 return (0);
737 case _PC_MAX_CANON:
738 *ap->a_retval = MAX_CANON;
739 return (0);
740 case _PC_MAX_INPUT:
741 *ap->a_retval = MAX_INPUT;
742 return (0);
743 case _PC_PIPE_BUF:
744 *ap->a_retval = PIPE_BUF;
745 return (0);
746 case _PC_CHOWN_RESTRICTED:
747 *ap->a_retval = 1;
748 return (0);
749 case _PC_VDISABLE:
750 *ap->a_retval = _POSIX_VDISABLE;
751 return (0);
752 default:
753 return (EINVAL);
754 }
755 /* NOTREACHED */
756 }
757
758 int
759 spec_devblocksize(ap)
760 struct vop_devblocksize_args /* {
761 struct vnode *a_vp;
762 int *a_retval;
763 } */ *ap;
764 {
765 *ap->a_retval = (ap->a_vp->v_specsize);
766 return (0);
767 }
768
769 /*
770 * Special device failed operation
771 */
772 spec_ebadf()
773 {
774
775 return (EBADF);
776 }
777
778 /*
779 * Special device bad operation
780 */
781 spec_badop()
782 {
783
784 panic("spec_badop called");
785 /* NOTREACHED */
786 }
787
788 /* Blktooff derives file offset from logical block number */
789 int
790 spec_blktooff(ap)
791 struct vop_blktooff_args /* {
792 struct vnode *a_vp;
793 daddr_t a_lblkno;
794 off_t *a_offset;
795 } */ *ap;
796 {
797 register struct vnode *vp = ap->a_vp;
798
799 switch (vp->v_type) {
800 case VCHR:
801 *ap->a_offset = (off_t)-1; /* failure */
802 return (EOPNOTSUPP);
803
804 case VBLK:
805 printf("spec_blktooff: not implemented for VBLK\n");
806 *ap->a_offset = (off_t)-1; /* failure */
807 return (EOPNOTSUPP);
808
809 default:
810 panic("spec_blktooff type");
811 }
812 /* NOTREACHED */
813 }
814
815 /* Offtoblk derives logical block number from file offset */
816 int
817 spec_offtoblk(ap)
818 struct vop_offtoblk_args /* {
819 struct vnode *a_vp;
820 off_t a_offset;
821 daddr_t *a_lblkno;
822 } */ *ap;
823 {
824 register struct vnode *vp = ap->a_vp;
825
826 switch (vp->v_type) {
827 case VCHR:
828 *ap->a_lblkno = (daddr_t)-1; /* failure */
829 return (EOPNOTSUPP);
830
831 case VBLK:
832 printf("spec_offtoblk: not implemented for VBLK\n");
833 *ap->a_lblkno = (daddr_t)-1; /* failure */
834 return (EOPNOTSUPP);
835
836 default:
837 panic("spec_offtoblk type");
838 }
839 /* NOTREACHED */
840 }