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