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