1 /* $NetBSD: spec_vnops.c,v 1.58 2001/09/21 08:02:55 chs Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)spec_vnops.c 8.15 (Berkeley) 7/14/95 36 */ 37 38 #include <sys/param.h> 39 #include <sys/proc.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/conf.h> 43 #include <sys/buf.h> 44 #include <sys/mount.h> 45 #include <sys/namei.h> 46 #include <sys/vnode.h> 47 #include <sys/stat.h> 48 #include <sys/errno.h> 49 #include <sys/ioctl.h> 50 #include <sys/file.h> 51 #include <sys/disklabel.h> 52 #include <sys/lockf.h> 53 54 #include <miscfs/genfs/genfs.h> 55 #include <miscfs/specfs/specdev.h> 56 57 /* symbolic sleep message strings for devices */ 58 const char devopn[] = "devopn"; 59 const char devio[] = "devio"; 60 const char devwait[] = "devwait"; 61 const char devin[] = "devin"; 62 const char devout[] = "devout"; 63 const char devioc[] = "devioc"; 64 const char devcls[] = "devcls"; 65 66 /* 67 * This vnode operations vector is used for two things only: 68 * - special device nodes created from whole cloth by the kernel. 69 * - as a temporary vnodeops replacement for vnodes which were found to 70 * be aliased by callers of checkalias(). 71 * For the ops vector for vnodes built from special devices found in a 72 * filesystem, see (e.g) ffs_specop_entries[] in ffs_vnops.c or the 73 * equivalent for other filesystems. 74 */ 75 76 int (**spec_vnodeop_p) __P((void *)); 77 const struct vnodeopv_entry_desc spec_vnodeop_entries[] = { 78 { &vop_default_desc, vn_default_error }, 79 { &vop_lookup_desc, spec_lookup }, /* lookup */ 80 { &vop_create_desc, spec_create }, /* create */ 81 { &vop_mknod_desc, spec_mknod }, /* mknod */ 82 { &vop_open_desc, spec_open }, /* open */ 83 { &vop_close_desc, spec_close }, /* close */ 84 { &vop_access_desc, spec_access }, /* access */ 85 { &vop_getattr_desc, spec_getattr }, /* getattr */ 86 { &vop_setattr_desc, spec_setattr }, /* setattr */ 87 { &vop_read_desc, spec_read }, /* read */ 88 { &vop_write_desc, spec_write }, /* write */ 89 { &vop_lease_desc, spec_lease_check }, /* lease */ 90 { &vop_fcntl_desc, spec_fcntl }, /* fcntl */ 91 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 92 { &vop_poll_desc, spec_poll }, /* poll */ 93 { &vop_revoke_desc, spec_revoke }, /* revoke */ 94 { &vop_mmap_desc, spec_mmap }, /* mmap */ 95 { &vop_fsync_desc, spec_fsync }, /* fsync */ 96 { &vop_seek_desc, spec_seek }, /* seek */ 97 { &vop_remove_desc, spec_remove }, /* remove */ 98 { &vop_link_desc, spec_link }, /* link */ 99 { &vop_rename_desc, spec_rename }, /* rename */ 100 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 101 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 102 { &vop_symlink_desc, spec_symlink }, /* symlink */ 103 { &vop_readdir_desc, spec_readdir }, /* readdir */ 104 { &vop_readlink_desc, spec_readlink }, /* readlink */ 105 { &vop_abortop_desc, spec_abortop }, /* abortop */ 106 { &vop_inactive_desc, spec_inactive }, /* inactive */ 107 { &vop_reclaim_desc, spec_reclaim }, /* reclaim */ 108 { &vop_lock_desc, spec_lock }, /* lock */ 109 { &vop_unlock_desc, spec_unlock }, /* unlock */ 110 { &vop_bmap_desc, spec_bmap }, /* bmap */ 111 { &vop_strategy_desc, spec_strategy }, /* strategy */ 112 { &vop_print_desc, spec_print }, /* print */ 113 { &vop_islocked_desc, spec_islocked }, /* islocked */ 114 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 115 { &vop_advlock_desc, spec_advlock }, /* advlock */ 116 { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 117 { &vop_valloc_desc, spec_valloc }, /* valloc */ 118 { &vop_vfree_desc, spec_vfree }, /* vfree */ 119 { &vop_truncate_desc, spec_truncate }, /* truncate */ 120 { &vop_update_desc, spec_update }, /* update */ 121 { &vop_bwrite_desc, spec_bwrite }, /* bwrite */ 122 { &vop_getpages_desc, spec_getpages }, /* getpages */ 123 { &vop_putpages_desc, spec_putpages }, /* putpages */ 124 { NULL, NULL } 125 }; 126 const struct vnodeopv_desc spec_vnodeop_opv_desc = 127 { &spec_vnodeop_p, spec_vnodeop_entries }; 128 129 /* 130 * Trivial lookup routine that always fails. 131 */ 132 int 133 spec_lookup(v) 134 void *v; 135 { 136 struct vop_lookup_args /* { 137 struct vnode *a_dvp; 138 struct vnode **a_vpp; 139 struct componentname *a_cnp; 140 } */ *ap = v; 141 142 *ap->a_vpp = NULL; 143 return (ENOTDIR); 144 } 145 146 /* 147 * Open a special file. 148 */ 149 /* ARGSUSED */ 150 int 151 spec_open(v) 152 void *v; 153 { 154 struct vop_open_args /* { 155 struct vnode *a_vp; 156 int a_mode; 157 struct ucred *a_cred; 158 struct proc *a_p; 159 } */ *ap = v; 160 struct proc *p = ap->a_p; 161 struct vnode *bvp, *vp = ap->a_vp; 162 dev_t bdev, dev = (dev_t)vp->v_rdev; 163 int maj = major(dev); 164 int error; 165 struct partinfo pi; 166 167 /* 168 * Don't allow open if fs is mounted -nodev. 169 */ 170 if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 171 return (ENXIO); 172 173 switch (vp->v_type) { 174 175 case VCHR: 176 if ((u_int)maj >= nchrdev) 177 return (ENXIO); 178 if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) { 179 /* 180 * When running in very secure mode, do not allow 181 * opens for writing of any disk character devices. 182 */ 183 if (securelevel >= 2 && cdevsw[maj].d_type == D_DISK) 184 return (EPERM); 185 /* 186 * When running in secure mode, do not allow opens 187 * for writing of /dev/mem, /dev/kmem, or character 188 * devices whose corresponding block devices are 189 * currently mounted. 190 */ 191 if (securelevel >= 1) { 192 if ((bdev = chrtoblk(dev)) != (dev_t)NODEV && 193 vfinddev(bdev, VBLK, &bvp) && 194 (error = vfs_mountedon(bvp))) 195 return (error); 196 if (iskmemdev(dev)) 197 return (EPERM); 198 } 199 } 200 if (cdevsw[maj].d_type == D_TTY) 201 vp->v_flag |= VISTTY; 202 VOP_UNLOCK(vp, 0); 203 error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, p); 204 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 205 return (error); 206 207 case VBLK: 208 if ((u_int)maj >= nblkdev) 209 return (ENXIO); 210 /* 211 * When running in very secure mode, do not allow 212 * opens for writing of any disk block devices. 213 */ 214 if (securelevel >= 2 && ap->a_cred != FSCRED && 215 (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK) 216 return (EPERM); 217 /* 218 * Do not allow opens of block devices that are 219 * currently mounted. 220 */ 221 if ((error = vfs_mountedon(vp)) != 0) 222 return (error); 223 error = (*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, p); 224 if (error) { 225 return error; 226 } 227 error = (*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, 228 DIOCGPART, (caddr_t)&pi, FREAD, curproc); 229 if (error == 0) { 230 vp->v_size = (voff_t)pi.disklab->d_secsize * 231 pi.part->p_size; 232 } 233 return 0; 234 235 case VNON: 236 case VLNK: 237 case VDIR: 238 case VREG: 239 case VBAD: 240 case VFIFO: 241 case VSOCK: 242 break; 243 } 244 return (0); 245 } 246 247 /* 248 * Vnode op for read 249 */ 250 /* ARGSUSED */ 251 int 252 spec_read(v) 253 void *v; 254 { 255 struct vop_read_args /* { 256 struct vnode *a_vp; 257 struct uio *a_uio; 258 int a_ioflag; 259 struct ucred *a_cred; 260 } */ *ap = v; 261 struct vnode *vp = ap->a_vp; 262 struct uio *uio = ap->a_uio; 263 struct proc *p = uio->uio_procp; 264 struct buf *bp; 265 daddr_t bn; 266 int bsize, bscale, ssize; 267 struct partinfo dpart; 268 int n, on, majordev; 269 int (*ioctl) __P((dev_t, u_long, caddr_t, int, struct proc *)); 270 int error = 0; 271 272 #ifdef DIAGNOSTIC 273 if (uio->uio_rw != UIO_READ) 274 panic("spec_read mode"); 275 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 276 panic("spec_read proc"); 277 #endif 278 if (uio->uio_resid == 0) 279 return (0); 280 281 switch (vp->v_type) { 282 283 case VCHR: 284 VOP_UNLOCK(vp, 0); 285 error = (*cdevsw[major(vp->v_rdev)].d_read) 286 (vp->v_rdev, uio, ap->a_ioflag); 287 vn_lock(vp, LK_SHARED | LK_RETRY); 288 return (error); 289 290 case VBLK: 291 if (uio->uio_offset < 0) 292 return (EINVAL); 293 bsize = BLKDEV_IOSIZE; 294 ssize = DEV_BSIZE; 295 if ((majordev = major(vp->v_rdev)) < nblkdev && 296 (ioctl = bdevsw[majordev].d_ioctl) != NULL && 297 (*ioctl)(vp->v_rdev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0) { 298 if (dpart.part->p_fstype == FS_BSDFFS && 299 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 300 bsize = dpart.part->p_frag * 301 dpart.part->p_fsize; 302 if (dpart.disklab->d_secsize != 0) 303 ssize = dpart.disklab->d_secsize; 304 } 305 bscale = bsize / ssize; 306 do { 307 bn = (uio->uio_offset / ssize) &~ (bscale - 1); 308 on = uio->uio_offset % bsize; 309 n = min((unsigned)(bsize - on), uio->uio_resid); 310 error = bread(vp, bn, bsize, NOCRED, &bp); 311 n = min(n, bsize - bp->b_resid); 312 if (error) { 313 brelse(bp); 314 return (error); 315 } 316 error = uiomove((char *)bp->b_data + on, n, uio); 317 brelse(bp); 318 } while (error == 0 && uio->uio_resid > 0 && n != 0); 319 return (error); 320 321 default: 322 panic("spec_read type"); 323 } 324 /* NOTREACHED */ 325 } 326 327 /* 328 * Vnode op for write 329 */ 330 /* ARGSUSED */ 331 int 332 spec_write(v) 333 void *v; 334 { 335 struct vop_write_args /* { 336 struct vnode *a_vp; 337 struct uio *a_uio; 338 int a_ioflag; 339 struct ucred *a_cred; 340 } */ *ap = v; 341 struct vnode *vp = ap->a_vp; 342 struct uio *uio = ap->a_uio; 343 struct proc *p = uio->uio_procp; 344 struct buf *bp; 345 daddr_t bn; 346 int bsize, bscale, ssize; 347 struct partinfo dpart; 348 int n, on, majordev; 349 int (*ioctl) __P((dev_t, u_long, caddr_t, int, struct proc *)); 350 int error = 0; 351 352 #ifdef DIAGNOSTIC 353 if (uio->uio_rw != UIO_WRITE) 354 panic("spec_write mode"); 355 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 356 panic("spec_write proc"); 357 #endif 358 359 switch (vp->v_type) { 360 361 case VCHR: 362 VOP_UNLOCK(vp, 0); 363 error = (*cdevsw[major(vp->v_rdev)].d_write) 364 (vp->v_rdev, uio, ap->a_ioflag); 365 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 366 return (error); 367 368 case VBLK: 369 if (uio->uio_resid == 0) 370 return (0); 371 if (uio->uio_offset < 0) 372 return (EINVAL); 373 bsize = BLKDEV_IOSIZE; 374 ssize = DEV_BSIZE; 375 if ((majordev = major(vp->v_rdev)) < nblkdev && 376 (ioctl = bdevsw[majordev].d_ioctl) != NULL && 377 (*ioctl)(vp->v_rdev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0) { 378 if (dpart.part->p_fstype == FS_BSDFFS && 379 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 380 bsize = dpart.part->p_frag * 381 dpart.part->p_fsize; 382 if (dpart.disklab->d_secsize != 0) 383 ssize = dpart.disklab->d_secsize; 384 } 385 bscale = bsize / ssize; 386 do { 387 bn = (uio->uio_offset / ssize) &~ (bscale - 1); 388 on = uio->uio_offset % bsize; 389 n = min((unsigned)(bsize - on), uio->uio_resid); 390 if (n == bsize) 391 bp = getblk(vp, bn, bsize, 0, 0); 392 else 393 error = bread(vp, bn, bsize, NOCRED, &bp); 394 if (error) { 395 brelse(bp); 396 return (error); 397 } 398 n = min(n, bsize - bp->b_resid); 399 error = uiomove((char *)bp->b_data + on, n, uio); 400 if (error) 401 brelse(bp); 402 else { 403 if (n + on == bsize) 404 bawrite(bp); 405 else 406 bdwrite(bp); 407 if (bp->b_flags & B_ERROR) 408 error = bp->b_error; 409 } 410 } while (error == 0 && uio->uio_resid > 0 && n != 0); 411 return (error); 412 413 default: 414 panic("spec_write type"); 415 } 416 /* NOTREACHED */ 417 } 418 419 /* 420 * Device ioctl operation. 421 */ 422 /* ARGSUSED */ 423 int 424 spec_ioctl(v) 425 void *v; 426 { 427 struct vop_ioctl_args /* { 428 struct vnode *a_vp; 429 u_long a_command; 430 caddr_t a_data; 431 int a_fflag; 432 struct ucred *a_cred; 433 struct proc *a_p; 434 } */ *ap = v; 435 dev_t dev = ap->a_vp->v_rdev; 436 int maj = major(dev); 437 438 switch (ap->a_vp->v_type) { 439 440 case VCHR: 441 return ((*cdevsw[maj].d_ioctl)(dev, ap->a_command, ap->a_data, 442 ap->a_fflag, ap->a_p)); 443 444 case VBLK: 445 if (ap->a_command == 0 && (long)ap->a_data == B_TAPE) { 446 if (bdevsw[maj].d_type == D_TAPE) 447 return (0); 448 else 449 return (1); 450 } 451 return ((*bdevsw[maj].d_ioctl)(dev, ap->a_command, ap->a_data, 452 ap->a_fflag, ap->a_p)); 453 454 default: 455 panic("spec_ioctl"); 456 /* NOTREACHED */ 457 } 458 } 459 460 /* ARGSUSED */ 461 int 462 spec_poll(v) 463 void *v; 464 { 465 struct vop_poll_args /* { 466 struct vnode *a_vp; 467 int a_events; 468 struct proc *a_p; 469 } */ *ap = v; 470 dev_t dev; 471 472 switch (ap->a_vp->v_type) { 473 474 case VCHR: 475 dev = ap->a_vp->v_rdev; 476 return (*cdevsw[major(dev)].d_poll)(dev, ap->a_events, ap->a_p); 477 478 default: 479 return (genfs_poll(v)); 480 } 481 } 482 /* 483 * Synch buffers associated with a block device 484 */ 485 /* ARGSUSED */ 486 int 487 spec_fsync(v) 488 void *v; 489 { 490 struct vop_fsync_args /* { 491 struct vnode *a_vp; 492 struct ucred *a_cred; 493 int a_flags; 494 off_t offlo; 495 off_t offhi; 496 struct proc *a_p; 497 } */ *ap = v; 498 struct vnode *vp = ap->a_vp; 499 500 if (vp->v_type == VBLK) 501 vflushbuf(vp, (ap->a_flags & FSYNC_WAIT) != 0); 502 return (0); 503 } 504 505 /* 506 * Just call the device strategy routine 507 */ 508 int 509 spec_strategy(v) 510 void *v; 511 { 512 struct vop_strategy_args /* { 513 struct buf *a_bp; 514 } */ *ap = v; 515 struct buf *bp; 516 517 bp = ap->a_bp; 518 if (!(bp->b_flags & B_READ) && 519 (LIST_FIRST(&bp->b_dep)) != NULL && bioops.io_start) 520 (*bioops.io_start)(bp); 521 (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 522 return (0); 523 } 524 525 int 526 spec_inactive(v) 527 void *v; 528 { 529 struct vop_inactive_args /* { 530 struct vnode *a_vp; 531 struct proc *a_p; 532 } */ *ap = v; 533 534 VOP_UNLOCK(ap->a_vp, 0); 535 return (0); 536 } 537 538 /* 539 * This is a noop, simply returning what one has been given. 540 */ 541 int 542 spec_bmap(v) 543 void *v; 544 { 545 struct vop_bmap_args /* { 546 struct vnode *a_vp; 547 daddr_t a_bn; 548 struct vnode **a_vpp; 549 daddr_t *a_bnp; 550 int *a_runp; 551 } */ *ap = v; 552 553 if (ap->a_vpp != NULL) 554 *ap->a_vpp = ap->a_vp; 555 if (ap->a_bnp != NULL) 556 *ap->a_bnp = ap->a_bn; 557 if (ap->a_runp != NULL) 558 *ap->a_runp = (MAXBSIZE >> DEV_BSHIFT) - 1; 559 return (0); 560 } 561 562 /* 563 * Device close routine 564 */ 565 /* ARGSUSED */ 566 int 567 spec_close(v) 568 void *v; 569 { 570 struct vop_close_args /* { 571 struct vnode *a_vp; 572 int a_fflag; 573 struct ucred *a_cred; 574 struct proc *a_p; 575 } */ *ap = v; 576 struct vnode *vp = ap->a_vp; 577 dev_t dev = vp->v_rdev; 578 int (*devclose) __P((dev_t, int, int, struct proc *)); 579 int mode, error, count, flags, flags1; 580 581 count = vcount(vp); 582 simple_lock(&vp->v_interlock); 583 flags = vp->v_flag; 584 simple_unlock(&vp->v_interlock); 585 586 switch (vp->v_type) { 587 588 case VCHR: 589 /* 590 * Hack: a tty device that is a controlling terminal 591 * has a reference from the session structure. 592 * We cannot easily tell that a character device is 593 * a controlling terminal, unless it is the closing 594 * process' controlling terminal. In that case, 595 * if the reference count is 2 (this last descriptor 596 * plus the session), release the reference from the session. 597 */ 598 if (count == 2 && ap->a_p && 599 vp == ap->a_p->p_session->s_ttyvp) { 600 vrele(vp); 601 count--; 602 ap->a_p->p_session->s_ttyvp = NULL; 603 } 604 /* 605 * If the vnode is locked, then we are in the midst 606 * of forcably closing the device, otherwise we only 607 * close on last reference. 608 */ 609 if (count > 1 && (flags & VXLOCK) == 0) 610 return (0); 611 devclose = cdevsw[major(dev)].d_close; 612 mode = S_IFCHR; 613 break; 614 615 case VBLK: 616 /* 617 * On last close of a block device (that isn't mounted) 618 * we must invalidate any in core blocks, so that 619 * we can, for instance, change floppy disks. 620 */ 621 error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0); 622 if (error) 623 return (error); 624 /* 625 * We do not want to really close the device if it 626 * is still in use unless we are trying to close it 627 * forcibly. Since every use (buffer, vnode, swap, cmap) 628 * holds a reference to the vnode, and because we mark 629 * any other vnodes that alias this device, when the 630 * sum of the reference counts on all the aliased 631 * vnodes descends to one, we are on last close. 632 */ 633 if (count > 1 && (flags & VXLOCK) == 0) 634 return (0); 635 devclose = bdevsw[major(dev)].d_close; 636 mode = S_IFBLK; 637 break; 638 639 default: 640 panic("spec_close: not special"); 641 } 642 643 flags1 = ap->a_fflag; 644 645 /* 646 * if VXLOCK is set, then we're going away soon, so make this 647 * non-blocking. Also ensures that we won't wedge in vn_lock below. 648 */ 649 if (flags & VXLOCK) 650 flags1 |= FNONBLOCK; 651 652 /* 653 * If we're able to block, release the vnode lock & reaquire. We 654 * might end up sleaping for someone else who wants our queues. They 655 * won't get them if we hold the vnode locked. Also, if VXLOCK is set, 656 * don't release the lock as we won't be able to regain it. 657 */ 658 if (!(flags1 & FNONBLOCK)) 659 VOP_UNLOCK(vp, 0); 660 661 error = (*devclose)(dev, flags1, mode, ap->a_p); 662 663 if (!(flags1 & FNONBLOCK)) 664 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 665 666 return (error); 667 } 668 669 /* 670 * Print out the contents of a special device vnode. 671 */ 672 int 673 spec_print(v) 674 void *v; 675 { 676 struct vop_print_args /* { 677 struct vnode *a_vp; 678 } */ *ap = v; 679 680 printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 681 minor(ap->a_vp->v_rdev)); 682 return 0; 683 } 684 685 /* 686 * Return POSIX pathconf information applicable to special devices. 687 */ 688 int 689 spec_pathconf(v) 690 void *v; 691 { 692 struct vop_pathconf_args /* { 693 struct vnode *a_vp; 694 int a_name; 695 register_t *a_retval; 696 } */ *ap = v; 697 698 switch (ap->a_name) { 699 case _PC_LINK_MAX: 700 *ap->a_retval = LINK_MAX; 701 return (0); 702 case _PC_MAX_CANON: 703 *ap->a_retval = MAX_CANON; 704 return (0); 705 case _PC_MAX_INPUT: 706 *ap->a_retval = MAX_INPUT; 707 return (0); 708 case _PC_PIPE_BUF: 709 *ap->a_retval = PIPE_BUF; 710 return (0); 711 case _PC_CHOWN_RESTRICTED: 712 *ap->a_retval = 1; 713 return (0); 714 case _PC_VDISABLE: 715 *ap->a_retval = _POSIX_VDISABLE; 716 return (0); 717 case _PC_SYNC_IO: 718 *ap->a_retval = 1; 719 return (0); 720 default: 721 return (EINVAL); 722 } 723 /* NOTREACHED */ 724 } 725 726 /* 727 * Advisory record locking support. 728 */ 729 int 730 spec_advlock(v) 731 void *v; 732 { 733 struct vop_advlock_args /* { 734 struct vnode *a_vp; 735 caddr_t a_id; 736 int a_op; 737 struct flock *a_fl; 738 int a_flags; 739 } */ *ap = v; 740 struct vnode *vp = ap->a_vp; 741 742 return lf_advlock(ap, &vp->v_speclockf, (off_t)0); 743 } 744