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