1 /* $NetBSD: kernfs_vnops.c,v 1.53 1997/10/10 02:01:02 fvdl 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 long n; 222 223 /* 224 * deal with cases where the message buffer has 225 * become corrupted. 226 */ 227 if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) { 228 msgbufenabled = 0; 229 return (ENXIO); 230 } 231 232 /* 233 * Note that reads of /kern/msgbuf won't necessarily yield 234 * consistent results, if the message buffer is modified 235 * while the read is in progress. The worst that can happen 236 * is that incorrect data will be read. There's no way 237 * that this can crash the system unless the values in the 238 * message buffer header are corrupted, but that'll cause 239 * the system to die anyway. 240 */ 241 if (off >= msgbufp->msg_bufs) 242 return (0); 243 n = msgbufp->msg_bufx + off; 244 if (n >= msgbufp->msg_bufs) 245 n -= msgbufp->msg_bufs; 246 len = min(msgbufp->msg_bufs - n, msgbufp->msg_bufs - off); 247 *bufp = msgbufp->msg_bufc + n; 248 return (len); 249 } 250 251 case KTT_HOSTNAME: { 252 char *cp = hostname; 253 int xlen = hostnamelen; 254 255 if (xlen >= (len-2)) 256 return (EINVAL); 257 258 bcopy(cp, *bufp, xlen); 259 (*bufp)[xlen] = '\n'; 260 (*bufp)[xlen+1] = '\0'; 261 break; 262 } 263 264 case KTT_AVENRUN: 265 averunnable.fscale = FSCALE; 266 sprintf(*bufp, "%d %d %d %ld\n", 267 averunnable.ldavg[0], averunnable.ldavg[1], 268 averunnable.ldavg[2], averunnable.fscale); 269 break; 270 271 default: 272 return (0); 273 } 274 275 len = strlen(*bufp); 276 if (len <= off) 277 return (0); 278 *bufp += off; 279 return (len - off); 280 } 281 282 int 283 kernfs_xwrite(kt, buf, len) 284 struct kern_target *kt; 285 char *buf; 286 int len; 287 { 288 289 switch (kt->kt_tag) { 290 case KTT_HOSTNAME: 291 if (buf[len-1] == '\n') 292 --len; 293 bcopy(buf, hostname, len); 294 hostname[len] = '\0'; 295 hostnamelen = len; 296 return (0); 297 298 default: 299 return (EIO); 300 } 301 } 302 303 304 /* 305 * vp is the current namei directory 306 * ndp is the name to locate in that directory... 307 */ 308 int 309 kernfs_lookup(v) 310 void *v; 311 { 312 struct vop_lookup_args /* { 313 struct vnode * a_dvp; 314 struct vnode ** a_vpp; 315 struct componentname * a_cnp; 316 } */ *ap = v; 317 struct componentname *cnp = ap->a_cnp; 318 struct vnode **vpp = ap->a_vpp; 319 struct vnode *dvp = ap->a_dvp; 320 const char *pname = cnp->cn_nameptr; 321 struct kern_target *kt; 322 struct vnode *fvp; 323 int error, i; 324 325 #ifdef KERNFS_DIAGNOSTIC 326 printf("kernfs_lookup(%p)\n", ap); 327 printf("kernfs_lookup(dp = %p, vpp = %p, cnp = %p)\n", dvp, vpp, ap->a_cnp); 328 printf("kernfs_lookup(%s)\n", pname); 329 #endif 330 331 *vpp = NULLVP; 332 333 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) 334 return (EROFS); 335 336 if (cnp->cn_namelen == 1 && *pname == '.') { 337 *vpp = dvp; 338 VREF(dvp); 339 /*VOP_LOCK(dvp);*/ 340 return (0); 341 } 342 343 #if 0 344 if (cnp->cn_namelen == 4 && bcmp(pname, "root", 4) == 0) { 345 *vpp = rootdir; 346 VREF(rootdir); 347 VOP_LOCK(rootdir); 348 return (0); 349 } 350 #endif 351 352 for (kt = kern_targets, i = 0; i < nkern_targets; kt++, i++) { 353 if (cnp->cn_namelen == kt->kt_namlen && 354 bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) 355 goto found; 356 } 357 358 #ifdef KERNFS_DIAGNOSTIC 359 printf("kernfs_lookup: i = %d, failed", i); 360 #endif 361 362 return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); 363 364 found: 365 if (kt->kt_tag == KTT_DEVICE) { 366 dev_t *dp = kt->kt_data; 367 loop: 368 if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) 369 return (ENOENT); 370 *vpp = fvp; 371 if (vget(fvp, 1)) 372 goto loop; 373 return (0); 374 } 375 376 #ifdef KERNFS_DIAGNOSTIC 377 printf("kernfs_lookup: allocate new vnode\n"); 378 #endif 379 error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p, &fvp); 380 if (error) 381 return (error); 382 383 MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, 384 M_WAITOK); 385 VTOKERN(fvp)->kf_kt = kt; 386 fvp->v_type = kt->kt_vtype; 387 *vpp = fvp; 388 389 #ifdef KERNFS_DIAGNOSTIC 390 printf("kernfs_lookup: newvp = %p\n", fvp); 391 #endif 392 return (0); 393 } 394 395 int 396 kernfs_access(v) 397 void *v; 398 { 399 struct vop_access_args /* { 400 struct vnode *a_vp; 401 int a_mode; 402 struct ucred *a_cred; 403 struct proc *a_p; 404 } */ *ap = v; 405 struct vnode *vp = ap->a_vp; 406 mode_t mode; 407 408 if (vp->v_flag & VROOT) { 409 mode = DIR_MODE; 410 } else { 411 struct kern_target *kt = VTOKERN(vp)->kf_kt; 412 mode = kt->kt_mode; 413 } 414 415 return (vaccess(vp->v_type, mode, (uid_t)0, (gid_t)0, ap->a_mode, 416 ap->a_cred)); 417 } 418 419 int 420 kernfs_getattr(v) 421 void *v; 422 { 423 struct vop_getattr_args /* { 424 struct vnode *a_vp; 425 struct vattr *a_vap; 426 struct ucred *a_cred; 427 struct proc *a_p; 428 } */ *ap = v; 429 struct vnode *vp = ap->a_vp; 430 struct vattr *vap = ap->a_vap; 431 struct timeval tv; 432 int error = 0; 433 char strbuf[KSTRING], *buf; 434 435 bzero((caddr_t) vap, sizeof(*vap)); 436 vattr_null(vap); 437 vap->va_uid = 0; 438 vap->va_gid = 0; 439 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 440 vap->va_size = 0; 441 vap->va_blocksize = DEV_BSIZE; 442 microtime(&tv); 443 TIMEVAL_TO_TIMESPEC(&tv, &vap->va_atime); 444 vap->va_mtime = vap->va_atime; 445 vap->va_ctime = vap->va_ctime; 446 vap->va_gen = 0; 447 vap->va_flags = 0; 448 vap->va_rdev = 0; 449 vap->va_bytes = 0; 450 451 if (vp->v_flag & VROOT) { 452 #ifdef KERNFS_DIAGNOSTIC 453 printf("kernfs_getattr: stat rootdir\n"); 454 #endif 455 vap->va_type = VDIR; 456 vap->va_mode = DIR_MODE; 457 vap->va_nlink = 2; 458 vap->va_fileid = 2; 459 vap->va_size = DEV_BSIZE; 460 } else { 461 struct kern_target *kt = VTOKERN(vp)->kf_kt; 462 int nbytes, total; 463 #ifdef KERNFS_DIAGNOSTIC 464 printf("kernfs_getattr: stat target %s\n", kt->kt_name); 465 #endif 466 vap->va_type = kt->kt_vtype; 467 vap->va_mode = kt->kt_mode; 468 vap->va_nlink = 1; 469 vap->va_fileid = 3 + (kt - kern_targets); 470 total = 0; 471 while (buf = strbuf, 472 nbytes = kernfs_xread(kt, total, &buf, sizeof(strbuf))) 473 total += nbytes; 474 vap->va_size = total; 475 } 476 477 #ifdef KERNFS_DIAGNOSTIC 478 printf("kernfs_getattr: return error %d\n", error); 479 #endif 480 return (error); 481 } 482 483 /*ARGSUSED*/ 484 int 485 kernfs_setattr(v) 486 void *v; 487 { 488 /* 489 * Silently ignore attribute changes. 490 * This allows for open with truncate to have no 491 * effect until some data is written. I want to 492 * do it this way because all writes are atomic. 493 */ 494 return (0); 495 } 496 497 int 498 kernfs_read(v) 499 void *v; 500 { 501 struct vop_read_args /* { 502 struct vnode *a_vp; 503 struct uio *a_uio; 504 int a_ioflag; 505 struct ucred *a_cred; 506 } */ *ap = v; 507 struct vnode *vp = ap->a_vp; 508 struct uio *uio = ap->a_uio; 509 struct kern_target *kt; 510 char strbuf[KSTRING], *buf; 511 int off, len; 512 int error; 513 514 if (vp->v_type == VDIR) 515 return (EOPNOTSUPP); 516 517 kt = VTOKERN(vp)->kf_kt; 518 519 #ifdef KERNFS_DIAGNOSTIC 520 printf("kern_read %s\n", kt->kt_name); 521 #endif 522 523 off = uio->uio_offset; 524 #if 0 525 while (buf = strbuf, 526 #else 527 if (buf = strbuf, 528 #endif 529 len = kernfs_xread(kt, off, &buf, sizeof(strbuf))) { 530 if ((error = uiomove(buf, len, uio)) != 0) 531 return (error); 532 off += len; 533 } 534 return (0); 535 } 536 537 int 538 kernfs_write(v) 539 void *v; 540 { 541 struct vop_write_args /* { 542 struct vnode *a_vp; 543 struct uio *a_uio; 544 int a_ioflag; 545 struct ucred *a_cred; 546 } */ *ap = v; 547 struct vnode *vp = ap->a_vp; 548 struct uio *uio = ap->a_uio; 549 struct kern_target *kt; 550 int error, xlen; 551 char strbuf[KSTRING]; 552 553 if (vp->v_type == VDIR) 554 return (EOPNOTSUPP); 555 556 kt = VTOKERN(vp)->kf_kt; 557 558 if (uio->uio_offset != 0) 559 return (EINVAL); 560 561 xlen = min(uio->uio_resid, KSTRING-1); 562 if ((error = uiomove(strbuf, xlen, uio)) != 0) 563 return (error); 564 565 if (uio->uio_resid != 0) 566 return (EIO); 567 568 strbuf[xlen] = '\0'; 569 xlen = strlen(strbuf); 570 return (kernfs_xwrite(kt, strbuf, xlen)); 571 } 572 573 int 574 kernfs_readdir(v) 575 void *v; 576 { 577 struct vop_readdir_args /* { 578 struct vnode *a_vp; 579 struct uio *a_uio; 580 struct ucred *a_cred; 581 int *a_eofflag; 582 off_t *a_cookies; 583 int a_ncookies; 584 } */ *ap = v; 585 struct uio *uio = ap->a_uio; 586 struct dirent d; 587 struct kern_target *kt; 588 int i; 589 int error; 590 off_t *cookies = ap->a_cookies; 591 int ncookies = ap->a_ncookies; 592 593 if (ap->a_vp->v_type != VDIR) 594 return (ENOTDIR); 595 596 if (uio->uio_resid < UIO_MX) 597 return (EINVAL); 598 if (uio->uio_offset < 0) 599 return (EINVAL); 600 601 error = 0; 602 i = uio->uio_offset; 603 bzero((caddr_t)&d, UIO_MX); 604 d.d_reclen = UIO_MX; 605 606 for (kt = &kern_targets[i]; 607 uio->uio_resid >= UIO_MX && i < nkern_targets; kt++, i++) { 608 #ifdef KERNFS_DIAGNOSTIC 609 printf("kernfs_readdir: i = %d\n", i); 610 #endif 611 612 if (kt->kt_tag == KTT_DEVICE) { 613 dev_t *dp = kt->kt_data; 614 struct vnode *fvp; 615 616 if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) 617 continue; 618 } 619 620 d.d_fileno = i + 3; 621 d.d_namlen = kt->kt_namlen; 622 bcopy(kt->kt_name, d.d_name, kt->kt_namlen + 1); 623 d.d_type = kt->kt_type; 624 625 if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0) 626 break; 627 if (ncookies-- > 0) 628 *cookies++ = i + 1; 629 } 630 631 uio->uio_offset = i; 632 return (error); 633 } 634 635 int 636 kernfs_inactive(v) 637 void *v; 638 { 639 struct vop_inactive_args /* { 640 struct vnode *a_vp; 641 } */ *ap = v; 642 struct vnode *vp = ap->a_vp; 643 644 #ifdef KERNFS_DIAGNOSTIC 645 printf("kernfs_inactive(%p)\n", vp); 646 #endif 647 /* 648 * Clear out the v_type field to avoid 649 * nasty things happening in vgone(). 650 */ 651 vp->v_type = VNON; 652 return (0); 653 } 654 655 int 656 kernfs_reclaim(v) 657 void *v; 658 { 659 struct vop_reclaim_args /* { 660 struct vnode *a_vp; 661 } */ *ap = v; 662 struct vnode *vp = ap->a_vp; 663 664 #ifdef KERNFS_DIAGNOSTIC 665 printf("kernfs_reclaim(%p)\n", vp); 666 #endif 667 if (vp->v_data) { 668 FREE(vp->v_data, M_TEMP); 669 vp->v_data = 0; 670 } 671 return (0); 672 } 673 674 /* 675 * Return POSIX pathconf information applicable to special devices. 676 */ 677 int 678 kernfs_pathconf(v) 679 void *v; 680 { 681 struct vop_pathconf_args /* { 682 struct vnode *a_vp; 683 int a_name; 684 register_t *a_retval; 685 } */ *ap = v; 686 687 switch (ap->a_name) { 688 case _PC_LINK_MAX: 689 *ap->a_retval = LINK_MAX; 690 return (0); 691 case _PC_MAX_CANON: 692 *ap->a_retval = MAX_CANON; 693 return (0); 694 case _PC_MAX_INPUT: 695 *ap->a_retval = MAX_INPUT; 696 return (0); 697 case _PC_PIPE_BUF: 698 *ap->a_retval = PIPE_BUF; 699 return (0); 700 case _PC_CHOWN_RESTRICTED: 701 *ap->a_retval = 1; 702 return (0); 703 case _PC_VDISABLE: 704 *ap->a_retval = _POSIX_VDISABLE; 705 return (0); 706 default: 707 return (EINVAL); 708 } 709 /* NOTREACHED */ 710 } 711 712 /* 713 * Print out the contents of a /dev/fd vnode. 714 */ 715 /* ARGSUSED */ 716 int 717 kernfs_print(v) 718 void *v; 719 { 720 721 printf("tag VT_KERNFS, kernfs vnode\n"); 722 return (0); 723 } 724 725 int 726 kernfs_link(v) 727 void *v; 728 { 729 struct vop_link_args /* { 730 struct vnode *a_dvp; 731 struct vnode *a_vp; 732 struct componentname *a_cnp; 733 } */ *ap = v; 734 735 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 736 vput(ap->a_dvp); 737 return (EROFS); 738 } 739 740 int 741 kernfs_symlink(v) 742 void *v; 743 { 744 struct vop_symlink_args /* { 745 struct vnode *a_dvp; 746 struct vnode **a_vpp; 747 struct componentname *a_cnp; 748 struct vattr *a_vap; 749 char *a_target; 750 } */ *ap = v; 751 752 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 753 vput(ap->a_dvp); 754 return (EROFS); 755 } 756