xref: /netbsd-src/sys/miscfs/kernfs/kernfs_vnops.c (revision 06be8101a16cc95f40783b3cb7afd12112103a9a)
1 /*	$NetBSD: kernfs_vnops.c,v 1.77 2001/11/10 13:33:42 lukem 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. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)kernfs_vnops.c	8.15 (Berkeley) 5/21/95
39  */
40 
41 /*
42  * Kernel parameter filesystem (/kern)
43  */
44 
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: kernfs_vnops.c,v 1.77 2001/11/10 13:33:42 lukem Exp $");
47 
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/vmmeter.h>
52 #include <sys/types.h>
53 #include <sys/time.h>
54 #include <sys/proc.h>
55 #include <sys/vnode.h>
56 #include <sys/malloc.h>
57 #include <sys/file.h>
58 #include <sys/stat.h>
59 #include <sys/mount.h>
60 #include <sys/namei.h>
61 #include <sys/buf.h>
62 #include <sys/dirent.h>
63 #include <sys/msgbuf.h>
64 
65 #include <miscfs/genfs/genfs.h>
66 #include <miscfs/kernfs/kernfs.h>
67 
68 #include <uvm/uvm_extern.h>
69 
70 #define KSTRING	256		/* Largest I/O available via this filesystem */
71 #define	UIO_MX 32
72 
73 #define	READ_MODE	(S_IRUSR|S_IRGRP|S_IROTH)
74 #define	WRITE_MODE	(S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)
75 #define DIR_MODE	(S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
76 
77 const struct kern_target kern_targets[] = {
78 /* NOTE: The name must be less than UIO_MX-16 chars in length */
79 #define N(s) sizeof(s)-1, s
80      /*        name            data          tag           type  ro/rw */
81      { DT_DIR, N("."),         0,            KTT_NULL,     VDIR, DIR_MODE   },
82      { DT_DIR, N(".."),        0,            KTT_NULL,     VDIR, DIR_MODE   },
83      { DT_REG, N("boottime"),  &boottime.tv_sec, KTT_INT,  VREG, READ_MODE  },
84 			/* XXX cast away const */
85      { DT_REG, N("copyright"), (void *)copyright,
86      					     KTT_STRING,   VREG, READ_MODE  },
87      { DT_REG, N("hostname"),  0,            KTT_HOSTNAME, VREG, WRITE_MODE },
88      { DT_REG, N("hz"),        &hz,          KTT_INT,      VREG, READ_MODE  },
89      { DT_REG, N("loadavg"),   0,            KTT_AVENRUN,  VREG, READ_MODE  },
90      { DT_REG, N("msgbuf"),    0,	     KTT_MSGBUF,   VREG, READ_MODE  },
91      { DT_REG, N("pagesize"),  &uvmexp.pagesize, KTT_INT,  VREG, READ_MODE  },
92      { DT_REG, N("physmem"),   &physmem,     KTT_INT,      VREG, READ_MODE  },
93 #if 0
94      { DT_DIR, N("root"),      0,            KTT_NULL,     VDIR, DIR_MODE   },
95 #endif
96      { DT_BLK, N("rootdev"),   &rootdev,     KTT_DEVICE,   VBLK, READ_MODE  },
97      { DT_CHR, N("rrootdev"),  &rrootdev,    KTT_DEVICE,   VCHR, READ_MODE  },
98      { DT_REG, N("time"),      0,            KTT_TIME,     VREG, READ_MODE  },
99 			/* XXX cast away const */
100      { DT_REG, N("version"),   (void *)version,
101      					     KTT_STRING,   VREG, READ_MODE  },
102 #undef N
103 };
104 static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]);
105 
106 int	kernfs_lookup	__P((void *));
107 #define	kernfs_create	genfs_eopnotsupp_rele
108 #define	kernfs_mknod	genfs_eopnotsupp_rele
109 #define	kernfs_open	genfs_nullop
110 #define	kernfs_close	genfs_nullop
111 int	kernfs_access	__P((void *));
112 int	kernfs_getattr	__P((void *));
113 int	kernfs_setattr	__P((void *));
114 int	kernfs_read	__P((void *));
115 int	kernfs_write	__P((void *));
116 #define	kernfs_fcntl	genfs_fcntl
117 #define	kernfs_ioctl	genfs_enoioctl
118 #define	kernfs_poll	genfs_poll
119 #define kernfs_revoke	genfs_revoke
120 #define	kernfs_fsync	genfs_nullop
121 #define	kernfs_seek	genfs_nullop
122 #define	kernfs_remove	genfs_eopnotsupp_rele
123 int	kernfs_link	__P((void *));
124 #define	kernfs_rename	genfs_eopnotsupp_rele
125 #define	kernfs_mkdir	genfs_eopnotsupp_rele
126 #define	kernfs_rmdir	genfs_eopnotsupp_rele
127 int	kernfs_symlink	__P((void *));
128 int	kernfs_readdir	__P((void *));
129 #define	kernfs_readlink	genfs_eopnotsupp
130 #define	kernfs_abortop	genfs_abortop
131 int	kernfs_inactive	__P((void *));
132 int	kernfs_reclaim	__P((void *));
133 #define	kernfs_lock	genfs_lock
134 #define	kernfs_unlock	genfs_unlock
135 #define	kernfs_bmap	genfs_badop
136 #define	kernfs_strategy	genfs_badop
137 int	kernfs_print	__P((void *));
138 #define	kernfs_islocked	genfs_islocked
139 int	kernfs_pathconf	__P((void *));
140 #define	kernfs_advlock	genfs_einval
141 #define	kernfs_blkatoff	genfs_eopnotsupp
142 #define	kernfs_valloc	genfs_eopnotsupp
143 #define	kernfs_vfree	genfs_nullop
144 #define	kernfs_truncate	genfs_eopnotsupp
145 #define	kernfs_update	genfs_nullop
146 #define	kernfs_bwrite	genfs_eopnotsupp
147 
148 int	kernfs_xread __P((const struct kern_target *, int, char **, int));
149 int	kernfs_xwrite __P((const struct kern_target *, char *, int));
150 
151 int (**kernfs_vnodeop_p) __P((void *));
152 const struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = {
153 	{ &vop_default_desc, vn_default_error },
154 	{ &vop_lookup_desc, kernfs_lookup },		/* lookup */
155 	{ &vop_create_desc, kernfs_create },		/* create */
156 	{ &vop_mknod_desc, kernfs_mknod },		/* mknod */
157 	{ &vop_open_desc, kernfs_open },		/* open */
158 	{ &vop_close_desc, kernfs_close },		/* close */
159 	{ &vop_access_desc, kernfs_access },		/* access */
160 	{ &vop_getattr_desc, kernfs_getattr },		/* getattr */
161 	{ &vop_setattr_desc, kernfs_setattr },		/* setattr */
162 	{ &vop_read_desc, kernfs_read },		/* read */
163 	{ &vop_write_desc, kernfs_write },		/* write */
164 	{ &vop_fcntl_desc, kernfs_fcntl },		/* fcntl */
165 	{ &vop_ioctl_desc, kernfs_ioctl },		/* ioctl */
166 	{ &vop_poll_desc, kernfs_poll },		/* poll */
167 	{ &vop_revoke_desc, kernfs_revoke },		/* revoke */
168 	{ &vop_fsync_desc, kernfs_fsync },		/* fsync */
169 	{ &vop_seek_desc, kernfs_seek },		/* seek */
170 	{ &vop_remove_desc, kernfs_remove },		/* remove */
171 	{ &vop_link_desc, kernfs_link },		/* link */
172 	{ &vop_rename_desc, kernfs_rename },		/* rename */
173 	{ &vop_mkdir_desc, kernfs_mkdir },		/* mkdir */
174 	{ &vop_rmdir_desc, kernfs_rmdir },		/* rmdir */
175 	{ &vop_symlink_desc, kernfs_symlink },		/* symlink */
176 	{ &vop_readdir_desc, kernfs_readdir },		/* readdir */
177 	{ &vop_readlink_desc, kernfs_readlink },	/* readlink */
178 	{ &vop_abortop_desc, kernfs_abortop },		/* abortop */
179 	{ &vop_inactive_desc, kernfs_inactive },	/* inactive */
180 	{ &vop_reclaim_desc, kernfs_reclaim },		/* reclaim */
181 	{ &vop_lock_desc, kernfs_lock },		/* lock */
182 	{ &vop_unlock_desc, kernfs_unlock },		/* unlock */
183 	{ &vop_bmap_desc, kernfs_bmap },		/* bmap */
184 	{ &vop_strategy_desc, kernfs_strategy },	/* strategy */
185 	{ &vop_print_desc, kernfs_print },		/* print */
186 	{ &vop_islocked_desc, kernfs_islocked },	/* islocked */
187 	{ &vop_pathconf_desc, kernfs_pathconf },	/* pathconf */
188 	{ &vop_advlock_desc, kernfs_advlock },		/* advlock */
189 	{ &vop_blkatoff_desc, kernfs_blkatoff },	/* blkatoff */
190 	{ &vop_valloc_desc, kernfs_valloc },		/* valloc */
191 	{ &vop_vfree_desc, kernfs_vfree },		/* vfree */
192 	{ &vop_truncate_desc, kernfs_truncate },	/* truncate */
193 	{ &vop_update_desc, kernfs_update },		/* update */
194 	{ &vop_bwrite_desc, kernfs_bwrite },		/* bwrite */
195 	{ NULL, NULL }
196 };
197 const struct vnodeopv_desc kernfs_vnodeop_opv_desc =
198 	{ &kernfs_vnodeop_p, kernfs_vnodeop_entries };
199 
200 int
201 kernfs_xread(kt, off, bufp, len)
202 	const struct kern_target *kt;
203 	int off;
204 	char **bufp;
205 	int len;
206 {
207 
208 	switch (kt->kt_tag) {
209 	case KTT_TIME: {
210 		struct timeval tv;
211 
212 		microtime(&tv);
213 		sprintf(*bufp, "%ld %ld\n", tv.tv_sec, tv.tv_usec);
214 		break;
215 	}
216 
217 	case KTT_INT: {
218 		int *ip = kt->kt_data;
219 
220 		sprintf(*bufp, "%d\n", *ip);
221 		break;
222 	}
223 
224 	case KTT_STRING: {
225 		char *cp = kt->kt_data;
226 
227 		*bufp = cp;
228 		break;
229 	}
230 
231 	case KTT_MSGBUF: {
232 		long n;
233 
234 		/*
235 		 * deal with cases where the message buffer has
236 		 * become corrupted.
237 		 */
238 		if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) {
239 			msgbufenabled = 0;
240 			return (ENXIO);
241 		}
242 
243 		/*
244 		 * Note that reads of /kern/msgbuf won't necessarily yield
245 		 * consistent results, if the message buffer is modified
246 		 * while the read is in progress.  The worst that can happen
247 		 * is that incorrect data will be read.  There's no way
248 		 * that this can crash the system unless the values in the
249 		 * message buffer header are corrupted, but that'll cause
250 		 * the system to die anyway.
251 		 */
252 		if (off >= msgbufp->msg_bufs)
253 			return (0);
254 		n = msgbufp->msg_bufx + off;
255 		if (n >= msgbufp->msg_bufs)
256 			n -= msgbufp->msg_bufs;
257 		len = min(msgbufp->msg_bufs - n, msgbufp->msg_bufs - off);
258 		*bufp = msgbufp->msg_bufc + n;
259 		return (len);
260 	}
261 
262 	case KTT_HOSTNAME: {
263 		char *cp = hostname;
264 		int xlen = hostnamelen;
265 
266 		if (xlen >= (len-2))
267 			return (EINVAL);
268 
269 		memcpy(*bufp, cp, xlen);
270 		(*bufp)[xlen] = '\n';
271 		(*bufp)[xlen+1] = '\0';
272 		break;
273 	}
274 
275 	case KTT_AVENRUN:
276 		averunnable.fscale = FSCALE;
277 		sprintf(*bufp, "%d %d %d %ld\n",
278 		    averunnable.ldavg[0], averunnable.ldavg[1],
279 		    averunnable.ldavg[2], averunnable.fscale);
280 		break;
281 
282 	default:
283 		return (0);
284 	}
285 
286 	len = strlen(*bufp);
287 	if (len <= off)
288 		return (0);
289 	*bufp += off;
290 	return (len - off);
291 }
292 
293 int
294 kernfs_xwrite(kt, buf, len)
295 	const struct kern_target *kt;
296 	char *buf;
297 	int len;
298 {
299 
300 	switch (kt->kt_tag) {
301 	case KTT_HOSTNAME:
302 		if (buf[len-1] == '\n')
303 			--len;
304 		memcpy(hostname, buf, len);
305 		hostname[len] = '\0';
306 		hostnamelen = len;
307 		return (0);
308 
309 	default:
310 		return (EIO);
311 	}
312 }
313 
314 
315 /*
316  * vp is the current namei directory
317  * ndp is the name to locate in that directory...
318  */
319 int
320 kernfs_lookup(v)
321 	void *v;
322 {
323 	struct vop_lookup_args /* {
324 		struct vnode * a_dvp;
325 		struct vnode ** a_vpp;
326 		struct componentname * a_cnp;
327 	} */ *ap = v;
328 	struct componentname *cnp = ap->a_cnp;
329 	struct vnode **vpp = ap->a_vpp;
330 	struct vnode *dvp = ap->a_dvp;
331 	const char *pname = cnp->cn_nameptr;
332 	const struct kern_target *kt;
333 	struct vnode *fvp;
334 	int error, i, wantpunlock;
335 
336 #ifdef KERNFS_DIAGNOSTIC
337 	printf("kernfs_lookup(%p)\n", ap);
338 	printf("kernfs_lookup(dp = %p, vpp = %p, cnp = %p)\n", dvp, vpp, ap->a_cnp);
339 	printf("kernfs_lookup(%s)\n", pname);
340 #endif
341 
342 	*vpp = NULLVP;
343 	cnp->cn_flags &= ~PDIRUNLOCK;
344 
345 	if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
346 		return (EROFS);
347 
348 	if (cnp->cn_namelen == 1 && *pname == '.') {
349 		*vpp = dvp;
350 		VREF(dvp);
351 		return (0);
352 	}
353 
354 	/*
355 	 * This code only supports a flat directory, so we don't
356 	 * need to worry about ..
357 	 */
358 
359 #if 0
360 	if (cnp->cn_namelen == 4 && memcmp(pname, "root", 4) == 0) {
361 		*vpp = rootdir;
362 		VREF(rootdir);
363 		vn_lock(rootdir, LK_SHARED | LK_RETRY);
364 		return (0);
365 	}
366 #endif
367 
368 	wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN));
369 
370 	for (kt = kern_targets, i = 0; i < nkern_targets; kt++, i++) {
371 		if (cnp->cn_namelen == kt->kt_namlen &&
372 		    memcmp(kt->kt_name, pname, cnp->cn_namelen) == 0)
373 			goto found;
374 	}
375 
376 #ifdef KERNFS_DIAGNOSTIC
377 	printf("kernfs_lookup: i = %d, failed", i);
378 #endif
379 
380 	return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
381 
382 found:
383 	if (kt->kt_tag == KTT_DEVICE) {
384 		dev_t *dp = kt->kt_data;
385 	loop:
386 		if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) {
387 			return (ENOENT);
388 		}
389 		*vpp = fvp;
390 		if (vget(fvp, LK_EXCLUSIVE))
391 			goto loop;
392 		if (wantpunlock) {
393 			VOP_UNLOCK(dvp, 0);
394 			cnp->cn_flags |= PDIRUNLOCK;
395 		}
396 		return (0);
397 	}
398 
399 #ifdef KERNFS_DIAGNOSTIC
400 	printf("kernfs_lookup: allocate new vnode\n");
401 #endif
402 	error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p, &fvp);
403 	if (error) {
404 		return (error);
405 	}
406 
407 	MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP,
408 	    M_WAITOK);
409 	VTOKERN(fvp)->kf_kt = kt;
410 	fvp->v_type = kt->kt_vtype;
411 	vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
412 	*vpp = fvp;
413 
414 #ifdef KERNFS_DIAGNOSTIC
415 	printf("kernfs_lookup: newvp = %p\n", fvp);
416 #endif
417 	if (wantpunlock) {
418 		VOP_UNLOCK(dvp, 0);
419 		cnp->cn_flags |= PDIRUNLOCK;
420 	}
421 	return (0);
422 }
423 
424 int
425 kernfs_access(v)
426 	void *v;
427 {
428 	struct vop_access_args /* {
429 		struct vnode *a_vp;
430 		int a_mode;
431 		struct ucred *a_cred;
432 		struct proc *a_p;
433 	} */ *ap = v;
434 	struct vnode *vp = ap->a_vp;
435 	mode_t mode;
436 
437 	if (vp->v_flag & VROOT) {
438 		mode = DIR_MODE;
439 	} else {
440 		const struct kern_target *kt = VTOKERN(vp)->kf_kt;
441 		mode = kt->kt_mode;
442 	}
443 
444 	return (vaccess(vp->v_type, mode, (uid_t)0, (gid_t)0, ap->a_mode,
445 	    ap->a_cred));
446 }
447 
448 int
449 kernfs_getattr(v)
450 	void *v;
451 {
452 	struct vop_getattr_args /* {
453 		struct vnode *a_vp;
454 		struct vattr *a_vap;
455 		struct ucred *a_cred;
456 		struct proc *a_p;
457 	} */ *ap = v;
458 	struct vnode *vp = ap->a_vp;
459 	struct vattr *vap = ap->a_vap;
460 	struct timeval tv;
461 	int error = 0;
462 	char strbuf[KSTRING], *buf;
463 
464 	memset((caddr_t) vap, 0, sizeof(*vap));
465 	vattr_null(vap);
466 	vap->va_uid = 0;
467 	vap->va_gid = 0;
468 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
469 	vap->va_size = 0;
470 	vap->va_blocksize = DEV_BSIZE;
471 	microtime(&tv);
472 	TIMEVAL_TO_TIMESPEC(&tv, &vap->va_atime);
473 	vap->va_mtime = vap->va_atime;
474 	vap->va_ctime = vap->va_ctime;
475 	vap->va_gen = 0;
476 	vap->va_flags = 0;
477 	vap->va_rdev = 0;
478 	vap->va_bytes = 0;
479 
480 	if (vp->v_flag & VROOT) {
481 #ifdef KERNFS_DIAGNOSTIC
482 		printf("kernfs_getattr: stat rootdir\n");
483 #endif
484 		vap->va_type = VDIR;
485 		vap->va_mode = DIR_MODE;
486 		vap->va_nlink = 2;
487 		vap->va_fileid = 2;
488 		vap->va_size = DEV_BSIZE;
489 	} else {
490 		const struct kern_target *kt = VTOKERN(vp)->kf_kt;
491 		int nbytes, total;
492 #ifdef KERNFS_DIAGNOSTIC
493 		printf("kernfs_getattr: stat target %s\n", kt->kt_name);
494 #endif
495 		vap->va_type = kt->kt_vtype;
496 		vap->va_mode = kt->kt_mode;
497 		vap->va_nlink = 1;
498 		vap->va_fileid = 1 + (kt - kern_targets);
499 		total = 0;
500 		while (buf = strbuf,
501 		       nbytes = kernfs_xread(kt, total, &buf, sizeof(strbuf)))
502 			total += nbytes;
503 		vap->va_size = total;
504 	}
505 
506 #ifdef KERNFS_DIAGNOSTIC
507 	printf("kernfs_getattr: return error %d\n", error);
508 #endif
509 	return (error);
510 }
511 
512 /*ARGSUSED*/
513 int
514 kernfs_setattr(v)
515 	void *v;
516 {
517 	/*
518 	 * Silently ignore attribute changes.
519 	 * This allows for open with truncate to have no
520 	 * effect until some data is written.  I want to
521 	 * do it this way because all writes are atomic.
522 	 */
523 	return (0);
524 }
525 
526 int
527 kernfs_read(v)
528 	void *v;
529 {
530 	struct vop_read_args /* {
531 		struct vnode *a_vp;
532 		struct uio *a_uio;
533 		int  a_ioflag;
534 		struct ucred *a_cred;
535 	} */ *ap = v;
536 	struct vnode *vp = ap->a_vp;
537 	struct uio *uio = ap->a_uio;
538 	const struct kern_target *kt;
539 	char strbuf[KSTRING], *buf;
540 	int off, len;
541 	int error;
542 
543 	if (vp->v_type == VDIR)
544 		return (EOPNOTSUPP);
545 
546 	kt = VTOKERN(vp)->kf_kt;
547 
548 #ifdef KERNFS_DIAGNOSTIC
549 	printf("kern_read %s\n", kt->kt_name);
550 #endif
551 
552 	off = uio->uio_offset;
553 #if 0
554 	while (buf = strbuf,
555 #else
556 	if (buf = strbuf,
557 #endif
558 	    len = kernfs_xread(kt, off, &buf, sizeof(strbuf))) {
559 		if ((error = uiomove(buf, len, uio)) != 0)
560 			return (error);
561 		off += len;
562 	}
563 	return (0);
564 }
565 
566 int
567 kernfs_write(v)
568 	void *v;
569 {
570 	struct vop_write_args /* {
571 		struct vnode *a_vp;
572 		struct uio *a_uio;
573 		int  a_ioflag;
574 		struct ucred *a_cred;
575 	} */ *ap = v;
576 	struct vnode *vp = ap->a_vp;
577 	struct uio *uio = ap->a_uio;
578 	const struct kern_target *kt;
579 	int error, xlen;
580 	char strbuf[KSTRING];
581 
582 	if (vp->v_type == VDIR)
583 		return (EOPNOTSUPP);
584 
585 	kt = VTOKERN(vp)->kf_kt;
586 
587 	if (uio->uio_offset != 0)
588 		return (EINVAL);
589 
590 	xlen = min(uio->uio_resid, KSTRING-1);
591 	if ((error = uiomove(strbuf, xlen, uio)) != 0)
592 		return (error);
593 
594 	if (uio->uio_resid != 0)
595 		return (EIO);
596 
597 	strbuf[xlen] = '\0';
598 	xlen = strlen(strbuf);
599 	return (kernfs_xwrite(kt, strbuf, xlen));
600 }
601 
602 int
603 kernfs_readdir(v)
604 	void *v;
605 {
606 	struct vop_readdir_args /* {
607 		struct vnode *a_vp;
608 		struct uio *a_uio;
609 		struct ucred *a_cred;
610 		int *a_eofflag;
611 		off_t **a_cookies;
612 		int a_*ncookies;
613 	} */ *ap = v;
614 	struct uio *uio = ap->a_uio;
615 	struct dirent d;
616 	const struct kern_target *kt;
617 	off_t i;
618 	int error;
619 	off_t *cookies = NULL;
620 	int ncookies = 0, nc = 0;
621 
622 	if (ap->a_vp->v_type != VDIR)
623 		return (ENOTDIR);
624 
625 	if (uio->uio_resid < UIO_MX)
626 		return (EINVAL);
627 	if (uio->uio_offset < 0)
628 		return (EINVAL);
629 
630 	error = 0;
631 	i = uio->uio_offset;
632 
633 	if (i >= nkern_targets)
634 		return 0;
635 
636 	memset((caddr_t)&d, 0, UIO_MX);
637 	d.d_reclen = UIO_MX;
638 
639 	if (ap->a_ncookies) {
640 		nc = uio->uio_resid / UIO_MX;
641 		nc = min(nc, (nkern_targets - i));
642 		cookies = malloc(nc * sizeof(off_t), M_TEMP, M_WAITOK);
643 		*ap->a_cookies = cookies;
644 	}
645 
646 	for (kt = &kern_targets[i];
647 	     uio->uio_resid >= UIO_MX && i < nkern_targets; kt++, i++) {
648 #ifdef KERNFS_DIAGNOSTIC
649 		printf("kernfs_readdir: i = %d\n", (int)i);
650 #endif
651 
652 		if (kt->kt_tag == KTT_DEVICE) {
653 			dev_t *dp = kt->kt_data;
654 			struct vnode *fvp;
655 
656 			if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp))
657 				continue;
658 		}
659 
660 		d.d_fileno = i + 3;
661 		d.d_namlen = kt->kt_namlen;
662 		memcpy(d.d_name, kt->kt_name, kt->kt_namlen + 1);
663 		d.d_type = kt->kt_type;
664 
665 		if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0)
666 			break;
667 		if (cookies) {
668 			*cookies++ = i + 1;
669 			ncookies++;
670 		}
671 	}
672 
673 	if (ap->a_ncookies) {
674 		if (error) {
675 			free(*ap->a_cookies, M_TEMP);
676 			*ap->a_ncookies = 0;
677 			*ap->a_cookies = NULL;
678 		} else
679 			*ap->a_ncookies = ncookies;
680 	}
681 
682 	uio->uio_offset = i;
683 	return (error);
684 }
685 
686 int
687 kernfs_inactive(v)
688 	void *v;
689 {
690 	struct vop_inactive_args /* {
691 		struct vnode *a_vp;
692 		struct proc *a_p;
693 	} */ *ap = v;
694 	struct vnode *vp = ap->a_vp;
695 
696 #ifdef KERNFS_DIAGNOSTIC
697 	printf("kernfs_inactive(%p)\n", vp);
698 #endif
699 	/*
700 	 * Clear out the v_type field to avoid
701 	 * nasty things happening in vgone().
702 	 */
703 	VOP_UNLOCK(vp, 0);
704 	vp->v_type = VNON;
705 	return (0);
706 }
707 
708 int
709 kernfs_reclaim(v)
710 	void *v;
711 {
712 	struct vop_reclaim_args /* {
713 		struct vnode *a_vp;
714 	} */ *ap = v;
715 	struct vnode *vp = ap->a_vp;
716 
717 #ifdef KERNFS_DIAGNOSTIC
718 	printf("kernfs_reclaim(%p)\n", vp);
719 #endif
720 	if (vp->v_data) {
721 		FREE(vp->v_data, M_TEMP);
722 		vp->v_data = 0;
723 	}
724 	return (0);
725 }
726 
727 /*
728  * Return POSIX pathconf information applicable to special devices.
729  */
730 int
731 kernfs_pathconf(v)
732 	void *v;
733 {
734 	struct vop_pathconf_args /* {
735 		struct vnode *a_vp;
736 		int a_name;
737 		register_t *a_retval;
738 	} */ *ap = v;
739 
740 	switch (ap->a_name) {
741 	case _PC_LINK_MAX:
742 		*ap->a_retval = LINK_MAX;
743 		return (0);
744 	case _PC_MAX_CANON:
745 		*ap->a_retval = MAX_CANON;
746 		return (0);
747 	case _PC_MAX_INPUT:
748 		*ap->a_retval = MAX_INPUT;
749 		return (0);
750 	case _PC_PIPE_BUF:
751 		*ap->a_retval = PIPE_BUF;
752 		return (0);
753 	case _PC_CHOWN_RESTRICTED:
754 		*ap->a_retval = 1;
755 		return (0);
756 	case _PC_VDISABLE:
757 		*ap->a_retval = _POSIX_VDISABLE;
758 		return (0);
759 	case _PC_SYNC_IO:
760 		*ap->a_retval = 1;
761 		return (0);
762 	default:
763 		return (EINVAL);
764 	}
765 	/* NOTREACHED */
766 }
767 
768 /*
769  * Print out the contents of a /dev/fd vnode.
770  */
771 /* ARGSUSED */
772 int
773 kernfs_print(v)
774 	void *v;
775 {
776 
777 	printf("tag VT_KERNFS, kernfs vnode\n");
778 	return (0);
779 }
780 
781 int
782 kernfs_link(v)
783 	void *v;
784 {
785 	struct vop_link_args /* {
786 		struct vnode *a_dvp;
787 		struct vnode *a_vp;
788 		struct componentname *a_cnp;
789 	} */ *ap = v;
790 
791 	VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
792 	vput(ap->a_dvp);
793 	return (EROFS);
794 }
795 
796 int
797 kernfs_symlink(v)
798 	void *v;
799 {
800 	struct vop_symlink_args /* {
801 		struct vnode *a_dvp;
802 		struct vnode **a_vpp;
803 		struct componentname *a_cnp;
804 		struct vattr *a_vap;
805 		char *a_target;
806 	} */ *ap = v;
807 
808 	VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
809 	vput(ap->a_dvp);
810 	return (EROFS);
811 }
812