1 #define DEBUG 1 2 /* 3 * Copyright (c) 1992, 1993 4 * The Regents of the University of California. All rights reserved. 5 * Copyright (c) 2000 6 * Poul-Henning Kamp. All rights reserved. 7 * 8 * This code is derived from software donated to Berkeley by 9 * Jan-Simon Pendry. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95 33 * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43 34 * 35 * $FreeBSD$ 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/time.h> 42 #include <sys/conf.h> 43 #include <sys/vnode.h> 44 #include <sys/malloc.h> 45 #include <sys/proc.h> 46 #include <sys/mount.h> 47 #include <sys/namei.h> 48 #include <sys/dirent.h> 49 50 #include <fs/devfs/devfs.h> 51 52 static int devfs_access __P((struct vop_access_args *ap)); 53 static int devfs_badop __P((void)); 54 static int devfs_getattr __P((struct vop_getattr_args *ap)); 55 static int devfs_lookupx __P((struct vop_lookup_args *ap)); 56 static int devfs_print __P((struct vop_print_args *ap)); 57 static int devfs_read __P((struct vop_read_args *ap)); 58 static int devfs_readdir __P((struct vop_readdir_args *ap)); 59 static int devfs_readlink __P((struct vop_readlink_args *ap)); 60 static int devfs_reclaim __P((struct vop_reclaim_args *ap)); 61 static int devfs_remove __P((struct vop_remove_args *ap)); 62 static int devfs_revoke __P((struct vop_revoke_args *ap)); 63 static int devfs_setattr __P((struct vop_setattr_args *ap)); 64 static int devfs_symlink __P((struct vop_symlink_args *ap)); 65 66 int 67 devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct proc *p) 68 { 69 int error; 70 struct vnode *vp; 71 dev_t dev; 72 73 if (p == NULL) 74 p = curproc; /* XXX */ 75 loop: 76 vp = de->de_vnode; 77 if (vp != NULL) { 78 if (vget(vp, LK_EXCLUSIVE, p ? p : curproc)) 79 goto loop; 80 *vpp = vp; 81 return (0); 82 } 83 if (de->de_dirent->d_type == DT_CHR) { 84 dev = *devfs_itod(de->de_inode); 85 if (dev == NULL) 86 return (ENOENT); 87 } else { 88 dev = NODEV; 89 } 90 error = getnewvnode(VT_DEVFS, mp, devfs_vnodeop_p, &vp); 91 if (error != 0) { 92 printf("devfs_allocv: failed to allocate new vnode\n"); 93 return (error); 94 } 95 96 if (de->de_dirent->d_type == DT_CHR) { 97 vp->v_type = VCHR; 98 vp = addaliasu(vp, dev->si_udev); 99 vp->v_op = devfs_specop_p; 100 } else if (de->de_dirent->d_type == DT_DIR) { 101 vp->v_type = VDIR; 102 } else if (de->de_dirent->d_type == DT_LNK) { 103 vp->v_type = VLNK; 104 } else { 105 vp->v_type = VBAD; 106 } 107 vp->v_data = de; 108 de->de_vnode = vp; 109 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 110 *vpp = vp; 111 return (0); 112 } 113 114 static int 115 devfs_access(ap) 116 struct vop_access_args /* { 117 struct vnode *a_vp; 118 int a_mode; 119 struct ucred *a_cred; 120 struct proc *a_p; 121 } */ *ap; 122 { 123 struct vnode *vp = ap->a_vp; 124 struct devfs_dirent *de; 125 126 de = vp->v_data; 127 if (vp->v_type == VDIR) 128 de = de->de_dir; 129 130 return (vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid, 131 ap->a_mode, ap->a_cred, NULL)); 132 } 133 134 static int 135 devfs_getattr(ap) 136 struct vop_getattr_args /* { 137 struct vnode *a_vp; 138 struct vattr *a_vap; 139 struct ucred *a_cred; 140 struct proc *a_p; 141 } */ *ap; 142 { 143 struct vnode *vp = ap->a_vp; 144 struct vattr *vap = ap->a_vap; 145 int error = 0; 146 struct devfs_dirent *de; 147 dev_t dev; 148 149 de = vp->v_data; 150 if (vp->v_type == VDIR) 151 de = de->de_dir; 152 bzero((caddr_t) vap, sizeof(*vap)); 153 vattr_null(vap); 154 vap->va_uid = de->de_uid; 155 vap->va_gid = de->de_gid; 156 vap->va_mode = de->de_mode; 157 vap->va_size = 0; 158 vap->va_blocksize = DEV_BSIZE; 159 vap->va_type = vp->v_type; 160 if (vp->v_type != VCHR) { 161 vap->va_atime = de->de_atime; 162 vap->va_mtime = de->de_mtime; 163 vap->va_ctime = de->de_ctime; 164 } else { 165 dev = vp->v_rdev; 166 vap->va_atime = dev->si_atime; 167 vap->va_mtime = dev->si_mtime; 168 vap->va_ctime = dev->si_ctime; 169 vap->va_rdev = dev->si_udev; 170 } 171 vap->va_gen = 0; 172 vap->va_flags = 0; 173 vap->va_bytes = 0; 174 vap->va_nlink = de->de_links; 175 vap->va_fileid = de->de_inode; 176 177 #ifdef DEBUG 178 if (error) 179 printf("devfs_getattr: return error %d\n", error); 180 #endif 181 return (error); 182 } 183 184 static int 185 devfs_lookupx(ap) 186 struct vop_lookup_args /* { 187 struct vnode * a_dvp; 188 struct vnode ** a_vpp; 189 struct componentname * a_cnp; 190 } */ *ap; 191 { 192 struct componentname *cnp; 193 struct vnode *dvp, **vpp; 194 struct proc *p; 195 struct devfs_dirent *de, *dd; 196 struct devfs_mount *dmp; 197 dev_t cdev; 198 int error, cloned, i, flags, nameiop; 199 char specname[SPECNAMELEN + 1], *pname; 200 201 cnp = ap->a_cnp; 202 vpp = ap->a_vpp; 203 dvp = ap->a_dvp; 204 pname = cnp->cn_nameptr; 205 p = cnp->cn_proc; 206 flags = cnp->cn_flags; 207 nameiop = cnp->cn_nameiop; 208 dmp = VFSTODEVFS(dvp->v_mount); 209 cloned = 0; 210 dd = dvp->v_data; 211 212 *vpp = NULLVP; 213 214 if (nameiop == RENAME) 215 return (EOPNOTSUPP); 216 217 if (dvp->v_type != VDIR) 218 return (ENOTDIR); 219 220 if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT)) 221 return (EIO); 222 223 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc); 224 if (error) 225 return (error); 226 227 if (cnp->cn_namelen == 1 && *pname == '.') { 228 if (nameiop != LOOKUP) 229 return (EINVAL); 230 *vpp = dvp; 231 VREF(dvp); 232 return (0); 233 } 234 235 if (flags & ISDOTDOT) { 236 if (nameiop != LOOKUP) 237 return (EINVAL); 238 VOP_UNLOCK(dvp, 0, p); 239 de = TAILQ_FIRST(&dd->de_dlist); /* "." */ 240 de = TAILQ_NEXT(de, de_list); /* ".." */ 241 de = de->de_dir; 242 error = devfs_allocv(de, dvp->v_mount, vpp, p); 243 if (error) { 244 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 245 return (error); 246 } 247 if ((flags & LOCKPARENT) && (flags & ISLASTCN)) 248 error = vn_lock(dvp, LK_EXCLUSIVE, p); 249 if (error) 250 vput(*vpp); 251 return (error); 252 } 253 254 devfs_populate(dmp); 255 dd = dvp->v_data; 256 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 257 if (cnp->cn_namelen != de->de_dirent->d_namlen) 258 continue; 259 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 260 de->de_dirent->d_namlen) != 0) 261 continue; 262 goto found; 263 } 264 265 /* 266 * OK, we didn't have an entry for the name we were asked for 267 * so we try to see if anybody can create it on demand. 268 * We need to construct the full "devname" for this device 269 * relative to "basedir" or the clone functions would not 270 * be able to tell "/dev/foo" from "/dev/bar/foo" 271 */ 272 i = SPECNAMELEN; 273 specname[i] = '\0'; 274 i -= cnp->cn_namelen; 275 if (i < 0) 276 goto notfound; 277 bcopy(cnp->cn_nameptr, specname + i, cnp->cn_namelen); 278 de = dd; 279 while (de != dmp->dm_basedir) { 280 i--; 281 if (i < 0) 282 goto notfound; 283 specname[i] = '/'; 284 i -= de->de_dirent->d_namlen; 285 if (i < 0) 286 goto notfound; 287 bcopy(de->de_dirent->d_name, specname + i, 288 de->de_dirent->d_namlen); 289 de = TAILQ_FIRST(&de->de_dlist); /* "." */ 290 de = TAILQ_NEXT(de, de_list); /* ".." */ 291 de = de->de_dir; 292 } 293 294 #if 0 295 printf("Finished specname: %d \"%s\"\n", i, specname + i); 296 #endif 297 cdev = NODEV; 298 EVENTHANDLER_INVOKE(dev_clone, specname + i, 299 strlen(specname + i), &cdev); 300 #if 0 301 printf("cloned %s -> %p %s\n", specname + i, cdev, 302 cdev == NODEV ? "NODEV" : cdev->si_name); 303 #endif 304 if (cdev == NODEV) 305 goto notfound; 306 307 devfs_populate(dmp); 308 dd = dvp->v_data; 309 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 310 if (cnp->cn_namelen != de->de_dirent->d_namlen) 311 continue; 312 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 313 de->de_dirent->d_namlen) != 0) 314 continue; 315 goto found; 316 } 317 318 notfound: 319 320 if ((nameiop == CREATE || nameiop == RENAME) && 321 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { 322 cnp->cn_flags |= SAVENAME; 323 if (!(flags & LOCKPARENT)) 324 VOP_UNLOCK(dvp, 0, p); 325 return (EJUSTRETURN); 326 } 327 return (ENOENT); 328 329 330 found: 331 332 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { 333 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p); 334 if (error) 335 return (error); 336 if (*vpp == dvp) { 337 VREF(dvp); 338 *vpp = dvp; 339 return (0); 340 } 341 error = devfs_allocv(de, dvp->v_mount, vpp, p); 342 if (error) 343 return (error); 344 if (!(flags & LOCKPARENT)) 345 VOP_UNLOCK(dvp, 0, p); 346 return (0); 347 } 348 error = devfs_allocv(de, dvp->v_mount, vpp, p); 349 if (error) 350 return (error); 351 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) 352 VOP_UNLOCK(dvp, 0, p); 353 return (0); 354 } 355 356 static int 357 devfs_lookup(struct vop_lookup_args *ap) 358 { 359 int j; 360 struct devfs_mount *dmp; 361 362 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 363 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curproc); 364 j = devfs_lookupx(ap); 365 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc); 366 return (j); 367 } 368 369 /* ARGSUSED */ 370 static int 371 devfs_print(ap) 372 struct vop_print_args /* { 373 struct vnode *a_vp; 374 } */ *ap; 375 { 376 377 printf("tag VT_DEVFS, devfs vnode\n"); 378 return (0); 379 } 380 381 static int 382 devfs_read(ap) 383 struct vop_read_args /* { 384 struct vnode *a_vp; 385 struct uio *a_uio; 386 int a_ioflag; 387 struct ucred *a_cred; 388 } */ *ap; 389 { 390 391 if (ap->a_vp->v_type != VDIR) 392 return (EINVAL); 393 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 394 } 395 396 static int 397 devfs_readdir(ap) 398 struct vop_readdir_args /* { 399 struct vnode *a_vp; 400 struct uio *a_uio; 401 struct ucred *a_cred; 402 int *a_eofflag; 403 int *a_ncookies; 404 u_long **a_cookies; 405 } */ *ap; 406 { 407 int error; 408 struct uio *uio; 409 struct dirent *dp; 410 struct devfs_dirent *dd; 411 struct devfs_dirent *de; 412 struct devfs_mount *dmp; 413 off_t off; 414 415 if (ap->a_vp->v_type != VDIR) 416 return (ENOTDIR); 417 418 if (ap->a_ncookies) 419 return (EOPNOTSUPP); 420 421 uio = ap->a_uio; 422 if (uio->uio_offset < 0) 423 return (EINVAL); 424 425 dmp = VFSTODEVFS(ap->a_vp->v_mount); 426 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curproc); 427 devfs_populate(dmp); 428 error = 0; 429 de = ap->a_vp->v_data; 430 dd = TAILQ_FIRST(&de->de_dlist); 431 off = 0; 432 while (dd != NULL) { 433 if (dd->de_dirent->d_type == DT_DIR) 434 de = dd->de_dir; 435 else 436 de = dd; 437 dp = dd->de_dirent; 438 if (dp->d_reclen > uio->uio_resid) 439 break; 440 dp->d_fileno = de->de_inode; 441 if (off >= uio->uio_offset) { 442 error = uiomove((caddr_t)dp, dp->d_reclen, uio); 443 if (error) 444 break; 445 } 446 off += dp->d_reclen; 447 dd = TAILQ_NEXT(dd, de_list); 448 } 449 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc); 450 uio->uio_offset = off; 451 return (error); 452 } 453 454 static int 455 devfs_readlink(ap) 456 struct vop_readlink_args /* { 457 struct vnode *a_vp; 458 struct uio *a_uio; 459 struct ucred *a_cead; 460 } */ *ap; 461 { 462 int error; 463 struct devfs_dirent *de; 464 465 de = ap->a_vp->v_data; 466 error = uiomove(de->de_symlink, strlen(de->de_symlink) + 1, ap->a_uio); 467 return (error); 468 } 469 470 static int 471 devfs_reclaim(ap) 472 struct vop_reclaim_args /* { 473 struct vnode *a_vp; 474 } */ *ap; 475 { 476 struct vnode *vp = ap->a_vp; 477 struct devfs_dirent *de; 478 int i; 479 480 de = vp->v_data; 481 if (de != NULL) 482 de->de_vnode = NULL; 483 if (de != NULL && de->de_flags & DE_ORPHAN) { 484 if (de->de_symlink) 485 FREE(de->de_symlink, M_DEVFS); 486 FREE(de, M_DEVFS); 487 } 488 vp->v_data = NULL; 489 if (vp->v_rdev != NODEV && vp->v_rdev != NULL) { 490 i = vcount(vp); 491 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0) { 492 destroy_dev(vp->v_rdev); 493 printf("Reclaim <%s> %d %d Killed\n", vp->v_rdev->si_name, vp->v_rdev->si_flags, i); 494 } 495 } 496 return (0); 497 } 498 499 static int 500 devfs_remove(ap) 501 struct vop_remove_args /* { 502 struct vnode *a_dvp; 503 struct vnode *a_vp; 504 struct componentname *a_cnp; 505 } */ *ap; 506 { 507 struct vnode *vp = ap->a_vp; 508 struct devfs_dirent *dd; 509 struct devfs_dirent *de, **dep; 510 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); 511 512 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curproc); 513 dd = ap->a_dvp->v_data; 514 de = vp->v_data; 515 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 516 dep = devfs_itode(dmp, de->de_inode); 517 if (dep != NULL) 518 *dep = DE_DELETED; 519 de->de_flags |= DE_ORPHAN; 520 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc); 521 return (0); 522 } 523 524 /* 525 * Revoke is called on a tty when a terminal session ends. The vnode 526 * is orphaned by setting v_op to deadfs so we need to let go of it 527 * as well so that we create a new one next time around. 528 */ 529 static int 530 devfs_revoke(ap) 531 struct vop_revoke_args /* { 532 struct vnode *a_vp; 533 int a_flags; 534 } */ *ap; 535 { 536 struct vnode *vp = ap->a_vp; 537 struct devfs_dirent *de; 538 539 de = vp->v_data; 540 de->de_vnode = NULL; 541 vop_revoke(ap); 542 return (0); 543 } 544 545 static int 546 devfs_setattr(ap) 547 struct vop_setattr_args /* { 548 struct vnode *a_vp; 549 struct vattr *a_vap; 550 struct ucred *a_cred; 551 struct proc *a_p; 552 } */ *ap; 553 { 554 struct devfs_dirent *de; 555 struct vattr *vap; 556 int c, error; 557 uid_t uid; 558 gid_t gid; 559 560 vap = ap->a_vap; 561 if ((vap->va_type != VNON) || 562 (vap->va_nlink != VNOVAL) || 563 (vap->va_fsid != VNOVAL) || 564 (vap->va_fileid != VNOVAL) || 565 (vap->va_blocksize != VNOVAL) || 566 (vap->va_flags != VNOVAL && vap->va_flags != 0) || 567 (vap->va_rdev != VNOVAL) || 568 ((int)vap->va_bytes != VNOVAL) || 569 (vap->va_gen != VNOVAL)) { 570 return (EINVAL); 571 } 572 573 de = ap->a_vp->v_data; 574 if (ap->a_vp->v_type == VDIR) 575 de = de->de_dir; 576 577 error = c = 0; 578 if (vap->va_uid == (uid_t)VNOVAL) 579 uid = de->de_uid; 580 else 581 uid = vap->va_uid; 582 if (vap->va_gid == (gid_t)VNOVAL) 583 gid = de->de_gid; 584 else 585 gid = vap->va_gid; 586 if (uid != de->de_uid || gid != de->de_gid) { 587 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || 588 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) && 589 (error = suser(ap->a_p)) != 0) 590 return (error); 591 de->de_uid = uid; 592 de->de_gid = gid; 593 c = 1; 594 } 595 if (vap->va_mode != (mode_t)VNOVAL) { 596 if ((ap->a_cred->cr_uid != de->de_uid) && 597 (error = suser(ap->a_p))) 598 return (error); 599 de->de_mode = vap->va_mode; 600 c = 1; 601 } 602 if (vap->va_atime.tv_sec != VNOVAL) { 603 if ((ap->a_cred->cr_uid != de->de_uid) && 604 (error = suser(ap->a_p))) 605 return (error); 606 de->de_atime = vap->va_atime; 607 c = 1; 608 } 609 if (vap->va_mtime.tv_sec != VNOVAL) { 610 if ((ap->a_cred->cr_uid != de->de_uid) && 611 (error = suser(ap->a_p))) 612 return (error); 613 de->de_mtime = vap->va_mtime; 614 c = 1; 615 } 616 617 if (c) 618 getnanotime(&de->de_ctime); 619 return (0); 620 } 621 622 static int 623 devfs_symlink(ap) 624 struct vop_symlink_args /* { 625 struct vnode *a_dvp; 626 struct vnode **a_vpp; 627 struct componentname *a_cnp; 628 struct vattr *a_vap; 629 char *a_target; 630 } */ *ap; 631 { 632 int i; 633 struct devfs_dirent *dd; 634 struct devfs_dirent *de; 635 struct devfs_mount *dmp; 636 637 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 638 dd = ap->a_dvp->v_data; 639 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 640 de->de_uid = 0; 641 de->de_gid = 0; 642 de->de_mode = 0642; 643 de->de_inode = dmp->dm_inode++; 644 de->de_dirent->d_type = DT_LNK; 645 i = strlen(ap->a_target) + 1; 646 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK); 647 bcopy(ap->a_target, de->de_symlink, i); 648 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curproc); 649 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 650 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); 651 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc); 652 return (0); 653 } 654 655 /* 656 * DEVFS "should never get here" operation 657 */ 658 static int 659 devfs_badop() 660 { 661 return (EIO); 662 } 663 664 vop_t **devfs_vnodeop_p; 665 static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 666 { &vop_default_desc, (vop_t *) vop_defaultop }, 667 { &vop_access_desc, (vop_t *) devfs_access }, 668 { &vop_bmap_desc, (vop_t *) devfs_badop }, 669 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 670 { &vop_lookup_desc, (vop_t *) devfs_lookup }, 671 { &vop_pathconf_desc, (vop_t *) vop_stdpathconf }, 672 { &vop_print_desc, (vop_t *) devfs_print }, 673 { &vop_read_desc, (vop_t *) devfs_read }, 674 { &vop_readdir_desc, (vop_t *) devfs_readdir }, 675 { &vop_readlink_desc, (vop_t *) devfs_readlink }, 676 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 677 { &vop_remove_desc, (vop_t *) devfs_remove }, 678 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 679 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 680 { &vop_symlink_desc, (vop_t *) devfs_symlink }, 681 { NULL, NULL } 682 }; 683 static struct vnodeopv_desc devfs_vnodeop_opv_desc = 684 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 685 686 VNODEOP_SET(devfs_vnodeop_opv_desc); 687 688 #if 0 689 int 690 foo(ap) 691 struct vop_generic_args *ap; 692 { 693 int i; 694 695 i = spec_vnoperate(ap); 696 printf("foo(%s) = %d\n", ap->a_desc->vdesc_name, i); 697 return (i); 698 } 699 #endif 700 701 vop_t **devfs_specop_p; 702 static struct vnodeopv_entry_desc devfs_specop_entries[] = { 703 #if 1 704 { &vop_default_desc, (vop_t *) spec_vnoperate }, 705 #else 706 { &vop_default_desc, (vop_t *) foo }, 707 { &vop_lock_desc, (vop_t *) spec_vnoperate }, 708 { &vop_unlock_desc, (vop_t *) spec_vnoperate }, 709 { &vop_lease_desc, (vop_t *) spec_vnoperate }, 710 { &vop_strategy_desc, (vop_t *) spec_vnoperate }, 711 { &vop_bmap_desc, (vop_t *) spec_vnoperate }, 712 #endif 713 { &vop_access_desc, (vop_t *) devfs_access }, 714 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 715 { &vop_print_desc, (vop_t *) devfs_print }, 716 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 717 { &vop_remove_desc, (vop_t *) devfs_remove }, 718 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 719 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 720 { NULL, NULL } 721 }; 722 static struct vnodeopv_desc devfs_specop_opv_desc = 723 { &devfs_specop_p, devfs_specop_entries }; 724 725 VNODEOP_SET(devfs_specop_opv_desc); 726