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