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