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