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