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