1 /* $NetBSD: spec_vnops.c,v 1.59 2001/09/23 04:39:25 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; 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 if ((majordev = major(vp->v_rdev)) < nblkdev && 295 (ioctl = bdevsw[majordev].d_ioctl) != NULL && 296 (*ioctl)(vp->v_rdev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0) { 297 if (dpart.part->p_fstype == FS_BSDFFS && 298 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 299 bsize = dpart.part->p_frag * 300 dpart.part->p_fsize; 301 } 302 bscale = bsize >> DEV_BSHIFT; 303 do { 304 bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1); 305 on = uio->uio_offset % bsize; 306 n = min((unsigned)(bsize - on), uio->uio_resid); 307 error = bread(vp, bn, bsize, NOCRED, &bp); 308 n = min(n, bsize - bp->b_resid); 309 if (error) { 310 brelse(bp); 311 return (error); 312 } 313 error = uiomove((char *)bp->b_data + on, n, uio); 314 brelse(bp); 315 } while (error == 0 && uio->uio_resid > 0 && n != 0); 316 return (error); 317 318 default: 319 panic("spec_read type"); 320 } 321 /* NOTREACHED */ 322 } 323 324 /* 325 * Vnode op for write 326 */ 327 /* ARGSUSED */ 328 int 329 spec_write(v) 330 void *v; 331 { 332 struct vop_write_args /* { 333 struct vnode *a_vp; 334 struct uio *a_uio; 335 int a_ioflag; 336 struct ucred *a_cred; 337 } */ *ap = v; 338 struct vnode *vp = ap->a_vp; 339 struct uio *uio = ap->a_uio; 340 struct proc *p = uio->uio_procp; 341 struct buf *bp; 342 daddr_t bn; 343 int bsize, bscale; 344 struct partinfo dpart; 345 int n, on, majordev; 346 int (*ioctl) __P((dev_t, u_long, caddr_t, int, struct proc *)); 347 int error = 0; 348 349 #ifdef DIAGNOSTIC 350 if (uio->uio_rw != UIO_WRITE) 351 panic("spec_write mode"); 352 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 353 panic("spec_write proc"); 354 #endif 355 356 switch (vp->v_type) { 357 358 case VCHR: 359 VOP_UNLOCK(vp, 0); 360 error = (*cdevsw[major(vp->v_rdev)].d_write) 361 (vp->v_rdev, uio, ap->a_ioflag); 362 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 363 return (error); 364 365 case VBLK: 366 if (uio->uio_resid == 0) 367 return (0); 368 if (uio->uio_offset < 0) 369 return (EINVAL); 370 bsize = BLKDEV_IOSIZE; 371 if ((majordev = major(vp->v_rdev)) < nblkdev && 372 (ioctl = bdevsw[majordev].d_ioctl) != NULL && 373 (*ioctl)(vp->v_rdev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0) { 374 if (dpart.part->p_fstype == FS_BSDFFS && 375 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 376 bsize = dpart.part->p_frag * 377 dpart.part->p_fsize; 378 } 379 bscale = bsize >> DEV_BSHIFT; 380 do { 381 bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1); 382 on = uio->uio_offset % bsize; 383 n = min((unsigned)(bsize - on), uio->uio_resid); 384 if (n == bsize) 385 bp = getblk(vp, bn, bsize, 0, 0); 386 else 387 error = bread(vp, bn, bsize, NOCRED, &bp); 388 if (error) { 389 brelse(bp); 390 return (error); 391 } 392 n = min(n, bsize - bp->b_resid); 393 error = uiomove((char *)bp->b_data + on, n, uio); 394 if (error) 395 brelse(bp); 396 else { 397 if (n + on == bsize) 398 bawrite(bp); 399 else 400 bdwrite(bp); 401 if (bp->b_flags & B_ERROR) 402 error = bp->b_error; 403 } 404 } while (error == 0 && uio->uio_resid > 0 && n != 0); 405 return (error); 406 407 default: 408 panic("spec_write type"); 409 } 410 /* NOTREACHED */ 411 } 412 413 /* 414 * Device ioctl operation. 415 */ 416 /* ARGSUSED */ 417 int 418 spec_ioctl(v) 419 void *v; 420 { 421 struct vop_ioctl_args /* { 422 struct vnode *a_vp; 423 u_long a_command; 424 caddr_t a_data; 425 int a_fflag; 426 struct ucred *a_cred; 427 struct proc *a_p; 428 } */ *ap = v; 429 dev_t dev = ap->a_vp->v_rdev; 430 int maj = major(dev); 431 432 switch (ap->a_vp->v_type) { 433 434 case VCHR: 435 return ((*cdevsw[maj].d_ioctl)(dev, ap->a_command, ap->a_data, 436 ap->a_fflag, ap->a_p)); 437 438 case VBLK: 439 if (ap->a_command == 0 && (long)ap->a_data == B_TAPE) { 440 if (bdevsw[maj].d_type == D_TAPE) 441 return (0); 442 else 443 return (1); 444 } 445 return ((*bdevsw[maj].d_ioctl)(dev, ap->a_command, ap->a_data, 446 ap->a_fflag, ap->a_p)); 447 448 default: 449 panic("spec_ioctl"); 450 /* NOTREACHED */ 451 } 452 } 453 454 /* ARGSUSED */ 455 int 456 spec_poll(v) 457 void *v; 458 { 459 struct vop_poll_args /* { 460 struct vnode *a_vp; 461 int a_events; 462 struct proc *a_p; 463 } */ *ap = v; 464 dev_t dev; 465 466 switch (ap->a_vp->v_type) { 467 468 case VCHR: 469 dev = ap->a_vp->v_rdev; 470 return (*cdevsw[major(dev)].d_poll)(dev, ap->a_events, ap->a_p); 471 472 default: 473 return (genfs_poll(v)); 474 } 475 } 476 /* 477 * Synch buffers associated with a block device 478 */ 479 /* ARGSUSED */ 480 int 481 spec_fsync(v) 482 void *v; 483 { 484 struct vop_fsync_args /* { 485 struct vnode *a_vp; 486 struct ucred *a_cred; 487 int a_flags; 488 off_t offlo; 489 off_t offhi; 490 struct proc *a_p; 491 } */ *ap = v; 492 struct vnode *vp = ap->a_vp; 493 494 if (vp->v_type == VBLK) 495 vflushbuf(vp, (ap->a_flags & FSYNC_WAIT) != 0); 496 return (0); 497 } 498 499 /* 500 * Just call the device strategy routine 501 */ 502 int 503 spec_strategy(v) 504 void *v; 505 { 506 struct vop_strategy_args /* { 507 struct buf *a_bp; 508 } */ *ap = v; 509 struct buf *bp; 510 511 bp = ap->a_bp; 512 if (!(bp->b_flags & B_READ) && 513 (LIST_FIRST(&bp->b_dep)) != NULL && bioops.io_start) 514 (*bioops.io_start)(bp); 515 (*bdevsw[major(bp->b_dev)].d_strategy)(bp); 516 return (0); 517 } 518 519 int 520 spec_inactive(v) 521 void *v; 522 { 523 struct vop_inactive_args /* { 524 struct vnode *a_vp; 525 struct proc *a_p; 526 } */ *ap = v; 527 528 VOP_UNLOCK(ap->a_vp, 0); 529 return (0); 530 } 531 532 /* 533 * This is a noop, simply returning what one has been given. 534 */ 535 int 536 spec_bmap(v) 537 void *v; 538 { 539 struct vop_bmap_args /* { 540 struct vnode *a_vp; 541 daddr_t a_bn; 542 struct vnode **a_vpp; 543 daddr_t *a_bnp; 544 int *a_runp; 545 } */ *ap = v; 546 547 if (ap->a_vpp != NULL) 548 *ap->a_vpp = ap->a_vp; 549 if (ap->a_bnp != NULL) 550 *ap->a_bnp = ap->a_bn; 551 if (ap->a_runp != NULL) 552 *ap->a_runp = (MAXBSIZE >> DEV_BSHIFT) - 1; 553 return (0); 554 } 555 556 /* 557 * Device close routine 558 */ 559 /* ARGSUSED */ 560 int 561 spec_close(v) 562 void *v; 563 { 564 struct vop_close_args /* { 565 struct vnode *a_vp; 566 int a_fflag; 567 struct ucred *a_cred; 568 struct proc *a_p; 569 } */ *ap = v; 570 struct vnode *vp = ap->a_vp; 571 dev_t dev = vp->v_rdev; 572 int (*devclose) __P((dev_t, int, int, struct proc *)); 573 int mode, error, count, flags, flags1; 574 575 count = vcount(vp); 576 simple_lock(&vp->v_interlock); 577 flags = vp->v_flag; 578 simple_unlock(&vp->v_interlock); 579 580 switch (vp->v_type) { 581 582 case VCHR: 583 /* 584 * Hack: a tty device that is a controlling terminal 585 * has a reference from the session structure. 586 * We cannot easily tell that a character device is 587 * a controlling terminal, unless it is the closing 588 * process' controlling terminal. In that case, 589 * if the reference count is 2 (this last descriptor 590 * plus the session), release the reference from the session. 591 */ 592 if (count == 2 && ap->a_p && 593 vp == ap->a_p->p_session->s_ttyvp) { 594 vrele(vp); 595 count--; 596 ap->a_p->p_session->s_ttyvp = NULL; 597 } 598 /* 599 * If the vnode is locked, then we are in the midst 600 * of forcably closing the device, otherwise we only 601 * close on last reference. 602 */ 603 if (count > 1 && (flags & VXLOCK) == 0) 604 return (0); 605 devclose = cdevsw[major(dev)].d_close; 606 mode = S_IFCHR; 607 break; 608 609 case VBLK: 610 /* 611 * On last close of a block device (that isn't mounted) 612 * we must invalidate any in core blocks, so that 613 * we can, for instance, change floppy disks. 614 */ 615 error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0); 616 if (error) 617 return (error); 618 /* 619 * We do not want to really close the device if it 620 * is still in use unless we are trying to close it 621 * forcibly. Since every use (buffer, vnode, swap, cmap) 622 * holds a reference to the vnode, and because we mark 623 * any other vnodes that alias this device, when the 624 * sum of the reference counts on all the aliased 625 * vnodes descends to one, we are on last close. 626 */ 627 if (count > 1 && (flags & VXLOCK) == 0) 628 return (0); 629 devclose = bdevsw[major(dev)].d_close; 630 mode = S_IFBLK; 631 break; 632 633 default: 634 panic("spec_close: not special"); 635 } 636 637 flags1 = ap->a_fflag; 638 639 /* 640 * if VXLOCK is set, then we're going away soon, so make this 641 * non-blocking. Also ensures that we won't wedge in vn_lock below. 642 */ 643 if (flags & VXLOCK) 644 flags1 |= FNONBLOCK; 645 646 /* 647 * If we're able to block, release the vnode lock & reaquire. We 648 * might end up sleaping for someone else who wants our queues. They 649 * won't get them if we hold the vnode locked. Also, if VXLOCK is set, 650 * don't release the lock as we won't be able to regain it. 651 */ 652 if (!(flags1 & FNONBLOCK)) 653 VOP_UNLOCK(vp, 0); 654 655 error = (*devclose)(dev, flags1, mode, ap->a_p); 656 657 if (!(flags1 & FNONBLOCK)) 658 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 659 660 return (error); 661 } 662 663 /* 664 * Print out the contents of a special device vnode. 665 */ 666 int 667 spec_print(v) 668 void *v; 669 { 670 struct vop_print_args /* { 671 struct vnode *a_vp; 672 } */ *ap = v; 673 674 printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 675 minor(ap->a_vp->v_rdev)); 676 return 0; 677 } 678 679 /* 680 * Return POSIX pathconf information applicable to special devices. 681 */ 682 int 683 spec_pathconf(v) 684 void *v; 685 { 686 struct vop_pathconf_args /* { 687 struct vnode *a_vp; 688 int a_name; 689 register_t *a_retval; 690 } */ *ap = v; 691 692 switch (ap->a_name) { 693 case _PC_LINK_MAX: 694 *ap->a_retval = LINK_MAX; 695 return (0); 696 case _PC_MAX_CANON: 697 *ap->a_retval = MAX_CANON; 698 return (0); 699 case _PC_MAX_INPUT: 700 *ap->a_retval = MAX_INPUT; 701 return (0); 702 case _PC_PIPE_BUF: 703 *ap->a_retval = PIPE_BUF; 704 return (0); 705 case _PC_CHOWN_RESTRICTED: 706 *ap->a_retval = 1; 707 return (0); 708 case _PC_VDISABLE: 709 *ap->a_retval = _POSIX_VDISABLE; 710 return (0); 711 case _PC_SYNC_IO: 712 *ap->a_retval = 1; 713 return (0); 714 default: 715 return (EINVAL); 716 } 717 /* NOTREACHED */ 718 } 719 720 /* 721 * Advisory record locking support. 722 */ 723 int 724 spec_advlock(v) 725 void *v; 726 { 727 struct vop_advlock_args /* { 728 struct vnode *a_vp; 729 caddr_t a_id; 730 int a_op; 731 struct flock *a_fl; 732 int a_flags; 733 } */ *ap = v; 734 struct vnode *vp = ap->a_vp; 735 736 return lf_advlock(ap, &vp->v_speclockf, (off_t)0); 737 } 738