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