1 /* $NetBSD: kernfs_vnops.c,v 1.68 2000/06/28 02:44:06 mrg 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.15 (Berkeley) 5/21/95 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 #include <uvm/uvm_extern.h> 66 67 #define KSTRING 256 /* Largest I/O available via this filesystem */ 68 #define UIO_MX 32 69 70 #define READ_MODE (S_IRUSR|S_IRGRP|S_IROTH) 71 #define WRITE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) 72 #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 73 74 struct kern_target kern_targets[] = { 75 /* NOTE: The name must be less than UIO_MX-16 chars in length */ 76 #define N(s) sizeof(s)-1, s 77 /* name data tag type ro/rw */ 78 { DT_DIR, N("."), 0, KTT_NULL, VDIR, DIR_MODE }, 79 { DT_DIR, N(".."), 0, KTT_NULL, VDIR, DIR_MODE }, 80 { DT_REG, N("boottime"), &boottime.tv_sec, KTT_INT, VREG, READ_MODE }, 81 { DT_REG, N("copyright"), copyright, KTT_STRING, VREG, READ_MODE }, 82 { DT_REG, N("hostname"), 0, KTT_HOSTNAME, VREG, WRITE_MODE }, 83 { DT_REG, N("hz"), &hz, KTT_INT, VREG, READ_MODE }, 84 { DT_REG, N("loadavg"), 0, KTT_AVENRUN, VREG, READ_MODE }, 85 { DT_REG, N("msgbuf"), 0, KTT_MSGBUF, VREG, READ_MODE }, 86 { DT_REG, N("pagesize"), &uvmexp.pagesize, KTT_INT, VREG, READ_MODE }, 87 { DT_REG, N("physmem"), &physmem, KTT_INT, VREG, READ_MODE }, 88 #if 0 89 { DT_DIR, N("root"), 0, KTT_NULL, VDIR, DIR_MODE }, 90 #endif 91 { DT_BLK, N("rootdev"), &rootdev, KTT_DEVICE, VBLK, READ_MODE }, 92 { DT_CHR, N("rrootdev"), &rrootdev, KTT_DEVICE, VCHR, READ_MODE }, 93 { DT_REG, N("time"), 0, KTT_TIME, VREG, READ_MODE }, 94 { DT_REG, N("version"), version, KTT_STRING, VREG, READ_MODE }, 95 #undef N 96 }; 97 static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]); 98 99 int kernfs_lookup __P((void *)); 100 #define kernfs_create genfs_eopnotsupp_rele 101 #define kernfs_mknod genfs_eopnotsupp_rele 102 #define kernfs_open genfs_nullop 103 #define kernfs_close genfs_nullop 104 int kernfs_access __P((void *)); 105 int kernfs_getattr __P((void *)); 106 int kernfs_setattr __P((void *)); 107 int kernfs_read __P((void *)); 108 int kernfs_write __P((void *)); 109 #define kernfs_fcntl genfs_fcntl 110 #define kernfs_ioctl genfs_enoioctl 111 #define kernfs_poll genfs_poll 112 #define kernfs_revoke genfs_revoke 113 #define kernfs_mmap genfs_eopnotsupp 114 #define kernfs_fsync genfs_nullop 115 #define kernfs_seek genfs_nullop 116 #define kernfs_remove genfs_eopnotsupp_rele 117 int kernfs_link __P((void *)); 118 #define kernfs_rename genfs_eopnotsupp_rele 119 #define kernfs_mkdir genfs_eopnotsupp_rele 120 #define kernfs_rmdir genfs_eopnotsupp_rele 121 int kernfs_symlink __P((void *)); 122 int kernfs_readdir __P((void *)); 123 #define kernfs_readlink genfs_eopnotsupp 124 #define kernfs_abortop genfs_abortop 125 int kernfs_inactive __P((void *)); 126 int kernfs_reclaim __P((void *)); 127 #define kernfs_lock genfs_lock 128 #define kernfs_unlock genfs_unlock 129 #define kernfs_bmap genfs_badop 130 #define kernfs_strategy genfs_badop 131 int kernfs_print __P((void *)); 132 #define kernfs_islocked genfs_islocked 133 int kernfs_pathconf __P((void *)); 134 #define kernfs_advlock genfs_einval 135 #define kernfs_blkatoff genfs_eopnotsupp 136 #define kernfs_valloc genfs_eopnotsupp 137 #define kernfs_vfree genfs_nullop 138 #define kernfs_truncate genfs_eopnotsupp 139 #define kernfs_update genfs_nullop 140 #define kernfs_bwrite genfs_eopnotsupp 141 142 int kernfs_xread __P((struct kern_target *, int, char **, int)); 143 int kernfs_xwrite __P((struct kern_target *, char *, int)); 144 145 int (**kernfs_vnodeop_p) __P((void *)); 146 struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = { 147 { &vop_default_desc, vn_default_error }, 148 { &vop_lookup_desc, kernfs_lookup }, /* lookup */ 149 { &vop_create_desc, kernfs_create }, /* create */ 150 { &vop_mknod_desc, kernfs_mknod }, /* mknod */ 151 { &vop_open_desc, kernfs_open }, /* open */ 152 { &vop_close_desc, kernfs_close }, /* close */ 153 { &vop_access_desc, kernfs_access }, /* access */ 154 { &vop_getattr_desc, kernfs_getattr }, /* getattr */ 155 { &vop_setattr_desc, kernfs_setattr }, /* setattr */ 156 { &vop_read_desc, kernfs_read }, /* read */ 157 { &vop_write_desc, kernfs_write }, /* write */ 158 { &vop_fcntl_desc, kernfs_fcntl }, /* fcntl */ 159 { &vop_ioctl_desc, kernfs_ioctl }, /* ioctl */ 160 { &vop_poll_desc, kernfs_poll }, /* poll */ 161 { &vop_revoke_desc, kernfs_revoke }, /* revoke */ 162 { &vop_mmap_desc, kernfs_mmap }, /* mmap */ 163 { &vop_fsync_desc, kernfs_fsync }, /* fsync */ 164 { &vop_seek_desc, kernfs_seek }, /* seek */ 165 { &vop_remove_desc, kernfs_remove }, /* remove */ 166 { &vop_link_desc, kernfs_link }, /* link */ 167 { &vop_rename_desc, kernfs_rename }, /* rename */ 168 { &vop_mkdir_desc, kernfs_mkdir }, /* mkdir */ 169 { &vop_rmdir_desc, kernfs_rmdir }, /* rmdir */ 170 { &vop_symlink_desc, kernfs_symlink }, /* symlink */ 171 { &vop_readdir_desc, kernfs_readdir }, /* readdir */ 172 { &vop_readlink_desc, kernfs_readlink }, /* readlink */ 173 { &vop_abortop_desc, kernfs_abortop }, /* abortop */ 174 { &vop_inactive_desc, kernfs_inactive }, /* inactive */ 175 { &vop_reclaim_desc, kernfs_reclaim }, /* reclaim */ 176 { &vop_lock_desc, kernfs_lock }, /* lock */ 177 { &vop_unlock_desc, kernfs_unlock }, /* unlock */ 178 { &vop_bmap_desc, kernfs_bmap }, /* bmap */ 179 { &vop_strategy_desc, kernfs_strategy }, /* strategy */ 180 { &vop_print_desc, kernfs_print }, /* print */ 181 { &vop_islocked_desc, kernfs_islocked }, /* islocked */ 182 { &vop_pathconf_desc, kernfs_pathconf }, /* pathconf */ 183 { &vop_advlock_desc, kernfs_advlock }, /* advlock */ 184 { &vop_blkatoff_desc, kernfs_blkatoff }, /* blkatoff */ 185 { &vop_valloc_desc, kernfs_valloc }, /* valloc */ 186 { &vop_vfree_desc, kernfs_vfree }, /* vfree */ 187 { &vop_truncate_desc, kernfs_truncate }, /* truncate */ 188 { &vop_update_desc, kernfs_update }, /* update */ 189 { &vop_bwrite_desc, kernfs_bwrite }, /* bwrite */ 190 { (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL } 191 }; 192 struct vnodeopv_desc kernfs_vnodeop_opv_desc = 193 { &kernfs_vnodeop_p, kernfs_vnodeop_entries }; 194 195 int 196 kernfs_xread(kt, off, bufp, len) 197 struct kern_target *kt; 198 int off; 199 char **bufp; 200 int len; 201 { 202 203 switch (kt->kt_tag) { 204 case KTT_TIME: { 205 struct timeval tv; 206 207 microtime(&tv); 208 sprintf(*bufp, "%ld %ld\n", tv.tv_sec, tv.tv_usec); 209 break; 210 } 211 212 case KTT_INT: { 213 int *ip = kt->kt_data; 214 215 sprintf(*bufp, "%d\n", *ip); 216 break; 217 } 218 219 case KTT_STRING: { 220 char *cp = kt->kt_data; 221 222 *bufp = cp; 223 break; 224 } 225 226 case KTT_MSGBUF: { 227 long n; 228 229 /* 230 * deal with cases where the message buffer has 231 * become corrupted. 232 */ 233 if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) { 234 msgbufenabled = 0; 235 return (ENXIO); 236 } 237 238 /* 239 * Note that reads of /kern/msgbuf won't necessarily yield 240 * consistent results, if the message buffer is modified 241 * while the read is in progress. The worst that can happen 242 * is that incorrect data will be read. There's no way 243 * that this can crash the system unless the values in the 244 * message buffer header are corrupted, but that'll cause 245 * the system to die anyway. 246 */ 247 if (off >= msgbufp->msg_bufs) 248 return (0); 249 n = msgbufp->msg_bufx + off; 250 if (n >= msgbufp->msg_bufs) 251 n -= msgbufp->msg_bufs; 252 len = min(msgbufp->msg_bufs - n, msgbufp->msg_bufs - off); 253 *bufp = msgbufp->msg_bufc + n; 254 return (len); 255 } 256 257 case KTT_HOSTNAME: { 258 char *cp = hostname; 259 int xlen = hostnamelen; 260 261 if (xlen >= (len-2)) 262 return (EINVAL); 263 264 memcpy(*bufp, cp, xlen); 265 (*bufp)[xlen] = '\n'; 266 (*bufp)[xlen+1] = '\0'; 267 break; 268 } 269 270 case KTT_AVENRUN: 271 averunnable.fscale = FSCALE; 272 sprintf(*bufp, "%d %d %d %ld\n", 273 averunnable.ldavg[0], averunnable.ldavg[1], 274 averunnable.ldavg[2], averunnable.fscale); 275 break; 276 277 default: 278 return (0); 279 } 280 281 len = strlen(*bufp); 282 if (len <= off) 283 return (0); 284 *bufp += off; 285 return (len - off); 286 } 287 288 int 289 kernfs_xwrite(kt, buf, len) 290 struct kern_target *kt; 291 char *buf; 292 int len; 293 { 294 295 switch (kt->kt_tag) { 296 case KTT_HOSTNAME: 297 if (buf[len-1] == '\n') 298 --len; 299 memcpy(hostname, buf, len); 300 hostname[len] = '\0'; 301 hostnamelen = len; 302 return (0); 303 304 default: 305 return (EIO); 306 } 307 } 308 309 310 /* 311 * vp is the current namei directory 312 * ndp is the name to locate in that directory... 313 */ 314 int 315 kernfs_lookup(v) 316 void *v; 317 { 318 struct vop_lookup_args /* { 319 struct vnode * a_dvp; 320 struct vnode ** a_vpp; 321 struct componentname * a_cnp; 322 } */ *ap = v; 323 struct componentname *cnp = ap->a_cnp; 324 struct vnode **vpp = ap->a_vpp; 325 struct vnode *dvp = ap->a_dvp; 326 const char *pname = cnp->cn_nameptr; 327 struct kern_target *kt; 328 struct vnode *fvp; 329 int error, i, wantpunlock; 330 331 #ifdef KERNFS_DIAGNOSTIC 332 printf("kernfs_lookup(%p)\n", ap); 333 printf("kernfs_lookup(dp = %p, vpp = %p, cnp = %p)\n", dvp, vpp, ap->a_cnp); 334 printf("kernfs_lookup(%s)\n", pname); 335 #endif 336 337 *vpp = NULLVP; 338 cnp->cn_flags &= ~PDIRUNLOCK; 339 340 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) 341 return (EROFS); 342 343 if (cnp->cn_namelen == 1 && *pname == '.') { 344 *vpp = dvp; 345 VREF(dvp); 346 return (0); 347 } 348 349 /* 350 * This code only supports a flat directory, so we don't 351 * need to worry about .. 352 */ 353 354 #if 0 355 if (cnp->cn_namelen == 4 && memcmp(pname, "root", 4) == 0) { 356 *vpp = rootdir; 357 VREF(rootdir); 358 vn_lock(rootdir, LK_SHARED | LK_RETRY); 359 return (0); 360 } 361 #endif 362 363 wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN)); 364 365 for (kt = kern_targets, i = 0; i < nkern_targets; kt++, i++) { 366 if (cnp->cn_namelen == kt->kt_namlen && 367 memcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) 368 goto found; 369 } 370 371 #ifdef KERNFS_DIAGNOSTIC 372 printf("kernfs_lookup: i = %d, failed", i); 373 #endif 374 375 return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); 376 377 found: 378 if (kt->kt_tag == KTT_DEVICE) { 379 dev_t *dp = kt->kt_data; 380 loop: 381 if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) { 382 return (ENOENT); 383 } 384 *vpp = fvp; 385 if (vget(fvp, LK_EXCLUSIVE)) 386 goto loop; 387 if (wantpunlock) { 388 VOP_UNLOCK(dvp, 0); 389 cnp->cn_flags |= PDIRUNLOCK; 390 } 391 return (0); 392 } 393 394 #ifdef KERNFS_DIAGNOSTIC 395 printf("kernfs_lookup: allocate new vnode\n"); 396 #endif 397 error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p, &fvp); 398 if (error) { 399 return (error); 400 } 401 402 MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, 403 M_WAITOK); 404 VTOKERN(fvp)->kf_kt = kt; 405 fvp->v_type = kt->kt_vtype; 406 vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY); 407 *vpp = fvp; 408 409 #ifdef KERNFS_DIAGNOSTIC 410 printf("kernfs_lookup: newvp = %p\n", fvp); 411 #endif 412 if (wantpunlock) { 413 VOP_UNLOCK(dvp, 0); 414 cnp->cn_flags |= PDIRUNLOCK; 415 } 416 return (0); 417 } 418 419 int 420 kernfs_access(v) 421 void *v; 422 { 423 struct vop_access_args /* { 424 struct vnode *a_vp; 425 int a_mode; 426 struct ucred *a_cred; 427 struct proc *a_p; 428 } */ *ap = v; 429 struct vnode *vp = ap->a_vp; 430 mode_t mode; 431 432 if (vp->v_flag & VROOT) { 433 mode = DIR_MODE; 434 } else { 435 struct kern_target *kt = VTOKERN(vp)->kf_kt; 436 mode = kt->kt_mode; 437 } 438 439 return (vaccess(vp->v_type, mode, (uid_t)0, (gid_t)0, ap->a_mode, 440 ap->a_cred)); 441 } 442 443 int 444 kernfs_getattr(v) 445 void *v; 446 { 447 struct vop_getattr_args /* { 448 struct vnode *a_vp; 449 struct vattr *a_vap; 450 struct ucred *a_cred; 451 struct proc *a_p; 452 } */ *ap = v; 453 struct vnode *vp = ap->a_vp; 454 struct vattr *vap = ap->a_vap; 455 struct timeval tv; 456 int error = 0; 457 char strbuf[KSTRING], *buf; 458 459 memset((caddr_t) vap, 0, sizeof(*vap)); 460 vattr_null(vap); 461 vap->va_uid = 0; 462 vap->va_gid = 0; 463 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 464 vap->va_size = 0; 465 vap->va_blocksize = DEV_BSIZE; 466 microtime(&tv); 467 TIMEVAL_TO_TIMESPEC(&tv, &vap->va_atime); 468 vap->va_mtime = vap->va_atime; 469 vap->va_ctime = vap->va_ctime; 470 vap->va_gen = 0; 471 vap->va_flags = 0; 472 vap->va_rdev = 0; 473 vap->va_bytes = 0; 474 475 if (vp->v_flag & VROOT) { 476 #ifdef KERNFS_DIAGNOSTIC 477 printf("kernfs_getattr: stat rootdir\n"); 478 #endif 479 vap->va_type = VDIR; 480 vap->va_mode = DIR_MODE; 481 vap->va_nlink = 2; 482 vap->va_fileid = 2; 483 vap->va_size = DEV_BSIZE; 484 } else { 485 struct kern_target *kt = VTOKERN(vp)->kf_kt; 486 int nbytes, total; 487 #ifdef KERNFS_DIAGNOSTIC 488 printf("kernfs_getattr: stat target %s\n", kt->kt_name); 489 #endif 490 vap->va_type = kt->kt_vtype; 491 vap->va_mode = kt->kt_mode; 492 vap->va_nlink = 1; 493 vap->va_fileid = 1 + (kt - kern_targets); 494 total = 0; 495 while (buf = strbuf, 496 nbytes = kernfs_xread(kt, total, &buf, sizeof(strbuf))) 497 total += nbytes; 498 vap->va_size = total; 499 } 500 501 #ifdef KERNFS_DIAGNOSTIC 502 printf("kernfs_getattr: return error %d\n", error); 503 #endif 504 return (error); 505 } 506 507 /*ARGSUSED*/ 508 int 509 kernfs_setattr(v) 510 void *v; 511 { 512 /* 513 * Silently ignore attribute changes. 514 * This allows for open with truncate to have no 515 * effect until some data is written. I want to 516 * do it this way because all writes are atomic. 517 */ 518 return (0); 519 } 520 521 int 522 kernfs_read(v) 523 void *v; 524 { 525 struct vop_read_args /* { 526 struct vnode *a_vp; 527 struct uio *a_uio; 528 int a_ioflag; 529 struct ucred *a_cred; 530 } */ *ap = v; 531 struct vnode *vp = ap->a_vp; 532 struct uio *uio = ap->a_uio; 533 struct kern_target *kt; 534 char strbuf[KSTRING], *buf; 535 int off, len; 536 int error; 537 538 if (vp->v_type == VDIR) 539 return (EOPNOTSUPP); 540 541 kt = VTOKERN(vp)->kf_kt; 542 543 #ifdef KERNFS_DIAGNOSTIC 544 printf("kern_read %s\n", kt->kt_name); 545 #endif 546 547 off = uio->uio_offset; 548 #if 0 549 while (buf = strbuf, 550 #else 551 if (buf = strbuf, 552 #endif 553 len = kernfs_xread(kt, off, &buf, sizeof(strbuf))) { 554 if ((error = uiomove(buf, len, uio)) != 0) 555 return (error); 556 off += len; 557 } 558 return (0); 559 } 560 561 int 562 kernfs_write(v) 563 void *v; 564 { 565 struct vop_write_args /* { 566 struct vnode *a_vp; 567 struct uio *a_uio; 568 int a_ioflag; 569 struct ucred *a_cred; 570 } */ *ap = v; 571 struct vnode *vp = ap->a_vp; 572 struct uio *uio = ap->a_uio; 573 struct kern_target *kt; 574 int error, xlen; 575 char strbuf[KSTRING]; 576 577 if (vp->v_type == VDIR) 578 return (EOPNOTSUPP); 579 580 kt = VTOKERN(vp)->kf_kt; 581 582 if (uio->uio_offset != 0) 583 return (EINVAL); 584 585 xlen = min(uio->uio_resid, KSTRING-1); 586 if ((error = uiomove(strbuf, xlen, uio)) != 0) 587 return (error); 588 589 if (uio->uio_resid != 0) 590 return (EIO); 591 592 strbuf[xlen] = '\0'; 593 xlen = strlen(strbuf); 594 return (kernfs_xwrite(kt, strbuf, xlen)); 595 } 596 597 int 598 kernfs_readdir(v) 599 void *v; 600 { 601 struct vop_readdir_args /* { 602 struct vnode *a_vp; 603 struct uio *a_uio; 604 struct ucred *a_cred; 605 int *a_eofflag; 606 off_t **a_cookies; 607 int a_*ncookies; 608 } */ *ap = v; 609 struct uio *uio = ap->a_uio; 610 struct dirent d; 611 struct kern_target *kt; 612 off_t i; 613 int error; 614 off_t *cookies = NULL; 615 int ncookies = 0, nc = 0; 616 617 if (ap->a_vp->v_type != VDIR) 618 return (ENOTDIR); 619 620 if (uio->uio_resid < UIO_MX) 621 return (EINVAL); 622 if (uio->uio_offset < 0) 623 return (EINVAL); 624 625 error = 0; 626 i = uio->uio_offset; 627 628 if (i >= nkern_targets) 629 return 0; 630 631 memset((caddr_t)&d, 0, UIO_MX); 632 d.d_reclen = UIO_MX; 633 634 if (ap->a_ncookies) { 635 nc = uio->uio_resid / UIO_MX; 636 nc = min(nc, (nkern_targets - i)); 637 MALLOC(cookies, off_t *, nc * sizeof(off_t), M_TEMP, 638 M_WAITOK); 639 *ap->a_cookies = cookies; 640 } 641 642 for (kt = &kern_targets[i]; 643 uio->uio_resid >= UIO_MX && i < nkern_targets; kt++, i++) { 644 #ifdef KERNFS_DIAGNOSTIC 645 printf("kernfs_readdir: i = %d\n", i); 646 #endif 647 648 if (kt->kt_tag == KTT_DEVICE) { 649 dev_t *dp = kt->kt_data; 650 struct vnode *fvp; 651 652 if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) 653 continue; 654 } 655 656 d.d_fileno = i + 3; 657 d.d_namlen = kt->kt_namlen; 658 memcpy(d.d_name, kt->kt_name, kt->kt_namlen + 1); 659 d.d_type = kt->kt_type; 660 661 if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0) 662 break; 663 if (cookies) { 664 *cookies++ = i + 1; 665 ncookies++; 666 } 667 } 668 669 if (ap->a_ncookies) { 670 if (error) { 671 FREE(*ap->a_cookies, M_TEMP); 672 *ap->a_ncookies = 0; 673 *ap->a_cookies = NULL; 674 } else 675 *ap->a_ncookies = ncookies; 676 } 677 678 uio->uio_offset = i; 679 return (error); 680 } 681 682 int 683 kernfs_inactive(v) 684 void *v; 685 { 686 struct vop_inactive_args /* { 687 struct vnode *a_vp; 688 struct proc *a_p; 689 } */ *ap = v; 690 struct vnode *vp = ap->a_vp; 691 692 #ifdef KERNFS_DIAGNOSTIC 693 printf("kernfs_inactive(%p)\n", vp); 694 #endif 695 /* 696 * Clear out the v_type field to avoid 697 * nasty things happening in vgone(). 698 */ 699 VOP_UNLOCK(vp, 0); 700 vp->v_type = VNON; 701 return (0); 702 } 703 704 int 705 kernfs_reclaim(v) 706 void *v; 707 { 708 struct vop_reclaim_args /* { 709 struct vnode *a_vp; 710 } */ *ap = v; 711 struct vnode *vp = ap->a_vp; 712 713 #ifdef KERNFS_DIAGNOSTIC 714 printf("kernfs_reclaim(%p)\n", vp); 715 #endif 716 if (vp->v_data) { 717 FREE(vp->v_data, M_TEMP); 718 vp->v_data = 0; 719 } 720 return (0); 721 } 722 723 /* 724 * Return POSIX pathconf information applicable to special devices. 725 */ 726 int 727 kernfs_pathconf(v) 728 void *v; 729 { 730 struct vop_pathconf_args /* { 731 struct vnode *a_vp; 732 int a_name; 733 register_t *a_retval; 734 } */ *ap = v; 735 736 switch (ap->a_name) { 737 case _PC_LINK_MAX: 738 *ap->a_retval = LINK_MAX; 739 return (0); 740 case _PC_MAX_CANON: 741 *ap->a_retval = MAX_CANON; 742 return (0); 743 case _PC_MAX_INPUT: 744 *ap->a_retval = MAX_INPUT; 745 return (0); 746 case _PC_PIPE_BUF: 747 *ap->a_retval = PIPE_BUF; 748 return (0); 749 case _PC_CHOWN_RESTRICTED: 750 *ap->a_retval = 1; 751 return (0); 752 case _PC_VDISABLE: 753 *ap->a_retval = _POSIX_VDISABLE; 754 return (0); 755 case _PC_SYNC_IO: 756 *ap->a_retval = 1; 757 return (0); 758 default: 759 return (EINVAL); 760 } 761 /* NOTREACHED */ 762 } 763 764 /* 765 * Print out the contents of a /dev/fd vnode. 766 */ 767 /* ARGSUSED */ 768 int 769 kernfs_print(v) 770 void *v; 771 { 772 773 printf("tag VT_KERNFS, kernfs vnode\n"); 774 return (0); 775 } 776 777 int 778 kernfs_link(v) 779 void *v; 780 { 781 struct vop_link_args /* { 782 struct vnode *a_dvp; 783 struct vnode *a_vp; 784 struct componentname *a_cnp; 785 } */ *ap = v; 786 787 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 788 vput(ap->a_dvp); 789 return (EROFS); 790 } 791 792 int 793 kernfs_symlink(v) 794 void *v; 795 { 796 struct vop_symlink_args /* { 797 struct vnode *a_dvp; 798 struct vnode **a_vpp; 799 struct componentname *a_cnp; 800 struct vattr *a_vap; 801 char *a_target; 802 } */ *ap = v; 803 804 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 805 vput(ap->a_dvp); 806 return (EROFS); 807 } 808