1 /* $NetBSD: kernfs_vnops.c,v 1.146 2012/03/22 20:34:38 drochner 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.146 2012/03/22 20:34:38 drochner 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 UREAD_MODE (S_IRUSR) 71 #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 72 #define UDIR_MODE (S_IRUSR|S_IXUSR) 73 74 #define N(s) sizeof(s)-1, s 75 const struct kern_target kern_targets[] = { 76 /* NOTE: The name must be less than UIO_MX-16 chars in length */ 77 /* name data tag type ro/rw */ 78 { DT_DIR, N("."), 0, KFSkern, VDIR, DIR_MODE }, 79 { DT_DIR, N(".."), 0, KFSroot, VDIR, DIR_MODE }, 80 { DT_REG, N("boottime"), &boottime.tv_sec, KFSint, VREG, READ_MODE }, 81 /* XXXUNCONST */ 82 { DT_REG, N("copyright"), __UNCONST(copyright), 83 KFSstring, VREG, READ_MODE }, 84 { DT_REG, N("hostname"), 0, KFShostname, VREG, WRITE_MODE }, 85 { DT_REG, N("hz"), &hz, KFSint, VREG, READ_MODE }, 86 { DT_REG, N("loadavg"), 0, KFSavenrun, VREG, READ_MODE }, 87 { DT_REG, N("msgbuf"), 0, KFSmsgbuf, VREG, READ_MODE }, 88 { DT_REG, N("pagesize"), &uvmexp.pagesize, KFSint, VREG, READ_MODE }, 89 { DT_REG, N("physmem"), &physmem, KFSint, VREG, READ_MODE }, 90 #if 0 91 { DT_DIR, N("root"), 0, KFSnull, VDIR, DIR_MODE }, 92 #endif 93 { DT_BLK, N("rootdev"), &rootdev, KFSdevice, VBLK, READ_MODE }, 94 { DT_CHR, N("rrootdev"), &rrootdev, KFSdevice, VCHR, READ_MODE }, 95 { DT_REG, N("time"), 0, KFStime, VREG, READ_MODE }, 96 /* XXXUNCONST */ 97 { DT_REG, N("version"), __UNCONST(version), 98 KFSstring, VREG, READ_MODE }, 99 }; 100 const struct kern_target subdir_targets[] = { 101 /* NOTE: The name must be less than UIO_MX-16 chars in length */ 102 /* name data tag type ro/rw */ 103 { DT_DIR, N("."), 0, KFSsubdir, VDIR, DIR_MODE }, 104 { DT_DIR, N(".."), 0, KFSkern, VDIR, DIR_MODE }, 105 }; 106 #undef N 107 SIMPLEQ_HEAD(,dyn_kern_target) dyn_kern_targets = 108 SIMPLEQ_HEAD_INITIALIZER(dyn_kern_targets); 109 int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]); 110 const int static_nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]); 111 int nkern_dirs = 2; 112 113 int kernfs_try_fileop(kfstype, kfsfileop, void *, int); 114 int kernfs_try_xread(kfstype, const struct kernfs_node *, char **, 115 size_t, int); 116 int kernfs_try_xwrite(kfstype, const struct kernfs_node *, char *, 117 size_t, int); 118 119 static int kernfs_default_xread(void *v); 120 static int kernfs_default_xwrite(void *v); 121 static int kernfs_default_fileop_getattr(void *); 122 123 /* must include all fileop's */ 124 const struct kernfs_fileop kernfs_default_fileops[] = { 125 { .kf_fileop = KERNFS_XREAD }, 126 { .kf_fileop = KERNFS_XWRITE }, 127 { .kf_fileop = KERNFS_FILEOP_OPEN }, 128 { .kf_fileop = KERNFS_FILEOP_GETATTR, 129 .kf_vop = kernfs_default_fileop_getattr }, 130 { .kf_fileop = KERNFS_FILEOP_IOCTL }, 131 { .kf_fileop = KERNFS_FILEOP_CLOSE }, 132 { .kf_fileop = KERNFS_FILEOP_READ, 133 .kf_vop = kernfs_default_xread }, 134 { .kf_fileop = KERNFS_FILEOP_WRITE, 135 .kf_vop = kernfs_default_xwrite }, 136 }; 137 138 int kernfs_lookup(void *); 139 #define kernfs_create genfs_eopnotsupp 140 #define kernfs_mknod genfs_eopnotsupp 141 int kernfs_open(void *); 142 int kernfs_close(void *); 143 int kernfs_access(void *); 144 int kernfs_getattr(void *); 145 int kernfs_setattr(void *); 146 int kernfs_read(void *); 147 int kernfs_write(void *); 148 #define kernfs_fcntl genfs_fcntl 149 int kernfs_ioctl(void *); 150 #define kernfs_poll genfs_poll 151 #define kernfs_revoke genfs_revoke 152 #define kernfs_fsync genfs_nullop 153 #define kernfs_seek genfs_nullop 154 #define kernfs_remove genfs_eopnotsupp 155 int kernfs_link(void *); 156 #define kernfs_rename genfs_eopnotsupp 157 #define kernfs_mkdir genfs_eopnotsupp 158 #define kernfs_rmdir genfs_eopnotsupp 159 int kernfs_symlink(void *); 160 int kernfs_readdir(void *); 161 #define kernfs_readlink genfs_eopnotsupp 162 #define kernfs_abortop genfs_abortop 163 int kernfs_inactive(void *); 164 int kernfs_reclaim(void *); 165 #define kernfs_lock genfs_lock 166 #define kernfs_unlock genfs_unlock 167 #define kernfs_bmap genfs_badop 168 #define kernfs_strategy genfs_badop 169 int kernfs_print(void *); 170 #define kernfs_islocked genfs_islocked 171 int kernfs_pathconf(void *); 172 #define kernfs_advlock genfs_einval 173 #define kernfs_bwrite genfs_eopnotsupp 174 #define kernfs_putpages genfs_putpages 175 176 static int kernfs_xread(struct kernfs_node *, int, char **, 177 size_t, size_t *); 178 static int kernfs_xwrite(const struct kernfs_node *, char *, size_t); 179 180 int (**kernfs_vnodeop_p)(void *); 181 const struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = { 182 { &vop_default_desc, vn_default_error }, 183 { &vop_lookup_desc, kernfs_lookup }, /* lookup */ 184 { &vop_create_desc, kernfs_create }, /* create */ 185 { &vop_mknod_desc, kernfs_mknod }, /* mknod */ 186 { &vop_open_desc, kernfs_open }, /* open */ 187 { &vop_close_desc, kernfs_close }, /* close */ 188 { &vop_access_desc, kernfs_access }, /* access */ 189 { &vop_getattr_desc, kernfs_getattr }, /* getattr */ 190 { &vop_setattr_desc, kernfs_setattr }, /* setattr */ 191 { &vop_read_desc, kernfs_read }, /* read */ 192 { &vop_write_desc, kernfs_write }, /* write */ 193 { &vop_fcntl_desc, kernfs_fcntl }, /* fcntl */ 194 { &vop_ioctl_desc, kernfs_ioctl }, /* ioctl */ 195 { &vop_poll_desc, kernfs_poll }, /* poll */ 196 { &vop_revoke_desc, kernfs_revoke }, /* revoke */ 197 { &vop_fsync_desc, kernfs_fsync }, /* fsync */ 198 { &vop_seek_desc, kernfs_seek }, /* seek */ 199 { &vop_remove_desc, kernfs_remove }, /* remove */ 200 { &vop_link_desc, kernfs_link }, /* link */ 201 { &vop_rename_desc, kernfs_rename }, /* rename */ 202 { &vop_mkdir_desc, kernfs_mkdir }, /* mkdir */ 203 { &vop_rmdir_desc, kernfs_rmdir }, /* rmdir */ 204 { &vop_symlink_desc, kernfs_symlink }, /* symlink */ 205 { &vop_readdir_desc, kernfs_readdir }, /* readdir */ 206 { &vop_readlink_desc, kernfs_readlink }, /* readlink */ 207 { &vop_abortop_desc, kernfs_abortop }, /* abortop */ 208 { &vop_inactive_desc, kernfs_inactive }, /* inactive */ 209 { &vop_reclaim_desc, kernfs_reclaim }, /* reclaim */ 210 { &vop_lock_desc, kernfs_lock }, /* lock */ 211 { &vop_unlock_desc, kernfs_unlock }, /* unlock */ 212 { &vop_bmap_desc, kernfs_bmap }, /* bmap */ 213 { &vop_strategy_desc, kernfs_strategy }, /* strategy */ 214 { &vop_print_desc, kernfs_print }, /* print */ 215 { &vop_islocked_desc, kernfs_islocked }, /* islocked */ 216 { &vop_pathconf_desc, kernfs_pathconf }, /* pathconf */ 217 { &vop_advlock_desc, kernfs_advlock }, /* advlock */ 218 { &vop_bwrite_desc, kernfs_bwrite }, /* bwrite */ 219 { &vop_putpages_desc, kernfs_putpages }, /* putpages */ 220 { NULL, NULL } 221 }; 222 const struct vnodeopv_desc kernfs_vnodeop_opv_desc = 223 { &kernfs_vnodeop_p, kernfs_vnodeop_entries }; 224 225 static inline int 226 kernfs_fileop_compare(struct kernfs_fileop *a, struct kernfs_fileop *b) 227 { 228 if (a->kf_type < b->kf_type) 229 return -1; 230 if (a->kf_type > b->kf_type) 231 return 1; 232 if (a->kf_fileop < b->kf_fileop) 233 return -1; 234 if (a->kf_fileop > b->kf_fileop) 235 return 1; 236 return (0); 237 } 238 239 SPLAY_HEAD(kfsfileoptree, kernfs_fileop) kfsfileoptree = 240 SPLAY_INITIALIZER(kfsfileoptree); 241 SPLAY_PROTOTYPE(kfsfileoptree, kernfs_fileop, kf_node, kernfs_fileop_compare); 242 SPLAY_GENERATE(kfsfileoptree, kernfs_fileop, kf_node, kernfs_fileop_compare); 243 244 kfstype 245 kernfs_alloctype(int nkf, const struct kernfs_fileop *kf) 246 { 247 static u_char nextfreetype = KFSlasttype; 248 struct kernfs_fileop *dkf, *fkf, skf; 249 int i; 250 251 /* XXX need to keep track of dkf's memory if we support 252 deallocating types */ 253 dkf = malloc(sizeof(kernfs_default_fileops), M_TEMP, M_WAITOK); 254 memcpy(dkf, kernfs_default_fileops, sizeof(kernfs_default_fileops)); 255 256 for (i = 0; i < sizeof(kernfs_default_fileops) / 257 sizeof(kernfs_default_fileops[0]); i++) { 258 dkf[i].kf_type = nextfreetype; 259 SPLAY_INSERT(kfsfileoptree, &kfsfileoptree, &dkf[i]); 260 } 261 262 for (i = 0; i < nkf; i++) { 263 skf.kf_type = nextfreetype; 264 skf.kf_fileop = kf[i].kf_fileop; 265 if ((fkf = SPLAY_FIND(kfsfileoptree, &kfsfileoptree, &skf))) 266 fkf->kf_vop = kf[i].kf_vop; 267 } 268 269 return nextfreetype++; 270 } 271 272 int 273 kernfs_try_fileop(kfstype type, kfsfileop fileop, void *v, int error) 274 { 275 struct kernfs_fileop *kf, skf; 276 277 skf.kf_type = type; 278 skf.kf_fileop = fileop; 279 if ((kf = SPLAY_FIND(kfsfileoptree, &kfsfileoptree, &skf))) 280 if (kf->kf_vop) 281 return kf->kf_vop(v); 282 return error; 283 } 284 285 int 286 kernfs_try_xread(kfstype type, const struct kernfs_node *kfs, char **bfp, 287 size_t len, int error) 288 { 289 struct kernfs_fileop *kf, skf; 290 291 skf.kf_type = type; 292 skf.kf_fileop = KERNFS_XREAD; 293 if ((kf = SPLAY_FIND(kfsfileoptree, &kfsfileoptree, &skf))) 294 if (kf->kf_xread) 295 return kf->kf_xread(kfs, bfp, len); 296 return error; 297 } 298 299 int 300 kernfs_try_xwrite(kfstype type, const struct kernfs_node *kfs, char *bf, 301 size_t len, int error) 302 { 303 struct kernfs_fileop *kf, skf; 304 305 skf.kf_type = type; 306 skf.kf_fileop = KERNFS_XWRITE; 307 if ((kf = SPLAY_FIND(kfsfileoptree, &kfsfileoptree, &skf))) 308 if (kf->kf_xwrite) 309 return kf->kf_xwrite(kfs, bf, len); 310 return error; 311 } 312 313 int 314 kernfs_addentry(kernfs_parentdir_t *pkt, kernfs_entry_t *dkt) 315 { 316 struct kernfs_subdir *ks, *parent; 317 318 if (pkt == NULL) { 319 SIMPLEQ_INSERT_TAIL(&dyn_kern_targets, dkt, dkt_queue); 320 nkern_targets++; 321 if (dkt->dkt_kt.kt_vtype == VDIR) 322 nkern_dirs++; 323 } else { 324 parent = (struct kernfs_subdir *)pkt->kt_data; 325 SIMPLEQ_INSERT_TAIL(&parent->ks_entries, dkt, dkt_queue); 326 parent->ks_nentries++; 327 if (dkt->dkt_kt.kt_vtype == VDIR) 328 parent->ks_dirs++; 329 } 330 if (dkt->dkt_kt.kt_vtype == VDIR && dkt->dkt_kt.kt_data == NULL) { 331 ks = malloc(sizeof(struct kernfs_subdir), 332 M_TEMP, M_WAITOK); 333 SIMPLEQ_INIT(&ks->ks_entries); 334 ks->ks_nentries = 2; /* . and .. */ 335 ks->ks_dirs = 2; 336 ks->ks_parent = pkt ? pkt : &kern_targets[0]; 337 dkt->dkt_kt.kt_data = ks; 338 } 339 return 0; 340 } 341 342 static int 343 kernfs_xread(struct kernfs_node *kfs, int off, char **bufp, size_t len, size_t *wrlen) 344 { 345 const struct kern_target *kt; 346 int err; 347 348 kt = kfs->kfs_kt; 349 350 switch (kfs->kfs_type) { 351 case KFStime: { 352 struct timeval tv; 353 354 microtime(&tv); 355 snprintf(*bufp, len, "%lld %ld\n", (long long)tv.tv_sec, 356 (long)tv.tv_usec); 357 break; 358 } 359 360 case KFSint: { 361 int *ip = kt->kt_data; 362 363 snprintf(*bufp, len, "%d\n", *ip); 364 break; 365 } 366 367 case KFSstring: { 368 char *cp = kt->kt_data; 369 370 *bufp = cp; 371 break; 372 } 373 374 case KFSmsgbuf: { 375 long n; 376 377 /* 378 * deal with cases where the message buffer has 379 * become corrupted. 380 */ 381 if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) { 382 msgbufenabled = 0; 383 return (ENXIO); 384 } 385 386 /* 387 * Note that reads of /kern/msgbuf won't necessarily yield 388 * consistent results, if the message buffer is modified 389 * while the read is in progress. The worst that can happen 390 * is that incorrect data will be read. There's no way 391 * that this can crash the system unless the values in the 392 * message buffer header are corrupted, but that'll cause 393 * the system to die anyway. 394 */ 395 if (off >= msgbufp->msg_bufs) { 396 *wrlen = 0; 397 return (0); 398 } 399 n = msgbufp->msg_bufx + off; 400 if (n >= msgbufp->msg_bufs) 401 n -= msgbufp->msg_bufs; 402 len = min(msgbufp->msg_bufs - n, msgbufp->msg_bufs - off); 403 *bufp = msgbufp->msg_bufc + n; 404 *wrlen = len; 405 return (0); 406 } 407 408 case KFShostname: { 409 char *cp = hostname; 410 size_t xlen = hostnamelen; 411 412 if (xlen >= (len - 2)) 413 return (EINVAL); 414 415 memcpy(*bufp, cp, xlen); 416 (*bufp)[xlen] = '\n'; 417 (*bufp)[xlen+1] = '\0'; 418 break; 419 } 420 421 case KFSavenrun: 422 averunnable.fscale = FSCALE; 423 snprintf(*bufp, len, "%d %d %d %ld\n", 424 averunnable.ldavg[0], averunnable.ldavg[1], 425 averunnable.ldavg[2], averunnable.fscale); 426 break; 427 428 default: 429 err = kernfs_try_xread(kfs->kfs_type, kfs, bufp, len, 430 EOPNOTSUPP); 431 if (err) 432 return err; 433 } 434 435 len = strlen(*bufp); 436 if (len <= off) 437 *wrlen = 0; 438 else { 439 *bufp += off; 440 *wrlen = len - off; 441 } 442 return (0); 443 } 444 445 static int 446 kernfs_xwrite(const struct kernfs_node *kfs, char *bf, size_t len) 447 { 448 449 switch (kfs->kfs_type) { 450 case KFShostname: 451 if (bf[len-1] == '\n') 452 --len; 453 memcpy(hostname, bf, len); 454 hostname[len] = '\0'; 455 hostnamelen = (size_t) len; 456 return (0); 457 458 default: 459 return kernfs_try_xwrite(kfs->kfs_type, kfs, bf, len, EIO); 460 } 461 } 462 463 464 /* 465 * vp is the current namei directory 466 * ndp is the name to locate in that directory... 467 */ 468 int 469 kernfs_lookup(void *v) 470 { 471 struct vop_lookup_args /* { 472 struct vnode * a_dvp; 473 struct vnode ** a_vpp; 474 struct componentname * a_cnp; 475 } */ *ap = v; 476 struct componentname *cnp = ap->a_cnp; 477 struct vnode **vpp = ap->a_vpp; 478 struct vnode *dvp = ap->a_dvp; 479 const char *pname = cnp->cn_nameptr; 480 const struct kernfs_node *kfs; 481 const struct kern_target *kt; 482 const struct dyn_kern_target *dkt; 483 const struct kernfs_subdir *ks; 484 int error, i; 485 486 *vpp = NULLVP; 487 488 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) 489 return (EROFS); 490 491 if (cnp->cn_namelen == 1 && *pname == '.') { 492 *vpp = dvp; 493 vref(dvp); 494 return (0); 495 } 496 497 kfs = VTOKERN(dvp); 498 switch (kfs->kfs_type) { 499 case KFSkern: 500 /* 501 * Shouldn't get here with .. in the root node. 502 */ 503 if (cnp->cn_flags & ISDOTDOT) 504 return (EIO); 505 506 for (i = 0; i < static_nkern_targets; i++) { 507 kt = &kern_targets[i]; 508 if (cnp->cn_namelen == kt->kt_namlen && 509 memcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) 510 goto found; 511 } 512 SIMPLEQ_FOREACH(dkt, &dyn_kern_targets, dkt_queue) { 513 if (cnp->cn_namelen == dkt->dkt_kt.kt_namlen && 514 memcmp(dkt->dkt_kt.kt_name, pname, cnp->cn_namelen) == 0) { 515 kt = &dkt->dkt_kt; 516 goto found; 517 } 518 } 519 break; 520 521 found: 522 error = kernfs_allocvp(dvp->v_mount, vpp, kt->kt_tag, kt, 0); 523 return (error); 524 525 case KFSsubdir: 526 ks = (struct kernfs_subdir *)kfs->kfs_kt->kt_data; 527 if (cnp->cn_flags & ISDOTDOT) { 528 kt = ks->ks_parent; 529 goto found; 530 } 531 532 SIMPLEQ_FOREACH(dkt, &ks->ks_entries, dkt_queue) { 533 if (cnp->cn_namelen == dkt->dkt_kt.kt_namlen && 534 memcmp(dkt->dkt_kt.kt_name, pname, cnp->cn_namelen) == 0) { 535 kt = &dkt->dkt_kt; 536 goto found; 537 } 538 } 539 break; 540 541 default: 542 return (ENOTDIR); 543 } 544 545 return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); 546 } 547 548 int 549 kernfs_open(void *v) 550 { 551 struct vop_open_args /* { 552 struct vnode *a_vp; 553 int a_mode; 554 kauth_cred_t a_cred; 555 } */ *ap = v; 556 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 557 558 return kernfs_try_fileop(kfs->kfs_type, KERNFS_FILEOP_OPEN, v, 0); 559 } 560 561 int 562 kernfs_close(void *v) 563 { 564 struct vop_close_args /* { 565 struct vnode *a_vp; 566 int a_fflag; 567 kauth_cred_t a_cred; 568 } */ *ap = v; 569 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 570 571 return kernfs_try_fileop(kfs->kfs_type, KERNFS_FILEOP_CLOSE, v, 0); 572 } 573 574 int 575 kernfs_access(void *v) 576 { 577 struct vop_access_args /* { 578 struct vnode *a_vp; 579 int a_mode; 580 kauth_cred_t a_cred; 581 } */ *ap = v; 582 struct vattr va; 583 int error; 584 585 if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred)) != 0) 586 return (error); 587 588 return kauth_authorize_vnode(ap->a_cred, 589 kauth_access_action(ap->a_mode, ap->a_vp->v_type, va.va_mode), 590 ap->a_vp, NULL, genfs_can_access(va.va_type, va.va_mode, 591 va.va_uid, va.va_gid, ap->a_mode, ap->a_cred)); 592 } 593 594 static int 595 kernfs_default_fileop_getattr(void *v) 596 { 597 struct vop_getattr_args /* { 598 struct vnode *a_vp; 599 struct vattr *a_vap; 600 kauth_cred_t a_cred; 601 } */ *ap = v; 602 struct vattr *vap = ap->a_vap; 603 604 vap->va_nlink = 1; 605 vap->va_bytes = vap->va_size = 0; 606 607 return 0; 608 } 609 610 int 611 kernfs_getattr(void *v) 612 { 613 struct vop_getattr_args /* { 614 struct vnode *a_vp; 615 struct vattr *a_vap; 616 kauth_cred_t a_cred; 617 } */ *ap = v; 618 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 619 struct kernfs_subdir *ks; 620 struct vattr *vap = ap->a_vap; 621 int error = 0; 622 char strbuf[KSTRING], *bf; 623 size_t nread, total; 624 625 vattr_null(vap); 626 vap->va_type = ap->a_vp->v_type; 627 vap->va_uid = 0; 628 vap->va_gid = 0; 629 vap->va_mode = kfs->kfs_mode; 630 vap->va_fileid = kfs->kfs_fileno; 631 vap->va_flags = 0; 632 vap->va_size = 0; 633 vap->va_blocksize = DEV_BSIZE; 634 /* Make all times be current TOD, except for the "boottime" node. */ 635 if (kfs->kfs_kt->kt_namlen == 8 && 636 !memcmp(kfs->kfs_kt->kt_name, "boottime", 8)) { 637 vap->va_ctime = boottime; 638 } else { 639 getnanotime(&vap->va_ctime); 640 } 641 vap->va_atime = vap->va_mtime = vap->va_ctime; 642 vap->va_gen = 0; 643 vap->va_flags = 0; 644 vap->va_rdev = 0; 645 vap->va_bytes = 0; 646 647 switch (kfs->kfs_type) { 648 case KFSkern: 649 vap->va_nlink = nkern_dirs; 650 vap->va_bytes = vap->va_size = DEV_BSIZE; 651 break; 652 653 case KFSroot: 654 vap->va_nlink = 1; 655 vap->va_bytes = vap->va_size = DEV_BSIZE; 656 break; 657 658 case KFSsubdir: 659 ks = (struct kernfs_subdir *)kfs->kfs_kt->kt_data; 660 vap->va_nlink = ks->ks_dirs; 661 vap->va_bytes = vap->va_size = DEV_BSIZE; 662 break; 663 664 case KFSnull: 665 case KFStime: 666 case KFSint: 667 case KFSstring: 668 case KFShostname: 669 case KFSavenrun: 670 case KFSdevice: 671 case KFSmsgbuf: 672 vap->va_nlink = 1; 673 total = 0; 674 do { 675 bf = strbuf; 676 error = kernfs_xread(kfs, total, &bf, 677 sizeof(strbuf), &nread); 678 total += nread; 679 } while (error == 0 && nread != 0); 680 vap->va_bytes = vap->va_size = total; 681 break; 682 683 default: 684 error = kernfs_try_fileop(kfs->kfs_type, 685 KERNFS_FILEOP_GETATTR, v, EINVAL); 686 break; 687 } 688 689 return (error); 690 } 691 692 /*ARGSUSED*/ 693 int 694 kernfs_setattr(void *v) 695 { 696 697 /* 698 * Silently ignore attribute changes. 699 * This allows for open with truncate to have no 700 * effect until some data is written. I want to 701 * do it this way because all writes are atomic. 702 */ 703 return (0); 704 } 705 706 int 707 kernfs_default_xread(void *v) 708 { 709 struct vop_read_args /* { 710 struct vnode *a_vp; 711 struct uio *a_uio; 712 int a_ioflag; 713 kauth_cred_t a_cred; 714 } */ *ap = v; 715 struct uio *uio = ap->a_uio; 716 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 717 char strbuf[KSTRING], *bf; 718 int off; 719 size_t len; 720 int error; 721 722 if (ap->a_vp->v_type == VDIR) 723 return EISDIR; 724 725 off = (int)uio->uio_offset; 726 /* Don't allow negative offsets */ 727 if (off < 0) 728 return EINVAL; 729 730 bf = strbuf; 731 if ((error = kernfs_xread(kfs, off, &bf, sizeof(strbuf), &len)) == 0) 732 error = uiomove(bf, len, uio); 733 return (error); 734 } 735 736 int 737 kernfs_read(void *v) 738 { 739 struct vop_read_args /* { 740 struct vnode *a_vp; 741 struct uio *a_uio; 742 int a_ioflag; 743 struct ucred *a_cred; 744 } */ *ap = v; 745 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 746 747 if (kfs->kfs_type < KFSlasttype) { 748 /* use default function */ 749 return kernfs_default_xread(v); 750 } 751 return kernfs_try_fileop(kfs->kfs_type, KERNFS_FILEOP_READ, v, 752 EOPNOTSUPP); 753 } 754 755 static int 756 kernfs_default_xwrite(void *v) 757 { 758 struct vop_write_args /* { 759 struct vnode *a_vp; 760 struct uio *a_uio; 761 int a_ioflag; 762 kauth_cred_t a_cred; 763 } */ *ap = v; 764 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 765 struct uio *uio = ap->a_uio; 766 int error; 767 size_t xlen; 768 char strbuf[KSTRING]; 769 770 if (uio->uio_offset != 0) 771 return (EINVAL); 772 773 xlen = min(uio->uio_resid, KSTRING-1); 774 if ((error = uiomove(strbuf, xlen, uio)) != 0) 775 return (error); 776 777 if (uio->uio_resid != 0) 778 return (EIO); 779 780 strbuf[xlen] = '\0'; 781 xlen = strlen(strbuf); 782 return (kernfs_xwrite(kfs, strbuf, xlen)); 783 } 784 785 int 786 kernfs_write(void *v) 787 { 788 struct vop_write_args /* { 789 struct vnode *a_vp; 790 struct uio *a_uio; 791 int a_ioflag; 792 kauth_cred_t a_cred; 793 } */ *ap = v; 794 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 795 796 if (kfs->kfs_type < KFSlasttype) { 797 /* use default function */ 798 return kernfs_default_xwrite(v); 799 } 800 return kernfs_try_fileop(kfs->kfs_type, KERNFS_FILEOP_WRITE, v, 801 EOPNOTSUPP); 802 } 803 804 int 805 kernfs_ioctl(void *v) 806 { 807 struct vop_ioctl_args /* { 808 const struct vnodeop_desc *a_desc; 809 struct vnode *a_vp; 810 u_long a_command; 811 void *a_data; 812 int a_fflag; 813 kauth_cred_t a_cred; 814 } */ *ap = v; 815 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 816 817 return kernfs_try_fileop(kfs->kfs_type, KERNFS_FILEOP_IOCTL, v, 818 EPASSTHROUGH); 819 } 820 821 static int 822 kernfs_setdirentfileno_kt(struct dirent *d, const struct kern_target *kt, 823 u_int32_t value, struct vop_readdir_args *ap) 824 { 825 struct kernfs_node *kfs; 826 struct vnode *vp; 827 int error; 828 829 if ((error = kernfs_allocvp(ap->a_vp->v_mount, &vp, kt->kt_tag, kt, 830 value)) != 0) 831 return error; 832 if (kt->kt_tag == KFSdevice) { 833 struct vattr va; 834 835 error = VOP_GETATTR(vp, &va, ap->a_cred); 836 if (error != 0) { 837 return error; 838 } 839 d->d_fileno = va.va_fileid; 840 } else { 841 kfs = VTOKERN(vp); 842 d->d_fileno = kfs->kfs_fileno; 843 } 844 vput(vp); 845 return 0; 846 } 847 848 static int 849 kernfs_setdirentfileno(struct dirent *d, off_t entry, 850 struct kernfs_node *thisdir_kfs, const struct kern_target *parent_kt, 851 const struct kern_target *kt, struct vop_readdir_args *ap) 852 { 853 const struct kern_target *ikt; 854 int error; 855 856 switch (entry) { 857 case 0: 858 d->d_fileno = thisdir_kfs->kfs_fileno; 859 return 0; 860 case 1: 861 ikt = parent_kt; 862 break; 863 default: 864 ikt = kt; 865 break; 866 } 867 if (ikt != thisdir_kfs->kfs_kt) { 868 if ((error = kernfs_setdirentfileno_kt(d, ikt, 0, ap)) != 0) 869 return error; 870 } else 871 d->d_fileno = thisdir_kfs->kfs_fileno; 872 return 0; 873 } 874 875 int 876 kernfs_readdir(void *v) 877 { 878 struct vop_readdir_args /* { 879 struct vnode *a_vp; 880 struct uio *a_uio; 881 kauth_cred_t a_cred; 882 int *a_eofflag; 883 off_t **a_cookies; 884 int a_*ncookies; 885 } */ *ap = v; 886 struct uio *uio = ap->a_uio; 887 struct dirent d; 888 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 889 const struct kern_target *kt; 890 const struct dyn_kern_target *dkt = NULL; 891 const struct kernfs_subdir *ks; 892 off_t i, j; 893 int error; 894 off_t *cookies = NULL; 895 int ncookies = 0, n; 896 897 if (uio->uio_resid < UIO_MX) 898 return (EINVAL); 899 if (uio->uio_offset < 0) 900 return (EINVAL); 901 902 error = 0; 903 i = uio->uio_offset; 904 memset(&d, 0, sizeof(d)); 905 d.d_reclen = UIO_MX; 906 ncookies = uio->uio_resid / UIO_MX; 907 908 switch (kfs->kfs_type) { 909 case KFSkern: 910 if (i >= nkern_targets) 911 return (0); 912 913 if (ap->a_ncookies) { 914 ncookies = min(ncookies, (nkern_targets - i)); 915 cookies = malloc(ncookies * sizeof(off_t), M_TEMP, 916 M_WAITOK); 917 *ap->a_cookies = cookies; 918 } 919 920 n = 0; 921 for (; i < nkern_targets && uio->uio_resid >= UIO_MX; i++) { 922 if (i < static_nkern_targets) 923 kt = &kern_targets[i]; 924 else { 925 if (dkt == NULL) { 926 dkt = SIMPLEQ_FIRST(&dyn_kern_targets); 927 for (j = static_nkern_targets; j < i && 928 dkt != NULL; j++) 929 dkt = SIMPLEQ_NEXT(dkt, dkt_queue); 930 if (j != i) 931 break; 932 } else { 933 dkt = SIMPLEQ_NEXT(dkt, dkt_queue); 934 } 935 if (dkt == NULL) 936 break; 937 kt = &dkt->dkt_kt; 938 } 939 if (kt->kt_tag == KFSdevice) { 940 dev_t *dp = kt->kt_data; 941 struct vnode *fvp; 942 943 if (*dp == NODEV || 944 !vfinddev(*dp, kt->kt_vtype, &fvp)) 945 continue; 946 vrele(fvp); 947 } 948 if (kt->kt_tag == KFSmsgbuf) { 949 if (!msgbufenabled 950 || msgbufp->msg_magic != MSG_MAGIC) { 951 continue; 952 } 953 } 954 d.d_namlen = kt->kt_namlen; 955 if ((error = kernfs_setdirentfileno(&d, i, kfs, 956 &kern_targets[0], kt, ap)) != 0) 957 break; 958 memcpy(d.d_name, kt->kt_name, kt->kt_namlen + 1); 959 d.d_type = kt->kt_type; 960 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 961 break; 962 if (cookies) 963 *cookies++ = i + 1; 964 n++; 965 } 966 ncookies = n; 967 break; 968 969 case KFSroot: 970 if (i >= 2) 971 return 0; 972 973 if (ap->a_ncookies) { 974 ncookies = min(ncookies, (2 - i)); 975 cookies = malloc(ncookies * sizeof(off_t), M_TEMP, 976 M_WAITOK); 977 *ap->a_cookies = cookies; 978 } 979 980 n = 0; 981 for (; i < 2 && uio->uio_resid >= UIO_MX; i++) { 982 kt = &kern_targets[i]; 983 d.d_namlen = kt->kt_namlen; 984 d.d_fileno = KERNFS_FILENO(kt, kt->kt_tag, 0); 985 memcpy(d.d_name, kt->kt_name, kt->kt_namlen + 1); 986 d.d_type = kt->kt_type; 987 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 988 break; 989 if (cookies) 990 *cookies++ = i + 1; 991 n++; 992 } 993 ncookies = n; 994 break; 995 996 case KFSsubdir: 997 ks = (struct kernfs_subdir *)kfs->kfs_kt->kt_data; 998 if (i >= ks->ks_nentries) 999 return (0); 1000 1001 if (ap->a_ncookies) { 1002 ncookies = min(ncookies, (ks->ks_nentries - i)); 1003 cookies = malloc(ncookies * sizeof(off_t), M_TEMP, 1004 M_WAITOK); 1005 *ap->a_cookies = cookies; 1006 } 1007 1008 dkt = SIMPLEQ_FIRST(&ks->ks_entries); 1009 for (j = 0; j < i && dkt != NULL; j++) 1010 dkt = SIMPLEQ_NEXT(dkt, dkt_queue); 1011 n = 0; 1012 for (; i < ks->ks_nentries && uio->uio_resid >= UIO_MX; i++) { 1013 if (i < 2) 1014 kt = &subdir_targets[i]; 1015 else { 1016 /* check if ks_nentries lied to us */ 1017 if (dkt == NULL) 1018 break; 1019 kt = &dkt->dkt_kt; 1020 dkt = SIMPLEQ_NEXT(dkt, dkt_queue); 1021 } 1022 if (kt->kt_tag == KFSdevice) { 1023 dev_t *dp = kt->kt_data; 1024 struct vnode *fvp; 1025 1026 if (*dp == NODEV || 1027 !vfinddev(*dp, kt->kt_vtype, &fvp)) 1028 continue; 1029 vrele(fvp); 1030 } 1031 d.d_namlen = kt->kt_namlen; 1032 if ((error = kernfs_setdirentfileno(&d, i, kfs, 1033 ks->ks_parent, kt, ap)) != 0) 1034 break; 1035 memcpy(d.d_name, kt->kt_name, kt->kt_namlen + 1); 1036 d.d_type = kt->kt_type; 1037 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1038 break; 1039 if (cookies) 1040 *cookies++ = i + 1; 1041 n++; 1042 } 1043 ncookies = n; 1044 break; 1045 1046 default: 1047 error = ENOTDIR; 1048 break; 1049 } 1050 1051 if (ap->a_ncookies) { 1052 if (error) { 1053 if (cookies) 1054 free(*ap->a_cookies, M_TEMP); 1055 *ap->a_ncookies = 0; 1056 *ap->a_cookies = NULL; 1057 } else 1058 *ap->a_ncookies = ncookies; 1059 } 1060 1061 uio->uio_offset = i; 1062 return (error); 1063 } 1064 1065 int 1066 kernfs_inactive(void *v) 1067 { 1068 struct vop_inactive_args /* { 1069 struct vnode *a_vp; 1070 bool *a_recycle; 1071 } */ *ap = v; 1072 struct vnode *vp = ap->a_vp; 1073 1074 *ap->a_recycle = false; 1075 VOP_UNLOCK(vp); 1076 return (0); 1077 } 1078 1079 int 1080 kernfs_reclaim(void *v) 1081 { 1082 struct vop_reclaim_args /* { 1083 struct vnode *a_vp; 1084 } */ *ap = v; 1085 1086 return (kernfs_freevp(ap->a_vp)); 1087 } 1088 1089 /* 1090 * Return POSIX pathconf information applicable to special devices. 1091 */ 1092 int 1093 kernfs_pathconf(void *v) 1094 { 1095 struct vop_pathconf_args /* { 1096 struct vnode *a_vp; 1097 int a_name; 1098 register_t *a_retval; 1099 } */ *ap = v; 1100 1101 switch (ap->a_name) { 1102 case _PC_LINK_MAX: 1103 *ap->a_retval = LINK_MAX; 1104 return (0); 1105 case _PC_MAX_CANON: 1106 *ap->a_retval = MAX_CANON; 1107 return (0); 1108 case _PC_MAX_INPUT: 1109 *ap->a_retval = MAX_INPUT; 1110 return (0); 1111 case _PC_PIPE_BUF: 1112 *ap->a_retval = PIPE_BUF; 1113 return (0); 1114 case _PC_CHOWN_RESTRICTED: 1115 *ap->a_retval = 1; 1116 return (0); 1117 case _PC_VDISABLE: 1118 *ap->a_retval = _POSIX_VDISABLE; 1119 return (0); 1120 case _PC_SYNC_IO: 1121 *ap->a_retval = 1; 1122 return (0); 1123 default: 1124 return (EINVAL); 1125 } 1126 /* NOTREACHED */ 1127 } 1128 1129 /* 1130 * Print out the contents of a /dev/fd vnode. 1131 */ 1132 /* ARGSUSED */ 1133 int 1134 kernfs_print(void *v) 1135 { 1136 1137 printf("tag VT_KERNFS, kernfs vnode\n"); 1138 return (0); 1139 } 1140 1141 int 1142 kernfs_link(void *v) 1143 { 1144 struct vop_link_args /* { 1145 struct vnode *a_dvp; 1146 struct vnode *a_vp; 1147 struct componentname *a_cnp; 1148 } */ *ap = v; 1149 1150 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 1151 vput(ap->a_dvp); 1152 return (EROFS); 1153 } 1154 1155 int 1156 kernfs_symlink(void *v) 1157 { 1158 struct vop_symlink_args /* { 1159 struct vnode *a_dvp; 1160 struct vnode **a_vpp; 1161 struct componentname *a_cnp; 1162 struct vattr *a_vap; 1163 char *a_target; 1164 } */ *ap = v; 1165 1166 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 1167 vput(ap->a_dvp); 1168 return (EROFS); 1169 } 1170