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