1 /* $NetBSD: kernfs_vnops.c,v 1.83 2002/08/03 04:52:44 simonb 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.83 2002/08/03 04:52:44 simonb 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 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 buf = strbuf; 511 if (0 == (error = kernfs_xread(kt, 0, &buf, 512 sizeof(strbuf), &total))) 513 vap->va_size = total; 514 } 515 516 #ifdef KERNFS_DIAGNOSTIC 517 printf("kernfs_getattr: return error %d\n", error); 518 #endif 519 return (error); 520 } 521 522 /*ARGSUSED*/ 523 int 524 kernfs_setattr(v) 525 void *v; 526 { 527 /* 528 * Silently ignore attribute changes. 529 * This allows for open with truncate to have no 530 * effect until some data is written. I want to 531 * do it this way because all writes are atomic. 532 */ 533 return (0); 534 } 535 536 int 537 kernfs_read(v) 538 void *v; 539 { 540 struct vop_read_args /* { 541 struct vnode *a_vp; 542 struct uio *a_uio; 543 int a_ioflag; 544 struct ucred *a_cred; 545 } */ *ap = v; 546 struct vnode *vp = ap->a_vp; 547 struct uio *uio = ap->a_uio; 548 const struct kern_target *kt; 549 char strbuf[KSTRING], *buf; 550 off_t off; 551 size_t len; 552 int error; 553 554 if (vp->v_type == VDIR) 555 return (EOPNOTSUPP); 556 557 kt = VTOKERN(vp)->kf_kt; 558 559 #ifdef KERNFS_DIAGNOSTIC 560 printf("kern_read %s\n", kt->kt_name); 561 #endif 562 563 off = uio->uio_offset; 564 buf = strbuf; 565 if ((error = kernfs_xread(kt, off, &buf, sizeof(strbuf), &len)) == 0) 566 error = uiomove(buf, len, uio); 567 return (error); 568 } 569 570 int 571 kernfs_write(v) 572 void *v; 573 { 574 struct vop_write_args /* { 575 struct vnode *a_vp; 576 struct uio *a_uio; 577 int a_ioflag; 578 struct ucred *a_cred; 579 } */ *ap = v; 580 struct vnode *vp = ap->a_vp; 581 struct uio *uio = ap->a_uio; 582 const struct kern_target *kt; 583 int error, xlen; 584 char strbuf[KSTRING]; 585 586 if (vp->v_type == VDIR) 587 return (EOPNOTSUPP); 588 589 kt = VTOKERN(vp)->kf_kt; 590 591 if (uio->uio_offset != 0) 592 return (EINVAL); 593 594 xlen = min(uio->uio_resid, KSTRING-1); 595 if ((error = uiomove(strbuf, xlen, uio)) != 0) 596 return (error); 597 598 if (uio->uio_resid != 0) 599 return (EIO); 600 601 strbuf[xlen] = '\0'; 602 xlen = strlen(strbuf); 603 return (kernfs_xwrite(kt, strbuf, xlen)); 604 } 605 606 int 607 kernfs_readdir(v) 608 void *v; 609 { 610 struct vop_readdir_args /* { 611 struct vnode *a_vp; 612 struct uio *a_uio; 613 struct ucred *a_cred; 614 int *a_eofflag; 615 off_t **a_cookies; 616 int a_*ncookies; 617 } */ *ap = v; 618 struct uio *uio = ap->a_uio; 619 struct dirent d; 620 const struct kern_target *kt; 621 off_t i; 622 int error; 623 off_t *cookies = NULL; 624 int ncookies = 0, nc = 0; 625 626 if (ap->a_vp->v_type != VDIR) 627 return (ENOTDIR); 628 629 if (uio->uio_resid < UIO_MX) 630 return (EINVAL); 631 if (uio->uio_offset < 0) 632 return (EINVAL); 633 634 error = 0; 635 i = uio->uio_offset; 636 637 if (i >= nkern_targets) 638 return 0; 639 640 memset((caddr_t)&d, 0, UIO_MX); 641 d.d_reclen = UIO_MX; 642 643 if (ap->a_ncookies) { 644 nc = uio->uio_resid / UIO_MX; 645 nc = min(nc, (nkern_targets - i)); 646 cookies = malloc(nc * sizeof(off_t), M_TEMP, M_WAITOK); 647 *ap->a_cookies = cookies; 648 } 649 650 for (kt = &kern_targets[i]; 651 uio->uio_resid >= UIO_MX && i < nkern_targets; kt++, i++) { 652 #ifdef KERNFS_DIAGNOSTIC 653 printf("kernfs_readdir: i = %d\n", (int)i); 654 #endif 655 656 if (kt->kt_tag == KTT_DEVICE) { 657 dev_t *dp = kt->kt_data; 658 struct vnode *fvp; 659 660 if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) 661 continue; 662 } 663 664 d.d_fileno = i + 3; 665 d.d_namlen = kt->kt_namlen; 666 memcpy(d.d_name, kt->kt_name, kt->kt_namlen + 1); 667 d.d_type = kt->kt_type; 668 669 if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0) 670 break; 671 if (cookies) { 672 *cookies++ = i + 1; 673 ncookies++; 674 } 675 } 676 677 if (ap->a_ncookies) { 678 if (error) { 679 free(*ap->a_cookies, M_TEMP); 680 *ap->a_ncookies = 0; 681 *ap->a_cookies = NULL; 682 } else 683 *ap->a_ncookies = ncookies; 684 } 685 686 uio->uio_offset = i; 687 return (error); 688 } 689 690 int 691 kernfs_inactive(v) 692 void *v; 693 { 694 struct vop_inactive_args /* { 695 struct vnode *a_vp; 696 struct proc *a_p; 697 } */ *ap = v; 698 struct vnode *vp = ap->a_vp; 699 700 #ifdef KERNFS_DIAGNOSTIC 701 printf("kernfs_inactive(%p)\n", vp); 702 #endif 703 /* 704 * Clear out the v_type field to avoid 705 * nasty things happening in vgone(). 706 */ 707 VOP_UNLOCK(vp, 0); 708 vp->v_type = VNON; 709 return (0); 710 } 711 712 int 713 kernfs_reclaim(v) 714 void *v; 715 { 716 struct vop_reclaim_args /* { 717 struct vnode *a_vp; 718 } */ *ap = v; 719 struct vnode *vp = ap->a_vp; 720 721 #ifdef KERNFS_DIAGNOSTIC 722 printf("kernfs_reclaim(%p)\n", vp); 723 #endif 724 if (vp->v_data) { 725 FREE(vp->v_data, M_TEMP); 726 vp->v_data = 0; 727 } 728 return (0); 729 } 730 731 /* 732 * Return POSIX pathconf information applicable to special devices. 733 */ 734 int 735 kernfs_pathconf(v) 736 void *v; 737 { 738 struct vop_pathconf_args /* { 739 struct vnode *a_vp; 740 int a_name; 741 register_t *a_retval; 742 } */ *ap = v; 743 744 switch (ap->a_name) { 745 case _PC_LINK_MAX: 746 *ap->a_retval = LINK_MAX; 747 return (0); 748 case _PC_MAX_CANON: 749 *ap->a_retval = MAX_CANON; 750 return (0); 751 case _PC_MAX_INPUT: 752 *ap->a_retval = MAX_INPUT; 753 return (0); 754 case _PC_PIPE_BUF: 755 *ap->a_retval = PIPE_BUF; 756 return (0); 757 case _PC_CHOWN_RESTRICTED: 758 *ap->a_retval = 1; 759 return (0); 760 case _PC_VDISABLE: 761 *ap->a_retval = _POSIX_VDISABLE; 762 return (0); 763 case _PC_SYNC_IO: 764 *ap->a_retval = 1; 765 return (0); 766 default: 767 return (EINVAL); 768 } 769 /* NOTREACHED */ 770 } 771 772 /* 773 * Print out the contents of a /dev/fd vnode. 774 */ 775 /* ARGSUSED */ 776 int 777 kernfs_print(v) 778 void *v; 779 { 780 781 printf("tag VT_KERNFS, kernfs vnode\n"); 782 return (0); 783 } 784 785 int 786 kernfs_link(v) 787 void *v; 788 { 789 struct vop_link_args /* { 790 struct vnode *a_dvp; 791 struct vnode *a_vp; 792 struct componentname *a_cnp; 793 } */ *ap = v; 794 795 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 796 vput(ap->a_dvp); 797 return (EROFS); 798 } 799 800 int 801 kernfs_symlink(v) 802 void *v; 803 { 804 struct vop_symlink_args /* { 805 struct vnode *a_dvp; 806 struct vnode **a_vpp; 807 struct componentname *a_cnp; 808 struct vattr *a_vap; 809 char *a_target; 810 } */ *ap = v; 811 812 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 813 vput(ap->a_dvp); 814 return (EROFS); 815 } 816