1 /* $NetBSD: spec_vnops.c,v 1.110 2007/12/02 13:56:18 hannken 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)spec_vnops.c 8.15 (Berkeley) 7/14/95 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.110 2007/12/02 13:56:18 hannken Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/proc.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/conf.h> 42 #include <sys/buf.h> 43 #include <sys/mount.h> 44 #include <sys/namei.h> 45 #include <sys/vnode.h> 46 #include <sys/stat.h> 47 #include <sys/errno.h> 48 #include <sys/ioctl.h> 49 #include <sys/poll.h> 50 #include <sys/file.h> 51 #include <sys/disklabel.h> 52 #include <sys/lockf.h> 53 #include <sys/tty.h> 54 #include <sys/kauth.h> 55 #include <sys/fstrans.h> 56 57 #include <miscfs/genfs/genfs.h> 58 #include <miscfs/specfs/specdev.h> 59 60 /* symbolic sleep message strings for devices */ 61 const char devopn[] = "devopn"; 62 const char devio[] = "devio"; 63 const char devwait[] = "devwait"; 64 const char devin[] = "devin"; 65 const char devout[] = "devout"; 66 const char devioc[] = "devioc"; 67 const char devcls[] = "devcls"; 68 69 struct vnode *speclisth[SPECHSZ]; 70 71 /* 72 * This vnode operations vector is used for two things only: 73 * - special device nodes created from whole cloth by the kernel. 74 * - as a temporary vnodeops replacement for vnodes which were found to 75 * be aliased by callers of checkalias(). 76 * For the ops vector for vnodes built from special devices found in a 77 * filesystem, see (e.g) ffs_specop_entries[] in ffs_vnops.c or the 78 * equivalent for other filesystems. 79 */ 80 81 int (**spec_vnodeop_p)(void *); 82 const struct vnodeopv_entry_desc spec_vnodeop_entries[] = { 83 { &vop_default_desc, vn_default_error }, 84 { &vop_lookup_desc, spec_lookup }, /* lookup */ 85 { &vop_create_desc, spec_create }, /* create */ 86 { &vop_mknod_desc, spec_mknod }, /* mknod */ 87 { &vop_open_desc, spec_open }, /* open */ 88 { &vop_close_desc, spec_close }, /* close */ 89 { &vop_access_desc, spec_access }, /* access */ 90 { &vop_getattr_desc, spec_getattr }, /* getattr */ 91 { &vop_setattr_desc, spec_setattr }, /* setattr */ 92 { &vop_read_desc, spec_read }, /* read */ 93 { &vop_write_desc, spec_write }, /* write */ 94 { &vop_lease_desc, spec_lease_check }, /* lease */ 95 { &vop_fcntl_desc, spec_fcntl }, /* fcntl */ 96 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 97 { &vop_poll_desc, spec_poll }, /* poll */ 98 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 99 { &vop_revoke_desc, spec_revoke }, /* revoke */ 100 { &vop_mmap_desc, spec_mmap }, /* mmap */ 101 { &vop_fsync_desc, spec_fsync }, /* fsync */ 102 { &vop_seek_desc, spec_seek }, /* seek */ 103 { &vop_remove_desc, spec_remove }, /* remove */ 104 { &vop_link_desc, spec_link }, /* link */ 105 { &vop_rename_desc, spec_rename }, /* rename */ 106 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 107 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 108 { &vop_symlink_desc, spec_symlink }, /* symlink */ 109 { &vop_readdir_desc, spec_readdir }, /* readdir */ 110 { &vop_readlink_desc, spec_readlink }, /* readlink */ 111 { &vop_abortop_desc, spec_abortop }, /* abortop */ 112 { &vop_inactive_desc, spec_inactive }, /* inactive */ 113 { &vop_reclaim_desc, spec_reclaim }, /* reclaim */ 114 { &vop_lock_desc, spec_lock }, /* lock */ 115 { &vop_unlock_desc, spec_unlock }, /* unlock */ 116 { &vop_bmap_desc, spec_bmap }, /* bmap */ 117 { &vop_strategy_desc, spec_strategy }, /* strategy */ 118 { &vop_print_desc, spec_print }, /* print */ 119 { &vop_islocked_desc, spec_islocked }, /* islocked */ 120 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 121 { &vop_advlock_desc, spec_advlock }, /* advlock */ 122 { &vop_bwrite_desc, spec_bwrite }, /* bwrite */ 123 { &vop_getpages_desc, spec_getpages }, /* getpages */ 124 { &vop_putpages_desc, spec_putpages }, /* putpages */ 125 { NULL, NULL } 126 }; 127 const struct vnodeopv_desc spec_vnodeop_opv_desc = 128 { &spec_vnodeop_p, spec_vnodeop_entries }; 129 130 /* 131 * Trivial lookup routine that always fails. 132 */ 133 int 134 spec_lookup(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 * Returns true if dev is /dev/mem or /dev/kmem. 148 */ 149 int 150 iskmemdev(dev_t dev) 151 { 152 /* mem_no is emitted by config(8) to generated devsw.c */ 153 extern const int mem_no; 154 155 /* minor 14 is /dev/io on i386 with COMPAT_10 */ 156 return (major(dev) == mem_no && (minor(dev) < 2 || minor(dev) == 14)); 157 } 158 159 /* 160 * Open a special file. 161 */ 162 /* ARGSUSED */ 163 int 164 spec_open(void *v) 165 { 166 struct vop_open_args /* { 167 struct vnode *a_vp; 168 int a_mode; 169 kauth_cred_t a_cred; 170 } */ *ap = v; 171 struct lwp *l = curlwp; 172 struct vnode *vp = ap->a_vp; 173 dev_t dev = (dev_t)vp->v_rdev; 174 int error; 175 struct partinfo pi; 176 enum kauth_device_req req; 177 178 /* 179 * Don't allow open if fs is mounted -nodev. 180 */ 181 if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) 182 return (ENXIO); 183 184 #define M2K(m) (((m) & FREAD) && ((m) & FWRITE) ? \ 185 KAUTH_REQ_DEVICE_RAWIO_SPEC_RW : \ 186 (m) & FWRITE ? KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE : \ 187 KAUTH_REQ_DEVICE_RAWIO_SPEC_READ) 188 189 switch (vp->v_type) { 190 191 case VCHR: 192 req = M2K(ap->a_mode); 193 error = kauth_authorize_device_spec(ap->a_cred, req, vp); 194 if (error) 195 return (error); 196 197 if (cdev_type(dev) == D_TTY) 198 vp->v_vflag |= VV_ISTTY; 199 VOP_UNLOCK(vp, 0); 200 error = cdev_open(dev, ap->a_mode, S_IFCHR, l); 201 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 202 if (cdev_type(dev) != D_DISK) 203 return error; 204 break; 205 206 case VBLK: 207 req = M2K(ap->a_mode); 208 error = kauth_authorize_device_spec(ap->a_cred, req, vp); 209 if (error) 210 return (error); 211 error = bdev_open(dev, ap->a_mode, S_IFBLK, l); 212 break; 213 214 case VNON: 215 case VLNK: 216 case VDIR: 217 case VREG: 218 case VBAD: 219 case VFIFO: 220 case VSOCK: 221 default: 222 return 0; 223 } 224 225 #undef M2K 226 227 if (error) 228 return error; 229 if (vp->v_type == VCHR) 230 error = cdev_ioctl(vp->v_rdev, DIOCGPART, &pi, FREAD, curlwp); 231 else 232 error = bdev_ioctl(vp->v_rdev, DIOCGPART, &pi, FREAD, curlwp); 233 if (error == 0) 234 uvm_vnp_setsize(vp, 235 (voff_t)pi.disklab->d_secsize * pi.part->p_size); 236 return 0; 237 } 238 239 /* 240 * Vnode op for read 241 */ 242 /* ARGSUSED */ 243 int 244 spec_read(void *v) 245 { 246 struct vop_read_args /* { 247 struct vnode *a_vp; 248 struct uio *a_uio; 249 int a_ioflag; 250 kauth_cred_t a_cred; 251 } */ *ap = v; 252 struct vnode *vp = ap->a_vp; 253 struct uio *uio = ap->a_uio; 254 struct lwp *l = curlwp; 255 struct buf *bp; 256 daddr_t bn; 257 int bsize, bscale; 258 struct partinfo dpart; 259 int n, on; 260 int error = 0; 261 262 #ifdef DIAGNOSTIC 263 if (uio->uio_rw != UIO_READ) 264 panic("spec_read mode"); 265 if (&uio->uio_vmspace->vm_map != kernel_map && 266 uio->uio_vmspace != curproc->p_vmspace) 267 panic("spec_read proc"); 268 #endif 269 if (uio->uio_resid == 0) 270 return (0); 271 272 switch (vp->v_type) { 273 274 case VCHR: 275 VOP_UNLOCK(vp, 0); 276 error = cdev_read(vp->v_rdev, uio, ap->a_ioflag); 277 vn_lock(vp, LK_SHARED | LK_RETRY); 278 return (error); 279 280 case VBLK: 281 if (uio->uio_offset < 0) 282 return (EINVAL); 283 bsize = BLKDEV_IOSIZE; 284 if (bdev_ioctl(vp->v_rdev, DIOCGPART, &dpart, FREAD, l) == 0) { 285 if (dpart.part->p_fstype == FS_BSDFFS && 286 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 287 bsize = dpart.part->p_frag * 288 dpart.part->p_fsize; 289 } 290 bscale = bsize >> DEV_BSHIFT; 291 do { 292 bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1); 293 on = uio->uio_offset % bsize; 294 n = min((unsigned)(bsize - on), uio->uio_resid); 295 error = bread(vp, bn, bsize, NOCRED, &bp); 296 n = min(n, bsize - bp->b_resid); 297 if (error) { 298 brelse(bp, 0); 299 return (error); 300 } 301 error = uiomove((char *)bp->b_data + on, n, uio); 302 brelse(bp, 0); 303 } while (error == 0 && uio->uio_resid > 0 && n != 0); 304 return (error); 305 306 default: 307 panic("spec_read type"); 308 } 309 /* NOTREACHED */ 310 } 311 312 /* 313 * Vnode op for write 314 */ 315 /* ARGSUSED */ 316 int 317 spec_write(void *v) 318 { 319 struct vop_write_args /* { 320 struct vnode *a_vp; 321 struct uio *a_uio; 322 int a_ioflag; 323 kauth_cred_t a_cred; 324 } */ *ap = v; 325 struct vnode *vp = ap->a_vp; 326 struct uio *uio = ap->a_uio; 327 struct lwp *l = curlwp; 328 struct buf *bp; 329 daddr_t bn; 330 int bsize, bscale; 331 struct partinfo dpart; 332 int n, on; 333 int error = 0; 334 335 #ifdef DIAGNOSTIC 336 if (uio->uio_rw != UIO_WRITE) 337 panic("spec_write mode"); 338 if (&uio->uio_vmspace->vm_map != kernel_map && 339 uio->uio_vmspace != curproc->p_vmspace) 340 panic("spec_write proc"); 341 #endif 342 343 switch (vp->v_type) { 344 345 case VCHR: 346 VOP_UNLOCK(vp, 0); 347 error = cdev_write(vp->v_rdev, uio, ap->a_ioflag); 348 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 349 return (error); 350 351 case VBLK: 352 if (uio->uio_resid == 0) 353 return (0); 354 if (uio->uio_offset < 0) 355 return (EINVAL); 356 bsize = BLKDEV_IOSIZE; 357 if (bdev_ioctl(vp->v_rdev, DIOCGPART, &dpart, FREAD, l) == 0) { 358 if (dpart.part->p_fstype == FS_BSDFFS && 359 dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) 360 bsize = dpart.part->p_frag * 361 dpart.part->p_fsize; 362 } 363 bscale = bsize >> DEV_BSHIFT; 364 do { 365 bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1); 366 on = uio->uio_offset % bsize; 367 n = min((unsigned)(bsize - on), uio->uio_resid); 368 if (n == bsize) 369 bp = getblk(vp, bn, bsize, 0, 0); 370 else 371 error = bread(vp, bn, bsize, NOCRED, &bp); 372 if (error) { 373 brelse(bp, 0); 374 return (error); 375 } 376 n = min(n, bsize - bp->b_resid); 377 error = uiomove((char *)bp->b_data + on, n, uio); 378 if (error) 379 brelse(bp, 0); 380 else { 381 if (n + on == bsize) 382 bawrite(bp); 383 else 384 bdwrite(bp); 385 error = bp->b_error; 386 } 387 } while (error == 0 && uio->uio_resid > 0 && n != 0); 388 return (error); 389 390 default: 391 panic("spec_write type"); 392 } 393 /* NOTREACHED */ 394 } 395 396 /* 397 * Device ioctl operation. 398 */ 399 /* ARGSUSED */ 400 int 401 spec_ioctl(void *v) 402 { 403 struct vop_ioctl_args /* { 404 struct vnode *a_vp; 405 u_long a_command; 406 void *a_data; 407 int a_fflag; 408 kauth_cred_t a_cred; 409 } */ *ap = v; 410 struct vnode *vp; 411 dev_t dev; 412 413 /* 414 * Extract all the info we need from the vnode, taking care to 415 * avoid a race with VOP_REVOKE(). 416 */ 417 418 vp = ap->a_vp; 419 dev = NODEV; 420 simple_lock(&vp->v_interlock); 421 if ((vp->v_iflag & VI_XLOCK) == 0 && vp->v_specinfo) { 422 dev = vp->v_rdev; 423 } 424 simple_unlock(&vp->v_interlock); 425 if (dev == NODEV) { 426 return ENXIO; 427 } 428 429 switch (vp->v_type) { 430 431 case VCHR: 432 return cdev_ioctl(dev, ap->a_command, ap->a_data, 433 ap->a_fflag, curlwp); 434 435 case VBLK: 436 return bdev_ioctl(dev, ap->a_command, ap->a_data, 437 ap->a_fflag, curlwp); 438 439 default: 440 panic("spec_ioctl"); 441 /* NOTREACHED */ 442 } 443 } 444 445 /* ARGSUSED */ 446 int 447 spec_poll(void *v) 448 { 449 struct vop_poll_args /* { 450 struct vnode *a_vp; 451 int a_events; 452 } */ *ap = v; 453 struct vnode *vp; 454 dev_t dev; 455 456 /* 457 * Extract all the info we need from the vnode, taking care to 458 * avoid a race with VOP_REVOKE(). 459 */ 460 461 vp = ap->a_vp; 462 dev = NODEV; 463 simple_lock(&vp->v_interlock); 464 if ((vp->v_iflag & VI_XLOCK) == 0 && vp->v_specinfo) { 465 dev = vp->v_rdev; 466 } 467 simple_unlock(&vp->v_interlock); 468 if (dev == NODEV) { 469 return POLLERR; 470 } 471 472 switch (vp->v_type) { 473 474 case VCHR: 475 return cdev_poll(dev, ap->a_events, curlwp); 476 477 default: 478 return (genfs_poll(v)); 479 } 480 } 481 482 /* ARGSUSED */ 483 int 484 spec_kqfilter(void *v) 485 { 486 struct vop_kqfilter_args /* { 487 struct vnode *a_vp; 488 struct proc *a_kn; 489 } */ *ap = v; 490 dev_t dev; 491 492 switch (ap->a_vp->v_type) { 493 494 case VCHR: 495 dev = ap->a_vp->v_rdev; 496 return cdev_kqfilter(dev, ap->a_kn); 497 default: 498 /* 499 * Block devices don't support kqfilter, and refuse it 500 * for any other files (like those vflush()ed) too. 501 */ 502 return (EOPNOTSUPP); 503 } 504 } 505 506 /* 507 * Allow mapping of only D_DISK. This is called only for VBLK. 508 */ 509 int 510 spec_mmap(void *v) 511 { 512 struct vop_mmap_args /* { 513 struct vnode *a_vp; 514 vm_prot_t a_prot; 515 kauth_cred_t a_cred; 516 } */ *ap = v; 517 struct vnode *vp = ap->a_vp; 518 519 KASSERT(vp->v_type == VBLK); 520 if (bdev_type(vp->v_rdev) != D_DISK) 521 return EINVAL; 522 523 return 0; 524 } 525 526 /* 527 * Synch buffers associated with a block device 528 */ 529 /* ARGSUSED */ 530 int 531 spec_fsync(void *v) 532 { 533 struct vop_fsync_args /* { 534 struct vnode *a_vp; 535 kauth_cred_t a_cred; 536 int a_flags; 537 off_t offlo; 538 off_t offhi; 539 } */ *ap = v; 540 struct vnode *vp = ap->a_vp; 541 542 if (vp->v_type == VBLK) 543 vflushbuf(vp, (ap->a_flags & FSYNC_WAIT) != 0); 544 return (0); 545 } 546 547 /* 548 * Just call the device strategy routine 549 */ 550 int 551 spec_strategy(void *v) 552 { 553 struct vop_strategy_args /* { 554 struct vnode *a_vp; 555 struct buf *a_bp; 556 } */ *ap = v; 557 struct vnode *vp = ap->a_vp; 558 struct buf *bp = ap->a_bp; 559 int error; 560 561 error = 0; 562 bp->b_dev = vp->v_rdev; 563 if (!(bp->b_flags & B_READ) && 564 (LIST_FIRST(&bp->b_dep)) != NULL && bioopsp) 565 bioopsp->io_start(bp); 566 567 if (!(bp->b_flags & B_READ)) 568 error = fscow_run(bp, false); 569 570 if (error) { 571 bp->b_error = error; 572 biodone(bp); 573 return (error); 574 } 575 576 bdev_strategy(bp); 577 578 return (0); 579 } 580 581 int 582 spec_inactive(void *v) 583 { 584 struct vop_inactive_args /* { 585 struct vnode *a_vp; 586 struct proc *a_l; 587 } */ *ap = v; 588 589 VOP_UNLOCK(ap->a_vp, 0); 590 return (0); 591 } 592 593 /* 594 * This is a noop, simply returning what one has been given. 595 */ 596 int 597 spec_bmap(void *v) 598 { 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 = v; 606 607 if (ap->a_vpp != NULL) 608 *ap->a_vpp = ap->a_vp; 609 if (ap->a_bnp != NULL) 610 *ap->a_bnp = ap->a_bn; 611 if (ap->a_runp != NULL) 612 *ap->a_runp = (MAXBSIZE >> DEV_BSHIFT) - 1; 613 return (0); 614 } 615 616 /* 617 * Device close routine 618 */ 619 /* ARGSUSED */ 620 int 621 spec_close(void *v) 622 { 623 struct vop_close_args /* { 624 struct vnode *a_vp; 625 int a_fflag; 626 kauth_cred_t a_cred; 627 } */ *ap = v; 628 struct vnode *vp = ap->a_vp; 629 struct session *sess; 630 dev_t dev = vp->v_rdev; 631 int mode, error, count, flags, flags1; 632 633 count = vcount(vp); 634 flags = vp->v_iflag; 635 636 switch (vp->v_type) { 637 638 case VCHR: 639 /* 640 * Hack: a tty device that is a controlling terminal 641 * has a reference from the session structure. 642 * We cannot easily tell that a character device is 643 * a controlling terminal, unless it is the closing 644 * process' controlling terminal. In that case, 645 * if the reference count is 2 (this last descriptor 646 * plus the session), release the reference from the session. 647 * Also remove the link from the tty back to the session 648 * and pgrp - due to the way consoles are handled we cannot 649 * guarantee that the vrele() will do the final close on the 650 * actual tty device. 651 */ 652 mutex_enter(&proclist_lock); 653 if (count == 2 && 654 vp == (sess = curlwp->l_proc->p_session)->s_ttyvp) { 655 sess->s_ttyvp = NULL; 656 if (sess->s_ttyp->t_session != NULL) { 657 sess->s_ttyp->t_pgrp = NULL; 658 sess->s_ttyp->t_session = NULL; 659 mutex_exit(&proclist_lock); 660 SESSRELE(sess); 661 } else { 662 if (sess->s_ttyp->t_pgrp != NULL) 663 panic("spec_close: spurious pgrp ref"); 664 mutex_exit(&proclist_lock); 665 } 666 vrele(vp); 667 count--; 668 } else 669 mutex_exit(&proclist_lock); 670 671 /* 672 * If the vnode is locked, then we are in the midst 673 * of forcably closing the device, otherwise we only 674 * close on last reference. 675 */ 676 if (count > 1 && (flags & VI_XLOCK) == 0) 677 return (0); 678 mode = S_IFCHR; 679 break; 680 681 case VBLK: 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 */ 687 error = vinvalbuf(vp, V_SAVE, ap->a_cred, curlwp, 0, 0); 688 if (error) 689 return (error); 690 /* 691 * We do not want to really close the device if it 692 * is still in use unless we are trying to close it 693 * forcibly. Since every use (buffer, vnode, swap, cmap) 694 * holds a reference to the vnode, and because we mark 695 * any other vnodes that alias this device, when the 696 * sum of the reference counts on all the aliased 697 * vnodes descends to one, we are on last close. 698 */ 699 if (count > 1 && (flags & VI_XLOCK) == 0) 700 return (0); 701 mode = S_IFBLK; 702 break; 703 704 default: 705 panic("spec_close: not special"); 706 } 707 708 flags1 = ap->a_fflag; 709 710 /* 711 * if VI_XLOCK is set, then we're going away soon, so make this 712 * non-blocking. Also ensures that we won't wedge in vn_lock below. 713 */ 714 if (flags & VI_XLOCK) 715 flags1 |= FNONBLOCK; 716 717 /* 718 * If we're able to block, release the vnode lock & reacquire. We 719 * might end up sleeping for someone else who wants our queues. They 720 * won't get them if we hold the vnode locked. Also, if VI_XLOCK is 721 * set, don't release the lock as we won't be able to regain it. 722 */ 723 if (!(flags1 & FNONBLOCK)) 724 VOP_UNLOCK(vp, 0); 725 726 if (vp->v_type == VBLK) 727 error = bdev_close(dev, flags1, mode, curlwp); 728 else 729 error = cdev_close(dev, flags1, mode, curlwp); 730 731 if (!(flags1 & FNONBLOCK)) 732 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 733 734 return (error); 735 } 736 737 /* 738 * Print out the contents of a special device vnode. 739 */ 740 int 741 spec_print(void *v) 742 { 743 struct vop_print_args /* { 744 struct vnode *a_vp; 745 } */ *ap = v; 746 747 printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), 748 minor(ap->a_vp->v_rdev)); 749 return 0; 750 } 751 752 /* 753 * Return POSIX pathconf information applicable to special devices. 754 */ 755 int 756 spec_pathconf(void *v) 757 { 758 struct vop_pathconf_args /* { 759 struct vnode *a_vp; 760 int a_name; 761 register_t *a_retval; 762 } */ *ap = v; 763 764 switch (ap->a_name) { 765 case _PC_LINK_MAX: 766 *ap->a_retval = LINK_MAX; 767 return (0); 768 case _PC_MAX_CANON: 769 *ap->a_retval = MAX_CANON; 770 return (0); 771 case _PC_MAX_INPUT: 772 *ap->a_retval = MAX_INPUT; 773 return (0); 774 case _PC_PIPE_BUF: 775 *ap->a_retval = PIPE_BUF; 776 return (0); 777 case _PC_CHOWN_RESTRICTED: 778 *ap->a_retval = 1; 779 return (0); 780 case _PC_VDISABLE: 781 *ap->a_retval = _POSIX_VDISABLE; 782 return (0); 783 case _PC_SYNC_IO: 784 *ap->a_retval = 1; 785 return (0); 786 default: 787 return (EINVAL); 788 } 789 /* NOTREACHED */ 790 } 791 792 /* 793 * Advisory record locking support. 794 */ 795 int 796 spec_advlock(void *v) 797 { 798 struct vop_advlock_args /* { 799 struct vnode *a_vp; 800 void *a_id; 801 int a_op; 802 struct flock *a_fl; 803 int a_flags; 804 } */ *ap = v; 805 struct vnode *vp = ap->a_vp; 806 807 return lf_advlock(ap, &vp->v_speclockf, (off_t)0); 808 } 809