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