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