xref: /netbsd-src/sys/miscfs/kernfs/kernfs_vnops.c (revision 0b9f50897e9a9c6709320fafb4c3787fddcc0a45)
1 /*
2  * Copyright (c) 1990, 1992 Jan-Simon Pendry
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Jan-Simon Pendry.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	$Id: kernfs_vnops.c,v 1.12 1993/09/07 15:41:21 ws Exp $
37  */
38 
39 /*
40  * Kernel parameter filesystem
41  */
42 
43 #include "param.h"
44 #include "systm.h"
45 #include "kernel.h"
46 #include "types.h"
47 #include "time.h"
48 #include "proc.h"
49 #include "file.h"
50 #include "vnode.h"
51 #include "stat.h"
52 #include "mount.h"
53 #include "namei.h"
54 #include "buf.h"
55 #include "miscfs/kernfs/kernfs.h"
56 
57 #include "../ufs/dir.h"		/* For readdir() XXX */
58 
59 struct kernfs_target kernfs_targets[] = {
60 /* NOTE: The name must be less than UIO_MX-16 chars in length */
61 DIR_TARGET(".",		0,		KTT_NULL,	KTM_DIR_PERMS	)
62 DIR_TARGET("..",	0,		KTT_NULL,	KTM_DIR_PERMS	)
63 REG_TARGET("copyright",	copyright,	KTT_STRING,	KTM_RO_PERMS	)
64 REG_TARGET("hostname",	0,		KTT_HOSTNAME,	KTM_RW_PERMS	)
65 REG_TARGET("hz",	&hz,		KTT_INT,	KTM_RO_PERMS	)
66 REG_TARGET("loadavg",	0,		KTT_AVENRUN,	KTM_RO_PERMS	)
67 REG_TARGET("physmem",	&physmem,	KTT_INT,	KTM_RO_PERMS	)
68 DIR_TARGET("root",	0,		KTT_NULL,	KTM_DIR_PERMS	)
69 BLK_TARGET("rootdev",	0,		KTT_NULL,	KTM_RO_PERMS	)
70 CHR_TARGET("rrootdev",	0,		KTT_NULL,	KTM_RO_PERMS	)
71 REG_TARGET("time",	0,		KTT_TIME,	KTM_RO_PERMS	)
72 REG_TARGET("version",	version,	KTT_STRING,	KTM_RO_PERMS	)
73 };
74 
75 static int nkernfs_targets = sizeof(kernfs_targets) / sizeof(kernfs_targets[0]);
76 
77 static int
78 kernfs_xread(kt, buf, len, lenp)
79 	struct kernfs_target *kt;
80 	char *buf;
81 	int len;
82 	int *lenp;
83 {
84 	int xlen;
85 
86 	switch (kt->kt_tag) {
87 	case KTT_TIME: {
88 		struct timeval tv;
89 		microtime(&tv);
90 		sprintf(buf, "%d %d\n", tv.tv_sec, tv.tv_usec);
91 		break;
92 	}
93 
94 	case KTT_INT: {
95 		int *ip = kt->kt_data;
96 		sprintf(buf, "%d\n", *ip);
97 		break;
98 	}
99 
100 	case KTT_STRING: {
101 		char *cp = kt->kt_data;
102 		int xlen = strlen(cp) + 1;
103 
104 		if (xlen >= len)
105 			return (EINVAL);
106 
107 		bcopy(cp, buf, xlen);
108 		break;
109 	}
110 
111 	case KTT_HOSTNAME: {
112 		char *cp = hostname;
113 		int xlen = hostnamelen;
114 
115 		if (xlen + 2 > len)	/* extra space for null and newline */
116 			return (EINVAL);
117 
118 		bcopy(cp, buf, xlen);	/* safer than sprintf */
119 		buf[xlen] = '\n';
120 		buf[xlen+1] = '\0';
121 		break;
122 	}
123 
124 	case KTT_AVENRUN:
125 		sprintf(buf, "%d %d %d %d\n",
126 				averunnable[0],
127 				averunnable[1],
128 				averunnable[2],
129 				FSCALE);
130 		break;
131 
132 	default:
133 		return (EINVAL);
134 	}
135 
136 	*lenp = strlen(buf);
137 	return (0);
138 }
139 
140 static int
141 kernfs_xwrite(kt, buf, len)
142 	struct kernfs_target *kt;
143 	char *buf;
144 	int len;
145 {
146 	switch (kt->kt_tag) {
147 	case KTT_HOSTNAME: {
148 		if (buf[len-1] == '\n')
149 			--len;
150 		bcopy(buf, hostname, len);
151 		/* kernfs_write set buf[value_passed_as_len] = \0.
152 		 * therefore, buf len (hostnamelen) = len.
153 		 */
154 		hostnamelen = len;
155 		hostname[hostnamelen] = '\0';	/* null end of string. */
156 		return (0);
157 	}
158 
159 	default:
160 		return (EIO);
161 	}
162 }
163 
164 /*
165  * vp is the current namei directory
166  * ndp is the name to locate in that directory...
167  */
168 kernfs_lookup(dvp, ndp, p)
169 	struct vnode *dvp;
170 	struct nameidata *ndp;
171 	struct proc *p;
172 {
173 	char *pname = ndp->ni_ptr;
174 	int error = ENOENT;
175 	int i;
176 	struct vnode *fvp;
177 
178 #ifdef KERNFS_DIAGNOSTIC
179 	printf("kernfs_lookup(%s)\n", pname);
180 #endif
181 	if (ndp->ni_namelen == 1 && *pname == '.') {
182 		ndp->ni_dvp = dvp;
183 		ndp->ni_vp = dvp;
184 		VREF(dvp);
185 		/*VOP_LOCK(dvp);*/
186 		return (0);
187 	}
188 
189 	if (ndp->ni_namelen == 4 && bcmp(pname, "root", 4) == 0) {
190 		ndp->ni_dvp = dvp;
191 		ndp->ni_vp = rootdir;
192 		VREF(rootdir);
193 		VOP_LOCK(rootdir);
194 		return (0);
195 	}
196 
197 	/*
198 	 * /kern/rootdev is the root device
199 	 */
200 	if (ndp->ni_namelen == 7 && bcmp(pname, "rootdev", 7) == 0) {
201 		if (vfinddev(rootdev, VBLK, &fvp))
202 			return (ENXIO);
203 		ndp->ni_dvp = dvp;
204 		ndp->ni_vp = fvp;
205 		VREF(fvp);
206 		VOP_LOCK(fvp);
207 		return (0);
208 	}
209 
210 	/*
211 	 * /kern/rrootdev is the root device
212 	 */
213 	if (ndp->ni_namelen == 8 && bcmp(pname, "rrootdev", 7) == 0) {
214 		ndp->ni_dvp = dvp;
215 		ndp->ni_vp = rrootdevvp;
216 		VREF(rrootdevvp);
217 		VOP_LOCK(rrootdevvp);
218 		return (0);
219 	}
220 
221 	for (i = 0; i < nkernfs_targets; i++) {
222 		struct kernfs_target *kt = &kernfs_targets[i];
223 		if (ndp->ni_namelen == strlen(kt->kt_name) &&
224 		    bcmp(kt->kt_name, pname, ndp->ni_namelen) == 0) {
225 			error = 0;
226 			break;
227 		}
228 	}
229 
230 #ifdef KERNFS_DIAGNOSTIC
231 	printf("kernfs_lookup: i = %d, error = %d\n", i, error);
232 #endif
233 
234 	if (error)
235 		goto bad;
236 
237 #ifdef KERNFS_DIAGNOSTIC
238 	printf("kernfs_lookup: allocate new vnode\n");
239 #endif
240 	error = getnewvnode(VT_KERNFS, dvp->v_mount, &kernfs_vnodeops, &fvp);
241 	if (error)
242 		goto bad;
243 	VTOKERN(fvp)->kf_kt = &kernfs_targets[i];
244 	fvp->v_type = VTOKERN(fvp)->kf_kt->kt_vtype;
245 	ndp->ni_dvp = dvp;
246 	ndp->ni_vp = fvp;
247 #ifdef KERNFS_DIAGNOSTIC
248 	printf("kernfs_lookup: newvp = %x\n", fvp);
249 #endif
250 	return (0);
251 
252 bad:;
253 	ndp->ni_dvp = dvp;
254 	ndp->ni_vp = NULL;
255 #ifdef KERNFS_DIAGNOSTIC
256 	printf("kernfs_lookup: error = %d\n", error);
257 #endif
258 	return (error);
259 }
260 
261 kernfs_open(vp, mode, cred, p)
262 	struct vnode *vp;
263 	int mode;
264 	struct ucred *cred;
265 	struct proc *p;
266 {
267 	/* if access succeeded, this always does, too */
268 
269 	return (0);
270 }
271 
272 /*
273  * Check mode permission on target pointer. Mode is READ, WRITE or EXEC.
274  * The mode is shifted to select the owner/group/other fields. The
275  * super user is granted all permissions.
276  */
277 kernfs_access(vp, mode, cred, p)
278 	struct vnode *vp;
279 	register int mode;
280 	struct ucred *cred;
281 	struct proc *p;
282 {
283 	struct kernfs_target *kt = VTOKERN(vp)->kf_kt;
284 	register gid_t *gp;
285 	int i, error;
286 
287 #ifdef KERN_DIAGNOSTIC
288 	if (!VOP_ISLOCKED(vp)) {
289 		vprint("kernfs_access: not locked", vp);
290 		panic("kernfs_access: not locked");
291 	}
292 #endif
293 	/*
294 	 * If you're the super-user, you always get access.
295 	 */
296 	if (cred->cr_uid == 0)
297 		return (0);
298 	/*
299 	 * Access check is based on only one of owner, group, public.
300 	 * If not owner, then check group. If not a member of the
301 	 * group, then check public access.
302 	 */
303 	if (cred->cr_uid != /* kt->kt_uid XXX */ 0) {
304 		mode >>= 3;
305 		gp = cred->cr_groups;
306 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
307 			if (/* kt->kt_gid XXX */ 0 == *gp)
308 				goto found;
309 		mode >>= 3;
310 found:
311 		;
312 	}
313 	if ((kt->kt_perms & mode) == mode)
314 		return (0);
315 	return (EACCES);
316 }
317 
318 kernfs_getattr(vp, vap, cred, p)
319 	struct vnode *vp;
320 	struct vattr *vap;
321 	struct ucred *cred;
322 	struct proc *p;
323 {
324 	int error = 0;
325 	char strbuf[KSTRING];
326 	struct kernfs_target *kt = VTOKERN(vp)->kf_kt;
327 
328 	bzero((caddr_t) vap, sizeof(*vap));
329 	vattr_null(vap);
330 	vap->va_uid = kt->kt_uid;
331 	vap->va_gid = kt->kt_gid;
332 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
333 	/* vap->va_qsize = 0; */
334 	vap->va_blocksize = DEV_BSIZE;
335 	microtime(&vap->va_atime);
336 	vap->va_mtime = vap->va_atime;
337 	vap->va_ctime = vap->va_ctime;
338 	vap->va_gen = 0;
339 	vap->va_flags = 0;
340 	vap->va_rdev = 0;
341 	/* vap->va_qbytes = 0; */
342 	vap->va_bytes = 0;
343 	vap->va_type = kt->kt_vtype;
344 	vap->va_mode = kt->kt_perms;
345 
346 	if (vp->v_flag & VROOT) {
347 #ifdef KERNFS_DIAGNOSTIC
348 		printf("kernfs_getattr: stat rootdir\n");
349 #endif
350 		vap->va_nlink = 2;
351 		vap->va_fileid = 2;
352 		vap->va_size = DEV_BSIZE;
353 	} else {
354 #ifdef KERNFS_DIAGNOSTIC
355 		printf("kernfs_getattr: stat target %s\n", kt->kt_name);
356 #endif
357 		vap->va_nlink = 1;
358 		vap->va_fileid = 3 + (kt - kernfs_targets) / sizeof(*kt);
359 		error = kernfs_xread(kt, strbuf, sizeof(strbuf), &vap->va_size);
360 	}
361 
362 	vp->v_type = vap->va_type;
363 #ifdef KERNFS_DIAGNOSTIC
364 	printf("kernfs_getattr: return error %d\n", error);
365 #endif
366 	return (error);
367 }
368 
369 
370 /*
371  * Change the mode on a file.
372  */
373 kernfs_chmod1(vp, mode, p)
374 	register struct vnode *vp;
375 	register int mode;
376 	struct proc *p;
377 {
378 	register struct ucred *cred = p->p_ucred;
379 	register struct kernfs_target *kt = VTOKERN(vp)->kf_kt;
380 	int error;
381 
382 	if ((mode & kt->kt_maxperms) != mode)	/* can't set ro var to rw */
383 		return (EPERM);
384 
385 	if (cred->cr_uid != kt->kt_uid &&
386 	    (error = suser(cred, &p->p_acflag)))
387 		return (error);
388 	if (cred->cr_uid) {
389 		if (vp->v_type != VDIR && (mode & S_ISVTX))
390 			return (EFTYPE);
391 		if (!groupmember(kt->kt_gid, cred) && (mode & S_ISGID))
392 			return (EPERM);
393 	}
394 	kt->kt_perms &= ~07777;
395 	kt->kt_perms |= mode & 07777;
396 /*	ip->i_flag |= ICHG;*/
397 	return (0);
398 }
399 
400 /*
401  * Perform chown operation on kernfs_target kt
402  */
403 kernfs_chown1(vp, uid, gid, p)
404 	register struct vnode *vp;
405 	uid_t uid;
406 	gid_t gid;
407 	struct proc *p;
408 {
409 	register struct kernfs_target *kt = VTOKERN(vp)->kf_kt;
410 	register struct ucred *cred = p->p_ucred;
411 	uid_t ouid;
412 	gid_t ogid;
413 	int error = 0;
414 
415 	if (uid == (u_short)VNOVAL)
416 		uid = kt->kt_uid;
417 	if (gid == (u_short)VNOVAL)
418 		gid = kt->kt_gid;
419 	/*
420 	 * If we don't own the file, are trying to change the owner
421 	 * of the file, or are not a member of the target group,
422 	 * the caller must be superuser or the call fails.
423 	 */
424 	if ((cred->cr_uid != kt->kt_uid || uid != kt->kt_uid ||
425 	    !groupmember((gid_t)gid, cred)) &&
426 	    (error = suser(cred, &p->p_acflag)))
427 		return (error);
428 	ouid = kt->kt_uid;
429 	ogid = kt->kt_gid;
430 
431 	kt->kt_uid = uid;
432 	kt->kt_gid = gid;
433 
434 /*	if (ouid != uid || ogid != gid)
435 		ip->i_flag |= ICHG;*/
436 	if (ouid != uid && cred->cr_uid != 0)
437 		kt->kt_perms &= ~S_ISUID;
438 	if (ogid != gid && cred->cr_uid != 0)
439 		kt->kt_perms &= ~S_ISGID;
440 	return (0);
441 }
442 
443 /*
444  * Set attribute vnode op. called from several syscalls
445  */
446 kernfs_setattr(vp, vap, cred, p)
447 	struct vnode *vp;
448 	struct vattr *vap;
449 	struct ucred *cred;
450 	struct proc *p;
451 {
452 	int error = 0;
453 
454 	/*
455 	 * Check for unsetable attributes.
456 	 */
457 	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
458 	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
459 	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
460 	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
461 		return (EINVAL);
462 	}
463 	/*
464 	 * Go through the fields and update iff not VNOVAL.
465 	 */
466 	if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL)
467 		if (error = kernfs_chown1(vp, vap->va_uid, vap->va_gid, p))
468 			return (error);
469 	if (vap->va_size != VNOVAL) {
470 		if (vp->v_type == VDIR)
471 			return (EISDIR);
472 		/* else just nod and smile... */
473 	}
474 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
475 /*		if (cred->cr_uid != ip->i_uid &&
476 		    (error = suser(cred, &p->p_acflag)))
477 			return (error);
478 		if (vap->va_atime.tv_sec != VNOVAL)
479 			ip->i_flag |= IACC;
480 		if (vap->va_mtime.tv_sec != VNOVAL)
481 			ip->i_flag |= IUPD;
482 		ip->i_flag |= ICHG;
483 		if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1))
484 			return (error);
485 */
486 	}
487 	if (vap->va_mode != (u_short)VNOVAL)
488 		error = kernfs_chmod1(vp, (int)vap->va_mode, p);
489 	if (vap->va_flags != VNOVAL) {
490 /*		if (cred->cr_uid != ip->i_uid &&
491 		    (error = suser(cred, &p->p_acflag)))
492 			return (error);
493 		if (cred->cr_uid == 0) {
494 			ip->i_flags = vap->va_flags;
495 		} else {
496 			ip->i_flags &= 0xffff0000;
497 			ip->i_flags |= (vap->va_flags & 0xffff);
498 		}
499 		ip->i_flag |= ICHG;
500 */
501 	}
502 	return (error);
503 }
504 
505 static int
506 kernfs_read(vp, uio, ioflag, cred)
507 	struct vnode *vp;
508 	struct uio *uio;
509 	int ioflag;
510 	struct ucred *cred;
511 {
512 	struct kernfs_target *kt = VTOKERN(vp)->kf_kt;
513 	char strbuf[KSTRING];
514 	int off = uio->uio_offset;
515 	int len = 0;
516 	char *cp = strbuf;
517 	int error;
518 #ifdef KERNFS_DIAGNOSTIC
519 	printf("kern_read %s\n", kt->kt_name);
520 #endif
521 
522 	error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len);
523 	if (error)
524 		return (error);
525 	cp = strbuf + off;
526 	len -= off;
527 	return (uiomove(cp, len, uio));
528 }
529 
530 static int
531 kernfs_write(vp, uio, ioflag, cred)
532 	struct vnode *vp;
533 	struct uio *uio;
534 	int ioflag;
535 	struct ucred *cred;
536 {
537 	struct kernfs_target *kt = VTOKERN(vp)->kf_kt;
538 	char strbuf[KSTRING];
539 	int len = uio->uio_resid;
540 	char *cp = strbuf;
541 	int xlen;
542 	int error;
543 
544 	if (uio->uio_offset != 0)
545 		return (EINVAL);
546 
547 	xlen = min(uio->uio_resid, KSTRING-1);
548 	error = uiomove(strbuf, xlen, uio);
549 	if (error)
550 		return (error);
551 
552 	if (uio->uio_resid != 0)
553 		return (EIO);
554 
555 	strbuf[xlen] = '\0';
556 	return (kernfs_xwrite(kt, strbuf, xlen));
557 }
558 
559 kernfs_readdir(vp, uio, cred, eofflagp, cookies, ncookies)
560 	struct vnode *vp;
561 	struct uio *uio;
562 	struct ucred *cred;
563 	int *eofflagp;
564 	u_int *cookies;
565 	int ncookies;
566 {
567 	struct filedesc *fdp;
568 	int i;
569 	int error;
570 
571 	i = uio->uio_offset / UIO_MX;
572 	error = 0;
573 	while (uio->uio_resid > 0 && (!cookies || ncookies > 0)) {
574 #ifdef KERNFS_DIAGNOSTIC
575 		printf("kernfs_readdir: i = %d\n", i);
576 #endif
577 		if (i >= nkernfs_targets) {
578 			*eofflagp = 1;
579 			break;
580 		}
581 		{
582 			struct direct d;
583 			struct direct *dp = &d;
584 			struct kernfs_target *kt = &kernfs_targets[i];
585 
586 			bzero((caddr_t) dp, UIO_MX);
587 
588 			dp->d_namlen = strlen(kt->kt_name);
589 			bcopy(kt->kt_name, dp->d_name, dp->d_namlen+1);
590 
591 #ifdef KERNFS_DIAGNOSTIC
592 			printf("kernfs_readdir: name = %s, len = %d\n",
593 					dp->d_name, dp->d_namlen);
594 #endif
595 			/*
596 			 * Fill in the remaining fields
597 			 */
598 			dp->d_reclen = UIO_MX;
599 			dp->d_ino = i + 3;
600 			/*
601 			 * And ship to userland
602 			 */
603 			error = uiomove((caddr_t) dp, UIO_MX, uio);
604 			if (error)
605 				break;
606 			if (cookies) {
607 				*cookies = (i + 1) * UIO_MX;
608 				ncookies--;
609 			}
610 		}
611 		i++;
612 	}
613 
614 	uio->uio_offset = i * UIO_MX;
615 
616 	return (error);
617 }
618 
619 kernfs_inactive(vp, p)
620 	struct vnode *vp;
621 	struct proc *p;
622 {
623 	/*
624 	 * Clear out the v_type field to avoid
625 	 * nasty things happening in vgone().
626 	 */
627 	vp->v_type = VNON;
628 #ifdef KERNFS_DIAGNOSTIC
629 	printf("kernfs_inactive(%x)\n", vp);
630 #endif
631 	return (0);
632 }
633 
634 /*
635  * Print out the contents of a kernfs vnode.
636  */
637 /* ARGSUSED */
638 void
639 kernfs_print(vp)
640 	struct vnode *vp;
641 {
642 	printf("tag VT_KERNFS, kernfs vnode\n");
643 }
644 
645 /*
646  * kernfs vnode unsupported operation
647  */
648 kernfs_enotsupp()
649 {
650 	return (EOPNOTSUPP);
651 }
652 
653 /*
654  * kernfs "should never get here" operation
655  */
656 kernfs_badop()
657 {
658 	panic("kernfs: bad op");
659 	/* NOTREACHED */
660 }
661 
662 /*
663  * kernfs vnode null operation
664  */
665 kernfs_nullop()
666 {
667 	return (0);
668 }
669 
670 #define kernfs_create ((int (*) __P(( \
671 		struct nameidata *ndp, \
672 		struct vattr *vap, \
673 		struct proc *p))) kernfs_enotsupp)
674 #define kernfs_mknod ((int (*) __P(( \
675 		struct nameidata *ndp, \
676 		struct vattr *vap, \
677 		struct ucred *cred, \
678 		struct proc *p))) kernfs_enotsupp)
679 #define kernfs_close ((int (*) __P(( \
680 		struct vnode *vp, \
681 		int fflag, \
682 		struct ucred *cred, \
683 		struct proc *p))) nullop)
684 #define	kernfs_ioctl ((int (*) __P(( \
685 		struct vnode *vp, \
686 		int command, \
687 		caddr_t data, \
688 		int fflag, \
689 		struct ucred *cred, \
690 		struct proc *p))) kernfs_enotsupp)
691 #define	kernfs_select ((int (*) __P(( \
692 		struct vnode *vp, \
693 		int which, \
694 		int fflags, \
695 		struct ucred *cred, \
696 		struct proc *p))) kernfs_enotsupp)
697 #define kernfs_mmap ((int (*) __P(( \
698 		struct vnode *vp, \
699 		int fflags, \
700 		struct ucred *cred, \
701 		struct proc *p))) kernfs_enotsupp)
702 #define kernfs_fsync ((int (*) __P(( \
703 		struct vnode *vp, \
704 		int fflags, \
705 		struct ucred *cred, \
706 		int waitfor, \
707 		struct proc *p))) nullop)
708 #define kernfs_seek ((int (*) __P(( \
709 		struct vnode *vp, \
710 		off_t oldoff, \
711 		off_t newoff, \
712 		struct ucred *cred))) nullop)
713 #define kernfs_remove ((int (*) __P(( \
714 		struct nameidata *ndp, \
715 		struct proc *p))) kernfs_enotsupp)
716 #define kernfs_link ((int (*) __P(( \
717 		struct vnode *vp, \
718 		struct nameidata *ndp, \
719 		struct proc *p))) kernfs_enotsupp)
720 #define kernfs_rename ((int (*) __P(( \
721 		struct nameidata *fndp, \
722 		struct nameidata *tdnp, \
723 		struct proc *p))) kernfs_enotsupp)
724 #define kernfs_mkdir ((int (*) __P(( \
725 		struct nameidata *ndp, \
726 		struct vattr *vap, \
727 		struct proc *p))) kernfs_enotsupp)
728 #define kernfs_rmdir ((int (*) __P(( \
729 		struct nameidata *ndp, \
730 		struct proc *p))) kernfs_enotsupp)
731 #define kernfs_symlink ((int (*) __P(( \
732 		struct nameidata *ndp, \
733 		struct vattr *vap, \
734 		char *target, \
735 		struct proc *p))) kernfs_enotsupp)
736 #define kernfs_readlink ((int (*) __P(( \
737 		struct vnode *vp, \
738 		struct uio *uio, \
739 		struct ucred *cred))) kernfs_enotsupp)
740 #define kernfs_abortop ((int (*) __P(( \
741 		struct nameidata *ndp))) nullop)
742 #ifdef KERNFS_DIAGNOSTIC
743 int kernfs_reclaim(vp)
744 struct vnode *vp;
745 {
746 	printf("kernfs_reclaim(%x)\n", vp);
747 	return (0);
748 }
749 #else
750 #define kernfs_reclaim ((int (*) __P(( \
751 		struct vnode *vp))) nullop)
752 #endif
753 #define	kernfs_lock ((int (*) __P(( \
754 		struct vnode *vp))) nullop)
755 #define kernfs_unlock ((int (*) __P(( \
756 		struct vnode *vp))) nullop)
757 #define	kernfs_bmap ((int (*) __P(( \
758 		struct vnode *vp, \
759 		daddr_t bn, \
760 		struct vnode **vpp, \
761 		daddr_t *bnp))) kernfs_badop)
762 #define	kernfs_strategy ((int (*) __P(( \
763 		struct buf *bp))) kernfs_badop)
764 #define kernfs_islocked ((int (*) __P(( \
765 		struct vnode *vp))) nullop)
766 #define kernfs_advlock ((int (*) __P(( \
767 		struct vnode *vp, \
768 		caddr_t id, \
769 		int op, \
770 		struct flock *fl, \
771 		int flags))) kernfs_enotsupp)
772 
773 struct vnodeops kernfs_vnodeops = {
774 	kernfs_lookup,	/* lookup */
775 	kernfs_create,	/* create */
776 	kernfs_mknod,	/* mknod */
777 	kernfs_open,	/* open */
778 	kernfs_close,	/* close */
779 	kernfs_access,	/* access */
780 	kernfs_getattr,	/* getattr */
781 	kernfs_setattr,	/* setattr */
782 	kernfs_read,	/* read */
783 	kernfs_write,	/* write */
784 	kernfs_ioctl,	/* ioctl */
785 	kernfs_select,	/* select */
786 	kernfs_mmap,	/* mmap */
787 	kernfs_fsync,	/* fsync */
788 	kernfs_seek,	/* seek */
789 	kernfs_remove,	/* remove */
790 	kernfs_link,	/* link */
791 	kernfs_rename,	/* rename */
792 	kernfs_mkdir,	/* mkdir */
793 	kernfs_rmdir,	/* rmdir */
794 	kernfs_symlink,	/* symlink */
795 	kernfs_readdir,	/* readdir */
796 	kernfs_readlink,	/* readlink */
797 	kernfs_abortop,	/* abortop */
798 	kernfs_inactive,	/* inactive */
799 	kernfs_reclaim,	/* reclaim */
800 	kernfs_lock,	/* lock */
801 	kernfs_unlock,	/* unlock */
802 	kernfs_bmap,	/* bmap */
803 	kernfs_strategy,	/* strategy */
804 	kernfs_print,	/* print */
805 	kernfs_islocked,	/* islocked */
806 	kernfs_advlock,	/* advlock */
807 };
808