1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * All rights reserved. 5 * 6 * This code is derived from software donated to Berkeley by 7 * Jan-Simon Pendry. 8 * 9 * %sccs.include.redist.c% 10 * 11 * @(#)kernfs_vnops.c 8.4 (Berkeley) 01/14/94 12 */ 13 14 /* 15 * Kernel parameter filesystem (/kern) 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/kernel.h> 21 #include <sys/vmmeter.h> 22 #include <sys/types.h> 23 #include <sys/time.h> 24 #include <sys/proc.h> 25 #include <sys/vnode.h> 26 #include <sys/malloc.h> 27 #include <sys/file.h> 28 #include <sys/stat.h> 29 #include <sys/mount.h> 30 #include <sys/namei.h> 31 #include <sys/buf.h> 32 #include <sys/dirent.h> 33 #include <miscfs/kernfs/kernfs.h> 34 35 #define KSTRING 256 /* Largest I/O available via this filesystem */ 36 #define UIO_MX 32 37 38 #define READ_MODE (S_IRUSR|S_IRGRP|S_IROTH) 39 #define WRITE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) 40 #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 41 42 struct kern_target { 43 char *kt_name; 44 void *kt_data; 45 #define KTT_NULL 1 46 #define KTT_TIME 5 47 #define KTT_INT 17 48 #define KTT_STRING 31 49 #define KTT_HOSTNAME 47 50 #define KTT_AVENRUN 53 51 int kt_tag; 52 int kt_rw; 53 int kt_vtype; 54 } kern_targets[] = { 55 /* NOTE: The name must be less than UIO_MX-16 chars in length */ 56 /* name data tag ro/rw */ 57 { ".", 0, KTT_NULL, VREAD, VDIR }, 58 { "..", 0, KTT_NULL, VREAD, VDIR }, 59 { "boottime", &boottime.tv_sec, KTT_INT, VREAD, VREG }, 60 { "copyright", copyright, KTT_STRING, VREAD, VREG }, 61 { "hostname", 0, KTT_HOSTNAME, VREAD|VWRITE, VREG }, 62 { "hz", &hz, KTT_INT, VREAD, VREG }, 63 { "loadavg", 0, KTT_AVENRUN, VREAD, VREG }, 64 { "pagesize", &cnt.v_page_size, KTT_INT, VREAD, VREG }, 65 { "physmem", &physmem, KTT_INT, VREAD, VREG }, 66 #if 0 67 { "root", 0, KTT_NULL, VREAD, VDIR }, 68 #endif 69 { "rootdev", 0, KTT_NULL, VREAD, VBLK }, 70 { "rrootdev", 0, KTT_NULL, VREAD, VCHR }, 71 { "time", 0, KTT_TIME, VREAD, VREG }, 72 { "version", version, KTT_STRING, VREAD, VREG }, 73 }; 74 75 static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]); 76 77 static int 78 kernfs_xread(kt, buf, len, lenp) 79 struct kern_target *kt; 80 char *buf; 81 int len; 82 int *lenp; 83 { 84 switch (kt->kt_tag) { 85 case KTT_TIME: { 86 struct timeval tv; 87 microtime(&tv); 88 sprintf(buf, "%d %d\n", tv.tv_sec, tv.tv_usec); 89 break; 90 } 91 92 case KTT_INT: { 93 int *ip = kt->kt_data; 94 sprintf(buf, "%d\n", *ip); 95 break; 96 } 97 98 case KTT_STRING: { 99 char *cp = kt->kt_data; 100 int xlen = strlen(cp) + 1; 101 102 if (xlen >= len) 103 return (EINVAL); 104 105 bcopy(cp, buf, xlen); 106 break; 107 } 108 109 case KTT_HOSTNAME: { 110 char *cp = hostname; 111 int xlen = hostnamelen; 112 113 if (xlen >= (len-2)) 114 return (EINVAL); 115 116 bcopy(cp, buf, xlen); 117 buf[xlen] = '\n'; 118 buf[xlen+1] = '\0'; 119 break; 120 } 121 122 case KTT_AVENRUN: 123 sprintf(buf, "%ld %ld %ld %ld\n", 124 averunnable.ldavg[0], 125 averunnable.ldavg[1], 126 averunnable.ldavg[2], 127 averunnable.fscale); 128 break; 129 130 default: 131 return (EINVAL); 132 } 133 134 *lenp = strlen(buf); 135 return (0); 136 } 137 138 static int 139 kernfs_xwrite(kt, buf, len) 140 struct kern_target *kt; 141 char *buf; 142 int len; 143 { 144 switch (kt->kt_tag) { 145 case KTT_HOSTNAME: { 146 if (buf[len-1] == '\n') 147 --len; 148 bcopy(buf, hostname, len); 149 hostname[len] = '\0'; 150 hostnamelen = len; 151 return (0); 152 } 153 154 default: 155 return (EIO); 156 } 157 } 158 159 160 /* 161 * vp is the current namei directory 162 * ndp is the name to locate in that directory... 163 */ 164 kernfs_lookup(ap) 165 struct vop_lookup_args /* { 166 struct vnode * a_dvp; 167 struct vnode ** a_vpp; 168 struct componentname * a_cnp; 169 } */ *ap; 170 { 171 struct vnode **vpp = ap->a_vpp; 172 struct vnode *dvp = ap->a_dvp; 173 struct componentname *cnp = ap->a_cnp; 174 struct vnode *fvp; 175 int error, i; 176 char *pname; 177 178 #ifdef KERNFS_DIAGNOSTIC 179 printf("kernfs_lookup(%x)\n", ap); 180 printf("kernfs_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp); 181 #endif 182 pname = cnp->cn_nameptr; 183 #ifdef KERNFS_DIAGNOSTIC 184 printf("kernfs_lookup(%s)\n", pname); 185 #endif 186 if (cnp->cn_namelen == 1 && *pname == '.') { 187 *vpp = dvp; 188 VREF(dvp); 189 /*VOP_LOCK(dvp);*/ 190 return (0); 191 } 192 193 #if 0 194 if (cnp->cn_namelen == 4 && bcmp(pname, "root", 4) == 0) { 195 *vpp = rootdir; 196 VREF(rootdir); 197 VOP_LOCK(rootdir); 198 return (0); 199 } 200 #endif 201 202 /* 203 * /kern/rootdev is the root device 204 */ 205 if (cnp->cn_namelen == 7 && bcmp(pname, "rootdev", 7) == 0) { 206 *vpp = rootvp; 207 VREF(rootvp); 208 VOP_LOCK(rootvp); 209 return (0); 210 } 211 212 /* 213 * /kern/rrootdev is the raw root device 214 */ 215 if (cnp->cn_namelen == 8 && bcmp(pname, "rrootdev", 8) == 0) { 216 if (rrootvp) { 217 *vpp = rrootvp; 218 VREF(rrootvp); 219 VOP_LOCK(rrootvp); 220 return (0); 221 } 222 error = ENXIO; 223 goto bad; 224 } 225 226 error = ENOENT; 227 228 for (i = 0; i < nkern_targets; i++) { 229 struct kern_target *kt = &kern_targets[i]; 230 if (cnp->cn_namelen == strlen(kt->kt_name) && 231 bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) { 232 error = 0; 233 break; 234 } 235 } 236 237 #ifdef KERNFS_DIAGNOSTIC 238 printf("kernfs_lookup: i = %d, error = %d\n", i, error); 239 #endif 240 241 if (error) 242 goto bad; 243 244 #ifdef KERNFS_DIAGNOSTIC 245 printf("kernfs_lookup: allocate new vnode\n"); 246 #endif 247 error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p, &fvp); 248 if (error) 249 goto bad; 250 MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, M_WAITOK); 251 VTOKERN(fvp)->kf_kt = &kern_targets[i]; 252 fvp->v_type = VTOKERN(fvp)->kf_kt->kt_vtype; 253 *vpp = fvp; 254 #ifdef KERNFS_DIAGNOSTIC 255 printf("kernfs_lookup: newvp = %x\n", fvp); 256 #endif 257 return (0); 258 259 bad:; 260 *vpp = NULL; 261 #ifdef KERNFS_DIAGNOSTIC 262 printf("kernfs_lookup: error = %d\n", error); 263 #endif 264 return (error); 265 } 266 267 kernfs_open(ap) 268 struct vop_open_args /* { 269 struct vnode *a_vp; 270 int a_mode; 271 struct ucred *a_cred; 272 struct proc *a_p; 273 } */ *ap; 274 { 275 struct vnode *vp = ap->a_vp; 276 277 /* 278 * Can always open the root (modulo perms) 279 */ 280 if (vp->v_flag & VROOT) 281 return (0); 282 283 #ifdef KERNFS_DIAGNOSTIC 284 printf("kernfs_open, mode = %x, file = %s\n", 285 ap->a_mode, VTOKERN(vp)->kf_kt->kt_name); 286 #endif 287 288 if ((ap->a_mode & FWRITE) && !(VTOKERN(vp)->kf_kt->kt_rw & VWRITE)) 289 return (EOPNOTSUPP); 290 291 return (0); 292 } 293 294 static int 295 kernfs_access(ap) 296 struct vop_access_args /* { 297 struct vnode *a_vp; 298 int a_mode; 299 struct ucred *a_cred; 300 struct proc *a_p; 301 } */ *ap; 302 { 303 struct vnode *vp = ap->a_vp; 304 struct ucred *cred = ap->a_cred; 305 mode_t mode = ap->a_mode; 306 307 if (mode & VEXEC) { 308 if (vp->v_flag & VROOT) 309 return (0); 310 return (EACCES); 311 } 312 313 if (cred->cr_uid == 0) { 314 if ((vp->v_flag & VROOT) == 0) { 315 struct kern_target *kt = VTOKERN(vp)->kf_kt; 316 317 if ((mode & VWRITE) && !(kt->kt_rw & VWRITE)) 318 return (EROFS); 319 } 320 return (0); 321 } 322 323 if (mode & VWRITE) 324 return (EACCES); 325 326 return (0); 327 } 328 329 330 kernfs_getattr(ap) 331 struct vop_getattr_args /* { 332 struct vnode *a_vp; 333 struct vattr *a_vap; 334 struct ucred *a_cred; 335 struct proc *a_p; 336 } */ *ap; 337 { 338 struct vnode *vp = ap->a_vp; 339 struct vattr *vap = ap->a_vap; 340 int error = 0; 341 char strbuf[KSTRING]; 342 343 bzero((caddr_t) vap, sizeof(*vap)); 344 vattr_null(vap); 345 vap->va_uid = 0; 346 vap->va_gid = 0; 347 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 348 /* vap->va_qsize = 0; */ 349 vap->va_blocksize = DEV_BSIZE; 350 microtime(&vap->va_atime); 351 vap->va_mtime = vap->va_atime; 352 vap->va_ctime = vap->va_ctime; 353 vap->va_gen = 0; 354 vap->va_flags = 0; 355 vap->va_rdev = 0; 356 /* vap->va_qbytes = 0; */ 357 vap->va_bytes = 0; 358 359 if (vp->v_flag & VROOT) { 360 #ifdef KERNFS_DIAGNOSTIC 361 printf("kernfs_getattr: stat rootdir\n"); 362 #endif 363 vap->va_type = VDIR; 364 vap->va_mode = DIR_MODE; 365 vap->va_nlink = 2; 366 vap->va_fileid = 2; 367 vap->va_size = DEV_BSIZE; 368 } else { 369 struct kern_target *kt = VTOKERN(vp)->kf_kt; 370 int nbytes; 371 #ifdef KERNFS_DIAGNOSTIC 372 printf("kernfs_getattr: stat target %s\n", kt->kt_name); 373 #endif 374 vap->va_type = kt->kt_vtype; 375 vap->va_mode = (kt->kt_rw & VWRITE ? WRITE_MODE : READ_MODE); 376 vap->va_nlink = 1; 377 vap->va_fileid = 3 + (kt - kern_targets) / sizeof(*kt); 378 error = kernfs_xread(kt, strbuf, sizeof(strbuf), &nbytes); 379 vap->va_size = nbytes; 380 } 381 382 vp->v_type = vap->va_type; 383 #ifdef KERNFS_DIAGNOSTIC 384 printf("kernfs_getattr: return error %d\n", error); 385 #endif 386 return (error); 387 } 388 389 kernfs_setattr(ap) 390 struct vop_setattr_args /* { 391 struct vnode *a_vp; 392 struct vattr *a_vap; 393 struct ucred *a_cred; 394 struct proc *a_p; 395 } */ *ap; 396 { 397 398 /* 399 * Silently ignore attribute changes. 400 * This allows for open with truncate to have no 401 * effect until some data is written. I want to 402 * do it this way because all writes are atomic. 403 */ 404 return (0); 405 } 406 407 static int 408 kernfs_read(ap) 409 struct vop_read_args /* { 410 struct vnode *a_vp; 411 struct uio *a_uio; 412 int a_ioflag; 413 struct ucred *a_cred; 414 } */ *ap; 415 { 416 struct vnode *vp = ap->a_vp; 417 struct uio *uio = ap->a_uio; 418 struct kern_target *kt; 419 char strbuf[KSTRING]; 420 int off = uio->uio_offset; 421 int error, len; 422 char *cp; 423 424 if (vp->v_flag & VROOT) 425 return (0); 426 427 kt = VTOKERN(vp)->kf_kt; 428 429 #ifdef KERNFS_DIAGNOSTIC 430 printf("kern_read %s\n", kt->kt_name); 431 #endif 432 433 len = 0; 434 error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len); 435 if (error) 436 return (error); 437 cp = strbuf + off; 438 len -= off; 439 return (uiomove(cp, len, uio)); 440 } 441 442 static int 443 kernfs_write(ap) 444 struct vop_write_args /* { 445 struct vnode *a_vp; 446 struct uio *a_uio; 447 int a_ioflag; 448 struct ucred *a_cred; 449 } */ *ap; 450 { 451 struct vnode *vp = ap->a_vp; 452 struct uio *uio = ap->a_uio; 453 struct kern_target *kt; 454 int error, xlen; 455 char strbuf[KSTRING]; 456 457 if (vp->v_flag & VROOT) 458 return (0); 459 460 kt = VTOKERN(vp)->kf_kt; 461 462 if (uio->uio_offset != 0) 463 return (EINVAL); 464 465 xlen = min(uio->uio_resid, KSTRING-1); 466 error = uiomove(strbuf, xlen, uio); 467 if (error) 468 return (error); 469 470 if (uio->uio_resid != 0) 471 return (EIO); 472 473 strbuf[xlen] = '\0'; 474 xlen = strlen(strbuf); 475 return (kernfs_xwrite(kt, strbuf, xlen)); 476 } 477 478 479 kernfs_readdir(ap) 480 struct vop_readdir_args /* { 481 struct vnode *a_vp; 482 struct uio *a_uio; 483 struct ucred *a_cred; 484 } */ *ap; 485 { 486 struct uio *uio = ap->a_uio; 487 int i; 488 int error; 489 490 i = uio->uio_offset / UIO_MX; 491 error = 0; 492 while (uio->uio_resid > 0 && i < nkern_targets) { 493 struct dirent d; 494 struct dirent *dp = &d; 495 struct kern_target *kt = &kern_targets[i]; 496 #ifdef KERNFS_DIAGNOSTIC 497 printf("kernfs_readdir: i = %d\n", i); 498 #endif 499 500 bzero((caddr_t) dp, UIO_MX); 501 502 dp->d_namlen = strlen(kt->kt_name); 503 bcopy(kt->kt_name, dp->d_name, dp->d_namlen+1); 504 505 #ifdef KERNFS_DIAGNOSTIC 506 printf("kernfs_readdir: name = %s, len = %d\n", 507 dp->d_name, dp->d_namlen); 508 #endif 509 /* 510 * Fill in the remaining fields 511 */ 512 dp->d_reclen = UIO_MX; 513 dp->d_fileno = i + 3; 514 dp->d_type = DT_UNKNOWN; /* XXX */ 515 /* 516 * And ship to userland 517 */ 518 error = uiomove((caddr_t) dp, UIO_MX, uio); 519 if (error) 520 break; 521 i++; 522 } 523 524 uio->uio_offset = i * UIO_MX; 525 526 return (error); 527 } 528 529 kernfs_inactive(ap) 530 struct vop_inactive_args /* { 531 struct vnode *a_vp; 532 } */ *ap; 533 { 534 struct vnode *vp = ap->a_vp; 535 536 /* 537 * Clear out the v_type field to avoid 538 * nasty things happening in vgone(). 539 */ 540 vp->v_type = VNON; 541 #ifdef KERNFS_DIAGNOSTIC 542 printf("kernfs_inactive(%x)\n", vp); 543 #endif 544 return (0); 545 } 546 547 kernfs_reclaim(ap) 548 struct vop_reclaim_args /* { 549 struct vnode *a_vp; 550 } */ *ap; 551 { 552 struct vnode *vp = ap->a_vp; 553 #ifdef KERNFS_DIAGNOSTIC 554 printf("kernfs_reclaim(%x)\n", vp); 555 #endif 556 if (vp->v_data) { 557 FREE(vp->v_data, M_TEMP); 558 vp->v_data = 0; 559 } 560 return (0); 561 } 562 563 /* 564 * Return POSIX pathconf information applicable to special devices. 565 */ 566 kernfs_pathconf(ap) 567 struct vop_pathconf_args /* { 568 struct vnode *a_vp; 569 int a_name; 570 int *a_retval; 571 } */ *ap; 572 { 573 574 switch (ap->a_name) { 575 case _PC_LINK_MAX: 576 *ap->a_retval = LINK_MAX; 577 return (0); 578 case _PC_MAX_CANON: 579 *ap->a_retval = MAX_CANON; 580 return (0); 581 case _PC_MAX_INPUT: 582 *ap->a_retval = MAX_INPUT; 583 return (0); 584 case _PC_PIPE_BUF: 585 *ap->a_retval = PIPE_BUF; 586 return (0); 587 case _PC_CHOWN_RESTRICTED: 588 *ap->a_retval = 1; 589 return (0); 590 case _PC_VDISABLE: 591 *ap->a_retval = _POSIX_VDISABLE; 592 return (0); 593 default: 594 return (EINVAL); 595 } 596 /* NOTREACHED */ 597 } 598 599 /* 600 * Print out the contents of a /dev/fd vnode. 601 */ 602 /* ARGSUSED */ 603 kernfs_print(ap) 604 struct vop_print_args /* { 605 struct vnode *a_vp; 606 } */ *ap; 607 { 608 609 printf("tag VT_KERNFS, kernfs vnode\n"); 610 return (0); 611 } 612 613 /*void*/ 614 kernfs_vfree(ap) 615 struct vop_vfree_args /* { 616 struct vnode *a_pvp; 617 ino_t a_ino; 618 int a_mode; 619 } */ *ap; 620 { 621 622 return (0); 623 } 624 625 /* 626 * /dev/fd vnode unsupported operation 627 */ 628 kernfs_enotsupp() 629 { 630 631 return (EOPNOTSUPP); 632 } 633 634 /* 635 * /dev/fd "should never get here" operation 636 */ 637 kernfs_badop() 638 { 639 640 panic("kernfs: bad op"); 641 /* NOTREACHED */ 642 } 643 644 /* 645 * kernfs vnode null operation 646 */ 647 kernfs_nullop() 648 { 649 650 return (0); 651 } 652 653 #define kernfs_create ((int (*) __P((struct vop_create_args *)))kernfs_enotsupp) 654 #define kernfs_mknod ((int (*) __P((struct vop_mknod_args *)))kernfs_enotsupp) 655 #define kernfs_close ((int (*) __P((struct vop_close_args *)))nullop) 656 #define kernfs_ioctl ((int (*) __P((struct vop_ioctl_args *)))kernfs_enotsupp) 657 #define kernfs_select ((int (*) __P((struct vop_select_args *)))kernfs_enotsupp) 658 #define kernfs_mmap ((int (*) __P((struct vop_mmap_args *)))kernfs_enotsupp) 659 #define kernfs_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 660 #define kernfs_seek ((int (*) __P((struct vop_seek_args *)))nullop) 661 #define kernfs_remove ((int (*) __P((struct vop_remove_args *)))kernfs_enotsupp) 662 #define kernfs_link ((int (*) __P((struct vop_link_args *)))kernfs_enotsupp) 663 #define kernfs_rename ((int (*) __P((struct vop_rename_args *)))kernfs_enotsupp) 664 #define kernfs_mkdir ((int (*) __P((struct vop_mkdir_args *)))kernfs_enotsupp) 665 #define kernfs_rmdir ((int (*) __P((struct vop_rmdir_args *)))kernfs_enotsupp) 666 #define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))kernfs_enotsupp) 667 #define kernfs_readlink \ 668 ((int (*) __P((struct vop_readlink_args *)))kernfs_enotsupp) 669 #define kernfs_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) 670 #define kernfs_lock ((int (*) __P((struct vop_lock_args *)))nullop) 671 #define kernfs_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) 672 #define kernfs_bmap ((int (*) __P((struct vop_bmap_args *)))kernfs_badop) 673 #define kernfs_strategy ((int (*) __P((struct vop_strategy_args *)))kernfs_badop) 674 #define kernfs_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) 675 #define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))kernfs_enotsupp) 676 #define kernfs_blkatoff \ 677 ((int (*) __P((struct vop_blkatoff_args *)))kernfs_enotsupp) 678 #define kernfs_valloc ((int(*) __P(( \ 679 struct vnode *pvp, \ 680 int mode, \ 681 struct ucred *cred, \ 682 struct vnode **vpp))) kernfs_enotsupp) 683 #define kernfs_truncate \ 684 ((int (*) __P((struct vop_truncate_args *)))kernfs_enotsupp) 685 #define kernfs_update ((int (*) __P((struct vop_update_args *)))kernfs_enotsupp) 686 #define kernfs_bwrite ((int (*) __P((struct vop_bwrite_args *)))kernfs_enotsupp) 687 688 int (**kernfs_vnodeop_p)(); 689 struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = { 690 { &vop_default_desc, vn_default_error }, 691 { &vop_lookup_desc, kernfs_lookup }, /* lookup */ 692 { &vop_create_desc, kernfs_create }, /* create */ 693 { &vop_mknod_desc, kernfs_mknod }, /* mknod */ 694 { &vop_open_desc, kernfs_open }, /* open */ 695 { &vop_close_desc, kernfs_close }, /* close */ 696 { &vop_access_desc, kernfs_access }, /* access */ 697 { &vop_getattr_desc, kernfs_getattr }, /* getattr */ 698 { &vop_setattr_desc, kernfs_setattr }, /* setattr */ 699 { &vop_read_desc, kernfs_read }, /* read */ 700 { &vop_write_desc, kernfs_write }, /* write */ 701 { &vop_ioctl_desc, kernfs_ioctl }, /* ioctl */ 702 { &vop_select_desc, kernfs_select }, /* select */ 703 { &vop_mmap_desc, kernfs_mmap }, /* mmap */ 704 { &vop_fsync_desc, kernfs_fsync }, /* fsync */ 705 { &vop_seek_desc, kernfs_seek }, /* seek */ 706 { &vop_remove_desc, kernfs_remove }, /* remove */ 707 { &vop_link_desc, kernfs_link }, /* link */ 708 { &vop_rename_desc, kernfs_rename }, /* rename */ 709 { &vop_mkdir_desc, kernfs_mkdir }, /* mkdir */ 710 { &vop_rmdir_desc, kernfs_rmdir }, /* rmdir */ 711 { &vop_symlink_desc, kernfs_symlink }, /* symlink */ 712 { &vop_readdir_desc, kernfs_readdir }, /* readdir */ 713 { &vop_readlink_desc, kernfs_readlink },/* readlink */ 714 { &vop_abortop_desc, kernfs_abortop }, /* abortop */ 715 { &vop_inactive_desc, kernfs_inactive },/* inactive */ 716 { &vop_reclaim_desc, kernfs_reclaim }, /* reclaim */ 717 { &vop_lock_desc, kernfs_lock }, /* lock */ 718 { &vop_unlock_desc, kernfs_unlock }, /* unlock */ 719 { &vop_bmap_desc, kernfs_bmap }, /* bmap */ 720 { &vop_strategy_desc, kernfs_strategy },/* strategy */ 721 { &vop_print_desc, kernfs_print }, /* print */ 722 { &vop_islocked_desc, kernfs_islocked },/* islocked */ 723 { &vop_pathconf_desc, kernfs_pathconf },/* pathconf */ 724 { &vop_advlock_desc, kernfs_advlock }, /* advlock */ 725 { &vop_blkatoff_desc, kernfs_blkatoff },/* blkatoff */ 726 { &vop_valloc_desc, kernfs_valloc }, /* valloc */ 727 { &vop_vfree_desc, kernfs_vfree }, /* vfree */ 728 { &vop_truncate_desc, kernfs_truncate },/* truncate */ 729 { &vop_update_desc, kernfs_update }, /* update */ 730 { &vop_bwrite_desc, kernfs_bwrite }, /* bwrite */ 731 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 732 }; 733 struct vnodeopv_desc kernfs_vnodeop_opv_desc = 734 { &kernfs_vnodeop_p, kernfs_vnodeop_entries }; 735