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