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