]> git.saurik.com Git - apple/xnu.git/blame - bsd/miscfs/specfs/spec_vnops.c
xnu-201.tar.gz
[apple/xnu.git] / bsd / miscfs / specfs / spec_vnops.c
CommitLineData
1c79356b
A
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
77struct vnode *speclisth[SPECHSZ];
78
79/* symbolic sleep message strings for devices */
80char devopn[] = "devopn";
81char devio[] = "devio";
82char devwait[] = "devwait";
83char devin[] = "devin";
84char devout[] = "devout";
85char devioc[] = "devioc";
86char devcls[] = "devcls";
87
88#define VOPFUNC int (*)(void *)
89
90int (**spec_vnodeop_p)(void *);
91struct 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};
144struct vnodeopv_desc spec_vnodeop_opv_desc =
145 { &spec_vnodeop_p, spec_vnodeop_entries };
146
147/*
148 * Trivial lookup routine that always fails.
149 */
150int
151spec_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
163void
164set_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
180void
181set_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 */
201spec_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 */
285spec_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 */
375spec_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 */
474spec_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 */
508spec_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;
0b4e3aa0 514 void * a_wql;
1c79356b
A
515 struct proc *a_p;
516 } */ *ap;
517{
518 register dev_t dev;
519
520 switch (ap->a_vp->v_type) {
521
522 default:
523 return (1); /* XXX */
524
525 case VCHR:
526 dev = ap->a_vp->v_rdev;
0b4e3aa0 527 return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_wql, ap->a_p);
1c79356b
A
528 }
529}
530/*
531 * Synch buffers associated with a block device
532 */
533/* ARGSUSED */
534int
535spec_fsync(ap)
536 struct vop_fsync_args /* {
537 struct vnode *a_vp;
538 struct ucred *a_cred;
539 int a_waitfor;
540 struct proc *a_p;
541 } */ *ap;
542{
543 register struct vnode *vp = ap->a_vp;
544 register struct buf *bp;
545 struct buf *nbp;
546 int s;
547
548 if (vp->v_type == VCHR)
549 return (0);
550 /*
551 * Flush all dirty buffers associated with a block device.
552 */
553loop:
554 s = splbio();
555 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
556 nbp = bp->b_vnbufs.le_next;
557 if ((bp->b_flags & B_BUSY))
558 continue;
559 if ((bp->b_flags & B_DELWRI) == 0)
560 panic("spec_fsync: not dirty");
561 bremfree(bp);
562 bp->b_flags |= B_BUSY;
563 splx(s);
564 bawrite(bp);
565 goto loop;
566 }
567 if (ap->a_waitfor == MNT_WAIT) {
568 while (vp->v_numoutput) {
569 vp->v_flag |= VBWAIT;
570 tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "spec_fsync", 0);
571 }
572#if DIAGNOSTIC
573 if (vp->v_dirtyblkhd.lh_first) {
574 vprint("spec_fsync: dirty", vp);
575 splx(s);
576 goto loop;
577 }
578#endif
579 }
580 splx(s);
581 return (0);
582}
583
584/*
585 * Just call the device strategy routine
586 */
587spec_strategy(ap)
588 struct vop_strategy_args /* {
589 struct buf *a_bp;
590 } */ *ap;
591{
592 (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp);
593 return (0);
594}
595
596/*
597 * This is a noop, simply returning what one has been given.
598 */
599spec_bmap(ap)
600 struct vop_bmap_args /* {
601 struct vnode *a_vp;
602 daddr_t a_bn;
603 struct vnode **a_vpp;
604 daddr_t *a_bnp;
605 int *a_runp;
606 } */ *ap;
607{
608
609 if (ap->a_vpp != NULL)
610 *ap->a_vpp = ap->a_vp;
611 if (ap->a_bnp != NULL)
612 *ap->a_bnp = ap->a_bn * (PAGE_SIZE / ap->a_vp->v_specsize);
613 if (ap->a_runp != NULL)
614 *ap->a_runp = (MAXPHYSIO / PAGE_SIZE) - 1;
615 return (0);
616}
617
618/*
619 * This is a noop, simply returning what one has been given.
620 */
621spec_cmap(ap)
622 struct vop_cmap_args /* {
623 struct vnode *a_vp;
624 off_t a_offset;
625 size_t a_size;
626 daddr_t *a_bpn;
627 size_t *a_run;
628 void *a_poff;
629 } */ *ap;
630{
631 return (EOPNOTSUPP);
632}
633
634
635/*
636 * Device close routine
637 */
638/* ARGSUSED */
639spec_close(ap)
640 struct vop_close_args /* {
641 struct vnode *a_vp;
642 int a_fflag;
643 struct ucred *a_cred;
644 struct proc *a_p;
645 } */ *ap;
646{
647 register struct vnode *vp = ap->a_vp;
648 dev_t dev = vp->v_rdev;
649 int (*devclose) __P((dev_t, int, int, struct proc *));
650 int mode, error;
651
652 switch (vp->v_type) {
653
654 case VCHR:
655 /*
656 * Hack: a tty device that is a controlling terminal
657 * has a reference from the session structure.
658 * We cannot easily tell that a character device is
659 * a controlling terminal, unless it is the closing
660 * process' controlling terminal. In that case,
661 * if the reference count is 2 (this last descriptor
662 * plus the session), release the reference from the session.
663 */
664 if (vcount(vp) == 2 && ap->a_p &&
665 vp == ap->a_p->p_session->s_ttyvp) {
666 vrele(vp);
667 ap->a_p->p_session->s_ttyvp = NULL;
668 }
669 /*
670 * If the vnode is locked, then we are in the midst
671 * of forcably closing the device, otherwise we only
672 * close on last reference.
673 */
674 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
675 return (0);
676 devclose = cdevsw[major(dev)].d_close;
677 mode = S_IFCHR;
678 break;
679
680 case VBLK:
0b4e3aa0 681#ifdef DEVFS_IMPLEMENTS_LOCKING
1c79356b
A
682 /*
683 * On last close of a block device (that isn't mounted)
684 * we must invalidate any in core blocks, so that
685 * we can, for instance, change floppy disks.
686 */
0b4e3aa0
A
687 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
688 error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0);
689 VOP_UNLOCK(vp, 0, ap->a_p);
690 if (error)
1c79356b
A
691 return (error);
692 /*
693 * We do not want to really close the device if it
694 * is still in use unless we are trying to close it
695 * forcibly. Since every use (buffer, vnode, swap, cmap)
696 * holds a reference to the vnode, and because we mark
697 * any other vnodes that alias this device, when the
698 * sum of the reference counts on all the aliased
699 * vnodes descends to one, we are on last close.
700 */
701 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
702 return (0);
0b4e3aa0
A
703#else /* DEVFS_IMPLEMENTS_LOCKING */
704 /*
705 * We do not want to really close the device if it
706 * is still in use unless we are trying to close it
707 * forcibly. Since every use (buffer, vnode, swap, cmap)
708 * holds a reference to the vnode, and because we mark
709 * any other vnodes that alias this device, when the
710 * sum of the reference counts on all the aliased
711 * vnodes descends to one, we are on last close.
712 */
713 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
714 return (0);
715
716 /*
717 * On last close of a block device (that isn't mounted)
718 * we must invalidate any in core blocks, so that
719 * we can, for instance, change floppy disks.
720 */
721 error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0);
722 if (error)
723 return (error);
724#endif /* DEVFS_IMPLEMENTS_LOCKING */
1c79356b
A
725 devclose = bdevsw[major(dev)].d_close;
726 mode = S_IFBLK;
727 break;
728
729 default:
730 panic("spec_close: not special");
731 }
732
733 return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p));
734}
735
736/*
737 * Print out the contents of a special device vnode.
738 */
739spec_print(ap)
740 struct vop_print_args /* {
741 struct vnode *a_vp;
742 } */ *ap;
743{
744
745 printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev),
746 minor(ap->a_vp->v_rdev));
747}
748
749/*
750 * Return POSIX pathconf information applicable to special devices.
751 */
752spec_pathconf(ap)
753 struct vop_pathconf_args /* {
754 struct vnode *a_vp;
755 int a_name;
756 int *a_retval;
757 } */ *ap;
758{
759
760 switch (ap->a_name) {
761 case _PC_LINK_MAX:
762 *ap->a_retval = LINK_MAX;
763 return (0);
764 case _PC_MAX_CANON:
765 *ap->a_retval = MAX_CANON;
766 return (0);
767 case _PC_MAX_INPUT:
768 *ap->a_retval = MAX_INPUT;
769 return (0);
770 case _PC_PIPE_BUF:
771 *ap->a_retval = PIPE_BUF;
772 return (0);
773 case _PC_CHOWN_RESTRICTED:
774 *ap->a_retval = 1;
775 return (0);
776 case _PC_VDISABLE:
777 *ap->a_retval = _POSIX_VDISABLE;
778 return (0);
779 default:
780 return (EINVAL);
781 }
782 /* NOTREACHED */
783}
784
785int
786spec_devblocksize(ap)
787 struct vop_devblocksize_args /* {
788 struct vnode *a_vp;
789 int *a_retval;
790 } */ *ap;
791{
792 *ap->a_retval = (ap->a_vp->v_specsize);
793 return (0);
794}
795
796/*
797 * Special device failed operation
798 */
799spec_ebadf()
800{
801
802 return (EBADF);
803}
804
805/*
806 * Special device bad operation
807 */
808spec_badop()
809{
810
811 panic("spec_badop called");
812 /* NOTREACHED */
813}
814
815/* Blktooff derives file offset from logical block number */
816int
817spec_blktooff(ap)
818 struct vop_blktooff_args /* {
819 struct vnode *a_vp;
820 daddr_t a_lblkno;
821 off_t *a_offset;
822 } */ *ap;
823{
824 register struct vnode *vp = ap->a_vp;
825
826 switch (vp->v_type) {
827 case VCHR:
828 *ap->a_offset = (off_t)-1; /* failure */
829 return (EOPNOTSUPP);
830
831 case VBLK:
832 printf("spec_blktooff: not implemented for VBLK\n");
833 *ap->a_offset = (off_t)-1; /* failure */
834 return (EOPNOTSUPP);
835
836 default:
837 panic("spec_blktooff type");
838 }
839 /* NOTREACHED */
840}
841
842/* Offtoblk derives logical block number from file offset */
843int
844spec_offtoblk(ap)
845 struct vop_offtoblk_args /* {
846 struct vnode *a_vp;
847 off_t a_offset;
848 daddr_t *a_lblkno;
849 } */ *ap;
850{
851 register struct vnode *vp = ap->a_vp;
852
853 switch (vp->v_type) {
854 case VCHR:
855 *ap->a_lblkno = (daddr_t)-1; /* failure */
856 return (EOPNOTSUPP);
857
858 case VBLK:
859 printf("spec_offtoblk: not implemented for VBLK\n");
860 *ap->a_lblkno = (daddr_t)-1; /* failure */
861 return (EOPNOTSUPP);
862
863 default:
864 panic("spec_offtoblk type");
865 }
866 /* NOTREACHED */
867}