1 /* $NetBSD: kernfs_vnops.c,v 1.89 2003/08/07 16:32:37 agc 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. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95 35 */ 36 37 /* 38 * Kernel parameter filesystem (/kern) 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: kernfs_vnops.c,v 1.89 2003/08/07 16:32:37 agc Exp $"); 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/vmmeter.h> 48 #include <sys/time.h> 49 #include <sys/proc.h> 50 #include <sys/vnode.h> 51 #include <sys/malloc.h> 52 #include <sys/file.h> 53 #include <sys/stat.h> 54 #include <sys/mount.h> 55 #include <sys/namei.h> 56 #include <sys/buf.h> 57 #include <sys/dirent.h> 58 #include <sys/msgbuf.h> 59 60 #include <miscfs/genfs/genfs.h> 61 #include <miscfs/kernfs/kernfs.h> 62 63 #include <uvm/uvm_extern.h> 64 65 #define KSTRING 256 /* Largest I/O available via this filesystem */ 66 #define UIO_MX 32 67 68 #define READ_MODE (S_IRUSR|S_IRGRP|S_IROTH) 69 #define WRITE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) 70 #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 71 72 const struct kern_target kern_targets[] = { 73 /* NOTE: The name must be less than UIO_MX-16 chars in length */ 74 #define N(s) sizeof(s)-1, s 75 /* name data tag type ro/rw */ 76 { DT_DIR, N("."), 0, KTT_NULL, VDIR, DIR_MODE }, 77 { DT_DIR, N(".."), 0, KTT_NULL, VDIR, DIR_MODE }, 78 { DT_REG, N("boottime"), &boottime.tv_sec, KTT_INT, VREG, READ_MODE }, 79 /* XXX cast away const */ 80 { DT_REG, N("copyright"), (void *)copyright, 81 KTT_STRING, VREG, READ_MODE }, 82 { DT_REG, N("hostname"), 0, KTT_HOSTNAME, VREG, WRITE_MODE }, 83 { DT_REG, N("hz"), &hz, KTT_INT, VREG, READ_MODE }, 84 { DT_REG, N("loadavg"), 0, KTT_AVENRUN, VREG, READ_MODE }, 85 { DT_REG, N("msgbuf"), 0, KTT_MSGBUF, VREG, READ_MODE }, 86 { DT_REG, N("pagesize"), &uvmexp.pagesize, KTT_INT, VREG, READ_MODE }, 87 { DT_REG, N("physmem"), &physmem, KTT_INT, VREG, READ_MODE }, 88 #if 0 89 { DT_DIR, N("root"), 0, KTT_NULL, VDIR, DIR_MODE }, 90 #endif 91 { DT_BLK, N("rootdev"), &rootdev, KTT_DEVICE, VBLK, READ_MODE }, 92 { DT_CHR, N("rrootdev"), &rrootdev, KTT_DEVICE, VCHR, READ_MODE }, 93 { DT_REG, N("time"), 0, KTT_TIME, VREG, READ_MODE }, 94 /* XXX cast away const */ 95 { DT_REG, N("version"), (void *)version, 96 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 103 #define kernfs_mknod genfs_eopnotsupp 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_fsync genfs_nullop 116 #define kernfs_seek genfs_nullop 117 #define kernfs_remove genfs_eopnotsupp 118 int kernfs_link __P((void *)); 119 #define kernfs_rename genfs_eopnotsupp 120 #define kernfs_mkdir genfs_eopnotsupp 121 #define kernfs_rmdir genfs_eopnotsupp 122 int kernfs_symlink __P((void *)); 123 int kernfs_readdir __P((void *)); 124 #define kernfs_readlink genfs_eopnotsupp 125 #define kernfs_abortop genfs_abortop 126 int kernfs_inactive __P((void *)); 127 int kernfs_reclaim __P((void *)); 128 #define kernfs_lock genfs_lock 129 #define kernfs_unlock genfs_unlock 130 #define kernfs_bmap genfs_badop 131 #define kernfs_strategy genfs_badop 132 int kernfs_print __P((void *)); 133 #define kernfs_islocked genfs_islocked 134 int kernfs_pathconf __P((void *)); 135 #define kernfs_advlock genfs_einval 136 #define kernfs_blkatoff genfs_eopnotsupp 137 #define kernfs_valloc genfs_eopnotsupp 138 #define kernfs_vfree genfs_nullop 139 #define kernfs_truncate genfs_eopnotsupp 140 #define kernfs_update genfs_nullop 141 #define kernfs_bwrite genfs_eopnotsupp 142 #define kernfs_putpages genfs_putpages 143 144 static int kernfs_xread __P((const struct kern_target *, int, char **, size_t, size_t *)); 145 static int kernfs_xwrite __P((const struct kern_target *, char *, size_t)); 146 147 int (**kernfs_vnodeop_p) __P((void *)); 148 const 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_fsync_desc, kernfs_fsync }, /* fsync */ 165 { &vop_seek_desc, kernfs_seek }, /* seek */ 166 { &vop_remove_desc, kernfs_remove }, /* remove */ 167 { &vop_link_desc, kernfs_link }, /* link */ 168 { &vop_rename_desc, kernfs_rename }, /* rename */ 169 { &vop_mkdir_desc, kernfs_mkdir }, /* mkdir */ 170 { &vop_rmdir_desc, kernfs_rmdir }, /* rmdir */ 171 { &vop_symlink_desc, kernfs_symlink }, /* symlink */ 172 { &vop_readdir_desc, kernfs_readdir }, /* readdir */ 173 { &vop_readlink_desc, kernfs_readlink }, /* readlink */ 174 { &vop_abortop_desc, kernfs_abortop }, /* abortop */ 175 { &vop_inactive_desc, kernfs_inactive }, /* inactive */ 176 { &vop_reclaim_desc, kernfs_reclaim }, /* reclaim */ 177 { &vop_lock_desc, kernfs_lock }, /* lock */ 178 { &vop_unlock_desc, kernfs_unlock }, /* unlock */ 179 { &vop_bmap_desc, kernfs_bmap }, /* bmap */ 180 { &vop_strategy_desc, kernfs_strategy }, /* strategy */ 181 { &vop_print_desc, kernfs_print }, /* print */ 182 { &vop_islocked_desc, kernfs_islocked }, /* islocked */ 183 { &vop_pathconf_desc, kernfs_pathconf }, /* pathconf */ 184 { &vop_advlock_desc, kernfs_advlock }, /* advlock */ 185 { &vop_blkatoff_desc, kernfs_blkatoff }, /* blkatoff */ 186 { &vop_valloc_desc, kernfs_valloc }, /* valloc */ 187 { &vop_vfree_desc, kernfs_vfree }, /* vfree */ 188 { &vop_truncate_desc, kernfs_truncate }, /* truncate */ 189 { &vop_update_desc, kernfs_update }, /* update */ 190 { &vop_bwrite_desc, kernfs_bwrite }, /* bwrite */ 191 { &vop_putpages_desc, kernfs_putpages }, /* putpages */ 192 { NULL, NULL } 193 }; 194 const struct vnodeopv_desc kernfs_vnodeop_opv_desc = 195 { &kernfs_vnodeop_p, kernfs_vnodeop_entries }; 196 197 static int 198 kernfs_xread(kt, off, bufp, len, wrlen) 199 const struct kern_target *kt; 200 int off; 201 char **bufp; 202 size_t len; 203 size_t *wrlen; 204 { 205 206 switch (kt->kt_tag) { 207 case KTT_TIME: { 208 struct timeval tv; 209 210 microtime(&tv); 211 sprintf(*bufp, "%ld %ld\n", tv.tv_sec, tv.tv_usec); 212 break; 213 } 214 215 case KTT_INT: { 216 int *ip = kt->kt_data; 217 218 sprintf(*bufp, "%d\n", *ip); 219 break; 220 } 221 222 case KTT_STRING: { 223 char *cp = kt->kt_data; 224 225 *bufp = cp; 226 break; 227 } 228 229 case KTT_MSGBUF: { 230 long n; 231 232 /* 233 * deal with cases where the message buffer has 234 * become corrupted. 235 */ 236 if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) { 237 msgbufenabled = 0; 238 return (ENXIO); 239 } 240 241 /* 242 * Note that reads of /kern/msgbuf won't necessarily yield 243 * consistent results, if the message buffer is modified 244 * while the read is in progress. The worst that can happen 245 * is that incorrect data will be read. There's no way 246 * that this can crash the system unless the values in the 247 * message buffer header are corrupted, but that'll cause 248 * the system to die anyway. 249 */ 250 if (off >= msgbufp->msg_bufs) { 251 *wrlen = 0; 252 return (0); 253 } 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 *wrlen = len; 260 return (0); 261 } 262 263 case KTT_HOSTNAME: { 264 char *cp = hostname; 265 int xlen = hostnamelen; 266 267 if (xlen >= (len-2)) 268 return (EINVAL); 269 270 memcpy(*bufp, cp, xlen); 271 (*bufp)[xlen] = '\n'; 272 (*bufp)[xlen+1] = '\0'; 273 break; 274 } 275 276 case KTT_AVENRUN: 277 averunnable.fscale = FSCALE; 278 sprintf(*bufp, "%d %d %d %ld\n", 279 averunnable.ldavg[0], averunnable.ldavg[1], 280 averunnable.ldavg[2], averunnable.fscale); 281 break; 282 283 default: 284 *wrlen = 0; 285 return (0); 286 } 287 288 len = strlen(*bufp); 289 if (len <= off) 290 *wrlen = 0; 291 else { 292 *bufp += off; 293 *wrlen = len - off; 294 } 295 return (0); 296 } 297 298 static int 299 kernfs_xwrite(kt, buf, len) 300 const struct kern_target *kt; 301 char *buf; 302 size_t len; 303 { 304 305 switch (kt->kt_tag) { 306 case KTT_HOSTNAME: 307 if (buf[len-1] == '\n') 308 --len; 309 memcpy(hostname, buf, len); 310 hostname[len] = '\0'; 311 hostnamelen = (size_t) len; 312 return (0); 313 314 default: 315 return (EIO); 316 } 317 } 318 319 320 /* 321 * vp is the current namei directory 322 * ndp is the name to locate in that directory... 323 */ 324 int 325 kernfs_lookup(v) 326 void *v; 327 { 328 struct vop_lookup_args /* { 329 struct vnode * a_dvp; 330 struct vnode ** a_vpp; 331 struct componentname * a_cnp; 332 } */ *ap = v; 333 struct componentname *cnp = ap->a_cnp; 334 struct vnode **vpp = ap->a_vpp; 335 struct vnode *dvp = ap->a_dvp; 336 const char *pname = cnp->cn_nameptr; 337 const struct kern_target *kt; 338 struct vnode *fvp; 339 int error, i, wantpunlock; 340 341 #ifdef KERNFS_DIAGNOSTIC 342 printf("kernfs_lookup(%p)\n", ap); 343 printf("kernfs_lookup(dp = %p, vpp = %p, cnp = %p)\n", dvp, vpp, ap->a_cnp); 344 printf("kernfs_lookup(%s)\n", pname); 345 #endif 346 347 *vpp = NULLVP; 348 cnp->cn_flags &= ~PDIRUNLOCK; 349 350 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) 351 return (EROFS); 352 353 if (cnp->cn_namelen == 1 && *pname == '.') { 354 *vpp = dvp; 355 VREF(dvp); 356 return (0); 357 } 358 359 /* 360 * This code only supports a flat directory, so we don't 361 * need to worry about .. 362 */ 363 364 #if 0 365 if (cnp->cn_namelen == 4 && memcmp(pname, "root", 4) == 0) { 366 *vpp = rootdir; 367 VREF(rootdir); 368 vn_lock(rootdir, LK_SHARED | LK_RETRY); 369 return (0); 370 } 371 #endif 372 373 wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN)); 374 375 for (kt = kern_targets, i = 0; i < nkern_targets; kt++, i++) { 376 if (cnp->cn_namelen == kt->kt_namlen && 377 memcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) 378 goto found; 379 } 380 381 #ifdef KERNFS_DIAGNOSTIC 382 printf("kernfs_lookup: i = %d, failed", i); 383 #endif 384 385 return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); 386 387 found: 388 if (kt->kt_tag == KTT_DEVICE) { 389 dev_t *dp = kt->kt_data; 390 loop: 391 if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) { 392 return (ENOENT); 393 } 394 *vpp = fvp; 395 if (vget(fvp, LK_EXCLUSIVE)) 396 goto loop; 397 if (wantpunlock) { 398 VOP_UNLOCK(dvp, 0); 399 cnp->cn_flags |= PDIRUNLOCK; 400 } 401 return (0); 402 } 403 404 #ifdef KERNFS_DIAGNOSTIC 405 printf("kernfs_lookup: allocate new vnode\n"); 406 #endif 407 error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p, &fvp); 408 if (error) { 409 return (error); 410 } 411 412 MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, 413 M_WAITOK); 414 VTOKERN(fvp)->kf_kt = kt; 415 fvp->v_type = kt->kt_vtype; 416 vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY); 417 *vpp = fvp; 418 419 #ifdef KERNFS_DIAGNOSTIC 420 printf("kernfs_lookup: newvp = %p\n", fvp); 421 #endif 422 if (wantpunlock) { 423 VOP_UNLOCK(dvp, 0); 424 cnp->cn_flags |= PDIRUNLOCK; 425 } 426 return (0); 427 } 428 429 int 430 kernfs_access(v) 431 void *v; 432 { 433 struct vop_access_args /* { 434 struct vnode *a_vp; 435 int a_mode; 436 struct ucred *a_cred; 437 struct proc *a_p; 438 } */ *ap = v; 439 struct vnode *vp = ap->a_vp; 440 mode_t mode; 441 442 if (vp->v_flag & VROOT) { 443 mode = DIR_MODE; 444 } else { 445 const struct kern_target *kt = VTOKERN(vp)->kf_kt; 446 mode = kt->kt_mode; 447 } 448 449 return (vaccess(vp->v_type, mode, (uid_t)0, (gid_t)0, ap->a_mode, 450 ap->a_cred)); 451 } 452 453 int 454 kernfs_getattr(v) 455 void *v; 456 { 457 struct vop_getattr_args /* { 458 struct vnode *a_vp; 459 struct vattr *a_vap; 460 struct ucred *a_cred; 461 struct proc *a_p; 462 } */ *ap = v; 463 struct vnode *vp = ap->a_vp; 464 struct vattr *vap = ap->a_vap; 465 int error = 0; 466 char strbuf[KSTRING], *buf; 467 468 memset((caddr_t) vap, 0, sizeof(*vap)); 469 vattr_null(vap); 470 vap->va_uid = 0; 471 vap->va_gid = 0; 472 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 473 vap->va_size = 0; 474 vap->va_blocksize = DEV_BSIZE; 475 /* 476 * Make all times be current TOD. Avoid microtime(9), it's slow. 477 * We don't guard the read from time(9) with splclock(9) since we 478 * don't actually need to be THAT sure the access is atomic. 479 */ 480 TIMEVAL_TO_TIMESPEC(&time, &vap->va_ctime); 481 vap->va_atime = vap->va_mtime = vap->va_ctime; 482 vap->va_gen = 0; 483 vap->va_flags = 0; 484 vap->va_rdev = 0; 485 vap->va_bytes = 0; 486 487 if (vp->v_flag & VROOT) { 488 #ifdef KERNFS_DIAGNOSTIC 489 printf("kernfs_getattr: stat rootdir\n"); 490 #endif 491 vap->va_type = VDIR; 492 vap->va_mode = DIR_MODE; 493 vap->va_nlink = 2; 494 vap->va_fileid = 2; 495 vap->va_size = DEV_BSIZE; 496 } else { 497 const struct kern_target *kt = VTOKERN(vp)->kf_kt; 498 size_t nread, total; 499 #ifdef KERNFS_DIAGNOSTIC 500 printf("kernfs_getattr: stat target %s\n", kt->kt_name); 501 #endif 502 vap->va_type = kt->kt_vtype; 503 vap->va_mode = kt->kt_mode; 504 vap->va_nlink = 1; 505 vap->va_fileid = 1 + (kt - kern_targets); 506 total = 0; 507 do { 508 buf = strbuf; 509 error = kernfs_xread(kt, total, &buf, 510 sizeof(strbuf), &nread); 511 total += nread; 512 } while (error == 0 && nread != 0); 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