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