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