1 /*
2  * Copyright (c) 1992 The Regents of the University of California
3  * Copyright (c) 1990, 1992 Jan-Simon Pendry
4  * All rights reserved.
5  *
6  * This code is derived from software donated to Berkeley by
7  * Jan-Simon Pendry.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)kernfs_vnops.c	7.1 (Berkeley) 07/18/92
12  */
13 
14 /*
15  * Kernel parameter filesystem (/kern)
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/kernel.h>
21 #include <sys/vmmeter.h>
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/proc.h>
25 #include <sys/vnode.h>
26 #include <sys/malloc.h>
27 #include <sys/file.h>
28 #include <sys/stat.h>
29 #include <sys/mount.h>
30 #include <sys/namei.h>
31 #include <sys/buf.h>
32 #include <sys/dirent.h>
33 #include <miscfs/kernfs/kernfs.h>
34 
35 #define KSTRING	256		/* Largest I/O available via this filesystem */
36 #define	UIO_MX 32
37 
38 struct kern_target {
39 	char *kt_name;
40 	void *kt_data;
41 #define	KTT_NULL 1
42 #define	KTT_TIME 5
43 #define KTT_INT	17
44 #define	KTT_STRING 31
45 #define KTT_HOSTNAME 47
46 #define KTT_AVENRUN 53
47 	int kt_tag;
48 #define	KTM_RO	0
49 #define	KTM_RO_MODE		(S_IRUSR|S_IRGRP|S_IROTH)
50 #define	KTM_RW	43
51 #define	KTM_RW_MODE		(S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)
52 #define KTM_DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
53 	int kt_rw;
54 	int kt_vtype;
55 } kern_targets[] = {
56 /* NOTE: The name must be less than UIO_MX-16 chars in length */
57 	/* name		data		tag		ro/rw */
58 	{ ".",		0,		KTT_NULL,	KTM_RO,	VDIR },
59 	{ "copyright",	copyright,	KTT_STRING,	KTM_RO,	VREG },
60 	{ "hostname",	0,		KTT_HOSTNAME,	KTM_RW,	VREG },
61 	{ "hz",		&hz,		KTT_INT,	KTM_RO,	VREG },
62 	{ "loadavg",	0,		KTT_AVENRUN,	KTM_RO,	VREG },
63 	{ "pagesize",	&cnt.v_page_size, KTT_INT,	KTM_RO,	VREG },
64 	{ "physmem",	&physmem,	KTT_INT,	KTM_RO,	VREG },
65 	{ "root",	0,		KTT_NULL,	KTM_RO,	VDIR },
66 	{ "rootdev",	0,		KTT_NULL,	KTM_RO,	VBLK },
67 	{ "time",	0,		KTT_TIME,	KTM_RO,	VREG },
68 	{ "version",	version,	KTT_STRING,	KTM_RO,	VREG },
69 };
70 
71 static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]);
72 
73 static int
74 kernfs_xread(kt, buf, len, lenp)
75 	struct kern_target *kt;
76 	char *buf;
77 	int len;
78 	int *lenp;
79 {
80 	int xlen;
81 
82 	switch (kt->kt_tag) {
83 	case KTT_TIME: {
84 		struct timeval tv;
85 		microtime(&tv);
86 		sprintf(buf, "%d %d\n", tv.tv_sec, tv.tv_usec);
87 		break;
88 	}
89 
90 	case KTT_INT: {
91 		int *ip = kt->kt_data;
92 		sprintf(buf, "%d\n", *ip);
93 		break;
94 	}
95 
96 	case KTT_STRING: {
97 		char *cp = kt->kt_data;
98 		int xlen = strlen(cp) + 1;
99 
100 		if (xlen >= len)
101 			return (EINVAL);
102 
103 		bcopy(cp, buf, xlen);
104 		break;
105 	}
106 
107 	case KTT_HOSTNAME: {
108 		char *cp = hostname;
109 		int xlen = hostnamelen;
110 
111 		if (xlen >= len)
112 			return (EINVAL);
113 
114 		sprintf(buf, "%s\n", cp);
115 		break;
116 	}
117 
118 	case KTT_AVENRUN:
119 		sprintf(buf, "%ld %ld %ld %ld\n",
120 				averunnable.ldavg[0],
121 				averunnable.ldavg[1],
122 				averunnable.ldavg[2],
123 				averunnable.fscale);
124 		break;
125 
126 	default:
127 		return (EINVAL);
128 	}
129 
130 	*lenp = strlen(buf);
131 	return (0);
132 }
133 
134 static int
135 kernfs_xwrite(kt, buf, len)
136 	struct kern_target *kt;
137 	char *buf;
138 	int len;
139 {
140 	switch (kt->kt_tag) {
141 	case KTT_HOSTNAME: {
142 		if (buf[len-1] == '\n')
143 			--len;
144 		bcopy(buf, hostname, len);
145 		hostnamelen = len - 1;
146 		return (0);
147 	}
148 
149 	default:
150 		return (EIO);
151 	}
152 }
153 
154 
155 /*
156  * vp is the current namei directory
157  * ndp is the name to locate in that directory...
158  */
159 kernfs_lookup(ap)
160 	struct vop_lookup_args /* {
161 		struct vnode * a_dvp;
162 		struct vnode ** a_vpp;
163 		struct componentname * a_cnp;
164 	} */ *ap;
165 {
166 	struct vnode **vpp = ap->a_vpp;
167 	struct vnode *dvp = ap->a_dvp;
168 	struct componentname *cnp = ap->a_cnp;
169 	char *pname;
170 	struct proc *p;
171 	int error;
172 	struct vnode *fvp;
173 	int i;
174 
175 #ifdef KERNFS_DIAGNOSTIC
176 	printf("kernfs_lookup(%x)\n", ap);
177 	printf("kernfs_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp);
178 #endif
179 	pname = cnp->cn_nameptr;
180 #ifdef KERNFS_DIAGNOSTIC
181 	printf("kernfs_lookup(%s)\n", pname);
182 #endif
183 	if (cnp->cn_namelen == 1 && *pname == '.') {
184 		*vpp = dvp;
185 		VREF(dvp);
186 		/*VOP_LOCK(dvp);*/
187 		return (0);
188 	}
189 
190 	if (cnp->cn_namelen == 4 && bcmp(pname, "root", 4) == 0) {
191 		*vpp = rootdir;
192 		VREF(rootdir);
193 		VOP_LOCK(rootdir);
194 		return (0);
195 	}
196 
197 	/*
198 	 * /kern/rootdev is the root device
199 	 */
200 	if (cnp->cn_namelen == 7 && bcmp(pname, "rootdev", 7) == 0) {
201 		*vpp = rootvp;
202 		VREF(rootvp);
203 		VOP_LOCK(rootvp);
204 		return (0);
205 	}
206 
207 	for (i = 0; i < nkern_targets; i++) {
208 		struct kern_target *kt = &kern_targets[i];
209 		if (cnp->cn_namelen == strlen(kt->kt_name) &&
210 		    bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) {
211 			error = 0;
212 			break;
213 		}
214 	}
215 
216 #ifdef KERNFS_DIAGNOSTIC
217 	printf("kernfs_lookup: i = %d, error = %d\n", i, error);
218 #endif
219 
220 	if (error)
221 		goto bad;
222 
223 #ifdef KERNFS_DIAGNOSTIC
224 	printf("kernfs_lookup: allocate new vnode\n");
225 #endif
226 	error = getnewvnode(VT_UFS, dvp->v_mount, kernfs_vnodeop_p, &fvp);
227 	if (error)
228 		goto bad;
229 	MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, M_WAITOK);
230 	VTOKERN(fvp)->kf_kt = &kern_targets[i];
231 	fvp->v_type = VTOKERN(fvp)->kf_kt->kt_vtype;
232 	*vpp = fvp;
233 #ifdef KERNFS_DIAGNOSTIC
234 	printf("kernfs_lookup: newvp = %x\n", fvp);
235 #endif
236 	return (0);
237 
238 bad:;
239 	*vpp = NULL;
240 #ifdef KERNFS_DIAGNOSTIC
241 	printf("kernfs_lookup: error = %d\n", error);
242 #endif
243 	return (error);
244 }
245 
246 kernfs_open(ap)
247 	struct vop_open_args /* {
248 		struct vnode *a_vp;
249 		int  a_mode;
250 		struct ucred *a_cred;
251 		struct proc *a_p;
252 	} */ *ap;
253 {
254 	struct vnode *vp = ap->a_vp;
255 
256 	/*
257 	 * Can always open the root (modulo perms)
258 	 */
259 	if (vp->v_flag & VROOT)
260 		return (0);
261 
262 #ifdef KERNFS_DIAGNOSTIC
263 	printf("kernfs_open, mode = %x, file = %s\n",
264 			ap->a_mode, VTOKERN(vp)->kf_kt->kt_name);
265 #endif
266 
267 	if ((ap->a_mode & FWRITE) && VTOKERN(vp)->kf_kt->kt_rw != KTM_RW)
268 		return (EBADF);
269 
270 	return (0);
271 }
272 
273 static int
274 kernfs_access(ap)
275 	struct vop_access_args /* {
276 		struct vnode *a_vp;
277 		int  a_mode;
278 		struct ucred *a_cred;
279 		struct proc *a_p;
280 	} */ *ap;
281 {
282 	struct vnode *vp = ap->a_vp;
283 	struct ucred *cred = ap->a_cred;
284 	struct kern_target *kt = VTOKERN(vp)->kf_kt;
285 	mode_t mode = ap->a_mode;
286 
287 	if (mode & VEXEC) {
288 		if (vp->v_flag & VROOT)
289 			return (0);
290 		return (EACCES);
291 	}
292 
293 	if (cred->cr_uid == 0) {
294 		if ((mode & VWRITE) && (kt->kt_rw != KTM_RW))
295 			return (EROFS);
296 		return (0);
297 	}
298 
299 	if (mode & VWRITE)
300 		return (EACCES);
301 
302 	return (0);
303 }
304 
305 
306 kernfs_getattr(ap)
307 	struct vop_getattr_args /* {
308 		struct vnode *a_vp;
309 		struct vattr *a_vap;
310 		struct ucred *a_cred;
311 		struct proc *a_p;
312 	} */ *ap;
313 {
314 	struct vnode *vp = ap->a_vp;
315 	struct vattr *vap = ap->a_vap;
316 	int error = 0;
317 	char strbuf[KSTRING];
318 	struct kern_target *kt = VTOKERN(vp)->kf_kt;
319 
320 	bzero((caddr_t) vap, sizeof(*vap));
321 	vattr_null(vap);
322 	vap->va_uid = 0;
323 	vap->va_gid = 0;
324 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
325 	/* vap->va_qsize = 0; */
326 	vap->va_blocksize = DEV_BSIZE;
327 	microtime(&vap->va_atime);
328 	vap->va_mtime = vap->va_atime;
329 	vap->va_ctime = vap->va_ctime;
330 	vap->va_gen = 0;
331 	vap->va_flags = 0;
332 	vap->va_rdev = 0;
333 	/* vap->va_qbytes = 0; */
334 	vap->va_bytes = 0;
335 
336 	if (vp->v_flag & VROOT) {
337 #ifdef KERNFS_DIAGNOSTIC
338 		printf("kernfs_getattr: stat rootdir\n");
339 #endif
340 		vap->va_type = VDIR;
341 		vap->va_mode = KTM_DIR_MODE;
342 		vap->va_nlink = 2;
343 		vap->va_fileid = 2;
344 		vap->va_size = DEV_BSIZE;
345 	} else {
346 		int nbytes;
347 #ifdef KERNFS_DIAGNOSTIC
348 		printf("kernfs_getattr: stat target %s\n", kt->kt_name);
349 #endif
350 		vap->va_type = kt->kt_vtype;
351 		vap->va_mode = (kt->kt_rw ? KTM_RW_MODE : KTM_RO_MODE);
352 		vap->va_nlink = 1;
353 		vap->va_fileid = 3 + (kt - kern_targets) / sizeof(*kt);
354 		error = kernfs_xread(kt, strbuf, sizeof(strbuf), &nbytes);
355 		vap->va_size = nbytes;
356 	}
357 
358 	vp->v_type = vap->va_type;
359 #ifdef KERNFS_DIAGNOSTIC
360 	printf("kernfs_getattr: return error %d\n", error);
361 #endif
362 	return (error);
363 }
364 
365 kernfs_setattr(ap)
366 	struct vop_setattr_args /* {
367 		struct vnode *a_vp;
368 		struct vattr *a_vap;
369 		struct ucred *a_cred;
370 		struct proc *a_p;
371 	} */ *ap;
372 {
373 
374 	/*
375 	 * Silently ignore attribute changes.
376 	 * This allows for open with truncate to have no
377 	 * effect until some data is written.  I want to
378 	 * do it this way because all writes are atomic.
379 	 */
380 	return (0);
381 }
382 
383 static int
384 kernfs_read(ap)
385 	struct vop_read_args /* {
386 		struct vnode *a_vp;
387 		struct uio *a_uio;
388 		int  a_ioflag;
389 		struct ucred *a_cred;
390 	} */ *ap;
391 {
392 	struct vnode *vp = ap->a_vp;
393 	struct uio *uio = ap->a_uio;
394 	struct kern_target *kt = VTOKERN(vp)->kf_kt;
395 	char strbuf[KSTRING];
396 	int off = uio->uio_offset;
397 	int len = 0;
398 	char *cp = strbuf;
399 	int error;
400 #ifdef KERNFS_DIAGNOSTIC
401 	printf("kern_read %s\n", kt->kt_name);
402 #endif
403 
404 	error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len);
405 	if (error)
406 		return (error);
407 	cp = strbuf + off;
408 	len -= off;
409 	return (uiomove(cp, len, uio));
410 }
411 
412 static int
413 kernfs_write(ap)
414 	struct vop_write_args /* {
415 		struct vnode *a_vp;
416 		struct uio *a_uio;
417 		int  a_ioflag;
418 		struct ucred *a_cred;
419 	} */ *ap;
420 {
421 	struct vnode *vp = ap->a_vp;
422 	struct uio *uio = ap->a_uio;
423 	struct kern_target *kt = VTOKERN(vp)->kf_kt;
424 	char strbuf[KSTRING];
425 	int len = uio->uio_resid;
426 	char *cp = strbuf;
427 	int xlen;
428 	int error;
429 
430 	if (uio->uio_offset != 0)
431 		return (EINVAL);
432 
433 	xlen = min(uio->uio_resid, KSTRING-1);
434 	error = uiomove(strbuf, xlen, uio);
435 	if (error)
436 		return (error);
437 
438 	if (uio->uio_resid != 0)
439 		return (EIO);
440 
441 	strbuf[xlen] = '\0';
442 	return (kernfs_xwrite(kt, strbuf, xlen));
443 }
444 
445 
446 kernfs_readdir(ap)
447 	struct vop_readdir_args /* {
448 		struct vnode *a_vp;
449 		struct uio *a_uio;
450 		struct ucred *a_cred;
451 	} */ *ap;
452 {
453 	struct uio *uio = ap->a_uio;
454 	int i;
455 	int error;
456 
457 	i = uio->uio_offset / UIO_MX;
458 	error = 0;
459 	while (uio->uio_resid > 0 && i < nkern_targets) {
460 		struct dirent d;
461 		struct dirent *dp = &d;
462 		struct kern_target *kt = &kern_targets[i];
463 #ifdef KERNFS_DIAGNOSTIC
464 		printf("kernfs_readdir: i = %d\n", i);
465 #endif
466 
467 		bzero((caddr_t) dp, UIO_MX);
468 
469 		dp->d_namlen = strlen(kt->kt_name);
470 		bcopy(kt->kt_name, dp->d_name, dp->d_namlen+1);
471 
472 #ifdef KERNFS_DIAGNOSTIC
473 		printf("kernfs_readdir: name = %s, len = %d\n",
474 				dp->d_name, dp->d_namlen);
475 #endif
476 		/*
477 		 * Fill in the remaining fields
478 		 */
479 		dp->d_reclen = UIO_MX;
480 		dp->d_fileno = i + 3;
481 		dp->d_type = DT_UNKNOWN;	/* XXX */
482 		/*
483 		 * And ship to userland
484 		 */
485 		error = uiomove((caddr_t) dp, UIO_MX, uio);
486 		if (error)
487 			break;
488 		i++;
489 	}
490 
491 	uio->uio_offset = i * UIO_MX;
492 
493 	return (error);
494 }
495 
496 kernfs_inactive(ap)
497 	struct vop_inactive_args /* {
498 		struct vnode *a_vp;
499 	} */ *ap;
500 {
501 	struct vnode *vp = ap->a_vp;
502 
503 	/*
504 	 * Clear out the v_type field to avoid
505 	 * nasty things happening in vgone().
506 	 */
507 	vp->v_type = VNON;
508 #ifdef KERNFS_DIAGNOSTIC
509 	printf("kernfs_inactive(%x)\n", vp);
510 #endif
511 	return (0);
512 }
513 
514 kernfs_reclaim(ap)
515 	struct vop_reclaim_args /* {
516 		struct vnode *a_vp;
517 	} */ *ap;
518 {
519 	struct vnode *vp = ap->a_vp;
520 	printf("kernfs_reclaim(%x)\n", vp);
521 	if (vp->v_data) {
522 		FREE(vp->v_data, M_TEMP);
523 		vp->v_data = 0;
524 	}
525 	return (0);
526 }
527 
528 /*
529  * Print out the contents of a /dev/fd vnode.
530  */
531 /* ARGSUSED */
532 kernfs_print(ap)
533 	struct vop_print_args /* {
534 		struct vnode *a_vp;
535 	} */ *ap;
536 {
537 
538 	printf("tag VT_NON, kernfs vnode\n");
539 	return (0);
540 }
541 
542 /*void*/
543 kernfs_vfree(ap)
544 	struct vop_vfree_args /* {
545 		struct vnode *a_pvp;
546 		ino_t a_ino;
547 		int a_mode;
548 	} */ *ap;
549 {
550 
551 	return (0);
552 }
553 
554 /*
555  * /dev/fd vnode unsupported operation
556  */
557 kernfs_enotsupp()
558 {
559 
560 	return (EOPNOTSUPP);
561 }
562 
563 /*
564  * /dev/fd "should never get here" operation
565  */
566 kernfs_badop()
567 {
568 
569 	panic("kernfs: bad op");
570 	/* NOTREACHED */
571 }
572 
573 /*
574  * /dev/fd vnode null operation
575  */
576 kernfs_nullop()
577 {
578 
579 	return (0);
580 }
581 
582 #define kernfs_create ((int (*) __P((struct  vop_create_args *)))kernfs_enotsupp)
583 #define kernfs_mknod ((int (*) __P((struct  vop_mknod_args *)))kernfs_enotsupp)
584 #define kernfs_close ((int (*) __P((struct  vop_close_args *)))nullop)
585 #define kernfs_ioctl ((int (*) __P((struct  vop_ioctl_args *)))kernfs_enotsupp)
586 #define kernfs_select ((int (*) __P((struct  vop_select_args *)))kernfs_enotsupp)
587 #define kernfs_mmap ((int (*) __P((struct  vop_mmap_args *)))kernfs_enotsupp)
588 #define kernfs_fsync ((int (*) __P((struct  vop_fsync_args *)))nullop)
589 #define kernfs_seek ((int (*) __P((struct  vop_seek_args *)))nullop)
590 #define kernfs_remove ((int (*) __P((struct  vop_remove_args *)))kernfs_enotsupp)
591 #define kernfs_link ((int (*) __P((struct  vop_link_args *)))kernfs_enotsupp)
592 #define kernfs_rename ((int (*) __P((struct  vop_rename_args *)))kernfs_enotsupp)
593 #define kernfs_mkdir ((int (*) __P((struct  vop_mkdir_args *)))kernfs_enotsupp)
594 #define kernfs_rmdir ((int (*) __P((struct  vop_rmdir_args *)))kernfs_enotsupp)
595 #define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))kernfs_enotsupp)
596 #define kernfs_readlink \
597 	((int (*) __P((struct  vop_readlink_args *)))kernfs_enotsupp)
598 #define kernfs_abortop ((int (*) __P((struct  vop_abortop_args *)))nullop)
599 #define kernfs_lock ((int (*) __P((struct  vop_lock_args *)))nullop)
600 #define kernfs_unlock ((int (*) __P((struct  vop_unlock_args *)))nullop)
601 #define kernfs_bmap ((int (*) __P((struct  vop_bmap_args *)))kernfs_badop)
602 #define kernfs_strategy ((int (*) __P((struct  vop_strategy_args *)))kernfs_badop)
603 #define kernfs_islocked ((int (*) __P((struct  vop_islocked_args *)))nullop)
604 #define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))kernfs_enotsupp)
605 #define kernfs_blkatoff \
606 	((int (*) __P((struct  vop_blkatoff_args *)))kernfs_enotsupp)
607 #define kernfs_valloc ((int(*) __P(( \
608 		struct vnode *pvp, \
609 		int mode, \
610 		struct ucred *cred, \
611 		struct vnode **vpp))) kernfs_enotsupp)
612 #define kernfs_truncate \
613 	((int (*) __P((struct  vop_truncate_args *)))kernfs_enotsupp)
614 #define kernfs_update ((int (*) __P((struct  vop_update_args *)))kernfs_enotsupp)
615 #define kernfs_bwrite ((int (*) __P((struct  vop_bwrite_args *)))kernfs_enotsupp)
616 
617 int (**kernfs_vnodeop_p)();
618 struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = {
619 	{ &vop_default_desc, vn_default_error },
620 	{ &vop_lookup_desc, kernfs_lookup },	/* lookup */
621 	{ &vop_create_desc, kernfs_create },	/* create */
622 	{ &vop_mknod_desc, kernfs_mknod },	/* mknod */
623 	{ &vop_open_desc, kernfs_open },		/* open */
624 	{ &vop_close_desc, kernfs_close },	/* close */
625 	{ &vop_access_desc, kernfs_access },	/* access */
626 	{ &vop_getattr_desc, kernfs_getattr },	/* getattr */
627 	{ &vop_setattr_desc, kernfs_setattr },	/* setattr */
628 	{ &vop_read_desc, kernfs_read },		/* read */
629 	{ &vop_write_desc, kernfs_write },	/* write */
630 	{ &vop_ioctl_desc, kernfs_ioctl },	/* ioctl */
631 	{ &vop_select_desc, kernfs_select },	/* select */
632 	{ &vop_mmap_desc, kernfs_mmap },		/* mmap */
633 	{ &vop_fsync_desc, kernfs_fsync },	/* fsync */
634 	{ &vop_seek_desc, kernfs_seek },		/* seek */
635 	{ &vop_remove_desc, kernfs_remove },	/* remove */
636 	{ &vop_link_desc, kernfs_link },		/* link */
637 	{ &vop_rename_desc, kernfs_rename },	/* rename */
638 	{ &vop_mkdir_desc, kernfs_mkdir },	/* mkdir */
639 	{ &vop_rmdir_desc, kernfs_rmdir },	/* rmdir */
640 	{ &vop_symlink_desc, kernfs_symlink },	/* symlink */
641 	{ &vop_readdir_desc, kernfs_readdir },	/* readdir */
642 	{ &vop_readlink_desc, kernfs_readlink },	/* readlink */
643 	{ &vop_abortop_desc, kernfs_abortop },	/* abortop */
644 	{ &vop_inactive_desc, kernfs_inactive },	/* inactive */
645 	{ &vop_reclaim_desc, kernfs_reclaim },	/* reclaim */
646 	{ &vop_lock_desc, kernfs_lock },		/* lock */
647 	{ &vop_unlock_desc, kernfs_unlock },	/* unlock */
648 	{ &vop_bmap_desc, kernfs_bmap },		/* bmap */
649 	{ &vop_strategy_desc, kernfs_strategy },	/* strategy */
650 	{ &vop_print_desc, kernfs_print },	/* print */
651 	{ &vop_islocked_desc, kernfs_islocked },	/* islocked */
652 	{ &vop_advlock_desc, kernfs_advlock },	/* advlock */
653 	{ &vop_blkatoff_desc, kernfs_blkatoff },	/* blkatoff */
654 	{ &vop_valloc_desc, kernfs_valloc },	/* valloc */
655 	{ &vop_vfree_desc, kernfs_vfree },	/* vfree */
656 	{ &vop_truncate_desc, kernfs_truncate },	/* truncate */
657 	{ &vop_update_desc, kernfs_update },	/* update */
658 	{ &vop_bwrite_desc, kernfs_bwrite },	/* bwrite */
659 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
660 };
661 struct vnodeopv_desc kernfs_vnodeop_opv_desc =
662 	{ &kernfs_vnodeop_p, kernfs_vnodeop_entries };
663