155344Spendry /*
263233Sbostic  * Copyright (c) 1992, 1993
363233Sbostic  *	The Regents of the University of California.  All rights reserved.
455344Spendry  *
555344Spendry  * This code is derived from software donated to Berkeley by
655344Spendry  * Jan-Simon Pendry.
755344Spendry  *
855344Spendry  * %sccs.include.redist.c%
955344Spendry  *
10*67365Smckusick  *	@(#)kernfs_vnops.c	8.7 (Berkeley) 06/04/94
1155344Spendry  */
1255344Spendry 
1355344Spendry /*
1455344Spendry  * Kernel parameter filesystem (/kern)
1555344Spendry  */
1655344Spendry 
1755344Spendry #include <sys/param.h>
1855344Spendry #include <sys/systm.h>
1955344Spendry #include <sys/kernel.h>
2055344Spendry #include <sys/vmmeter.h>
2155344Spendry #include <sys/types.h>
2255344Spendry #include <sys/time.h>
2355344Spendry #include <sys/proc.h>
2455344Spendry #include <sys/vnode.h>
2555344Spendry #include <sys/malloc.h>
2655344Spendry #include <sys/file.h>
2755344Spendry #include <sys/stat.h>
2855344Spendry #include <sys/mount.h>
2955344Spendry #include <sys/namei.h>
3055344Spendry #include <sys/buf.h>
3155344Spendry #include <sys/dirent.h>
3255344Spendry #include <miscfs/kernfs/kernfs.h>
3355344Spendry 
3455344Spendry #define KSTRING	256		/* Largest I/O available via this filesystem */
3555344Spendry #define	UIO_MX 32
3655344Spendry 
3755356Spendry #define	READ_MODE	(S_IRUSR|S_IRGRP|S_IROTH)
3855356Spendry #define	WRITE_MODE	(S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)
3955356Spendry #define DIR_MODE	(S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
4055356Spendry 
4155344Spendry struct kern_target {
4255344Spendry 	char *kt_name;
4355344Spendry 	void *kt_data;
4455344Spendry #define	KTT_NULL 1
4555344Spendry #define	KTT_TIME 5
4655344Spendry #define KTT_INT	17
4755344Spendry #define	KTT_STRING 31
4855344Spendry #define KTT_HOSTNAME 47
4955344Spendry #define KTT_AVENRUN 53
5055344Spendry 	int kt_tag;
5155344Spendry 	int kt_rw;
5255344Spendry 	int kt_vtype;
5355344Spendry } kern_targets[] = {
5455344Spendry /* NOTE: The name must be less than UIO_MX-16 chars in length */
5555344Spendry 	/* name		data		tag		ro/rw */
5655356Spendry 	{ ".",		0,		KTT_NULL,	VREAD,		VDIR },
5755356Spendry 	{ "..",		0,		KTT_NULL,	VREAD,		VDIR },
5855358Spendry 	{ "boottime",	&boottime.tv_sec, KTT_INT,	VREAD,		VREG },
5955356Spendry 	{ "copyright",	copyright,	KTT_STRING,	VREAD,		VREG },
6055356Spendry 	{ "hostname",	0,		KTT_HOSTNAME,	VREAD|VWRITE,	VREG },
6155356Spendry 	{ "hz",		&hz,		KTT_INT,	VREAD,		VREG },
6255356Spendry 	{ "loadavg",	0,		KTT_AVENRUN,	VREAD,		VREG },
6355356Spendry 	{ "pagesize",	&cnt.v_page_size, KTT_INT,	VREAD,		VREG },
6455356Spendry 	{ "physmem",	&physmem,	KTT_INT,	VREAD,		VREG },
6559556Spendry #if 0
6655356Spendry 	{ "root",	0,		KTT_NULL,	VREAD,		VDIR },
6759556Spendry #endif
6855356Spendry 	{ "rootdev",	0,		KTT_NULL,	VREAD,		VBLK },
6955356Spendry 	{ "rrootdev",	0,		KTT_NULL,	VREAD,		VCHR },
7055356Spendry 	{ "time",	0,		KTT_TIME,	VREAD,		VREG },
7155356Spendry 	{ "version",	version,	KTT_STRING,	VREAD,		VREG },
7255344Spendry };
7355344Spendry 
7455344Spendry static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]);
7555344Spendry 
7655344Spendry static int
7755344Spendry kernfs_xread(kt, buf, len, lenp)
7855344Spendry 	struct kern_target *kt;
7955344Spendry 	char *buf;
8055344Spendry 	int len;
8155344Spendry 	int *lenp;
8255344Spendry {
8355344Spendry 	switch (kt->kt_tag) {
8455344Spendry 	case KTT_TIME: {
8555344Spendry 		struct timeval tv;
8655344Spendry 		microtime(&tv);
8755344Spendry 		sprintf(buf, "%d %d\n", tv.tv_sec, tv.tv_usec);
8855344Spendry 		break;
8955344Spendry 	}
9055344Spendry 
9155344Spendry 	case KTT_INT: {
9255344Spendry 		int *ip = kt->kt_data;
9355344Spendry 		sprintf(buf, "%d\n", *ip);
9455344Spendry 		break;
9555344Spendry 	}
9655344Spendry 
9755344Spendry 	case KTT_STRING: {
9855344Spendry 		char *cp = kt->kt_data;
9955344Spendry 		int xlen = strlen(cp) + 1;
10055344Spendry 
10155344Spendry 		if (xlen >= len)
10255344Spendry 			return (EINVAL);
10355344Spendry 
10455344Spendry 		bcopy(cp, buf, xlen);
10555344Spendry 		break;
10655344Spendry 	}
10755344Spendry 
10855344Spendry 	case KTT_HOSTNAME: {
10955344Spendry 		char *cp = hostname;
11055344Spendry 		int xlen = hostnamelen;
11155344Spendry 
11259556Spendry 		if (xlen >= (len-2))
11355344Spendry 			return (EINVAL);
11455344Spendry 
11559556Spendry 		bcopy(cp, buf, xlen);
11659556Spendry 		buf[xlen] = '\n';
11759556Spendry 		buf[xlen+1] = '\0';
11855344Spendry 		break;
11955344Spendry 	}
12055344Spendry 
12155344Spendry 	case KTT_AVENRUN:
12255344Spendry 		sprintf(buf, "%ld %ld %ld %ld\n",
12355344Spendry 				averunnable.ldavg[0],
12455344Spendry 				averunnable.ldavg[1],
12555344Spendry 				averunnable.ldavg[2],
12655344Spendry 				averunnable.fscale);
12755344Spendry 		break;
12855344Spendry 
12955344Spendry 	default:
13055344Spendry 		return (EINVAL);
13155344Spendry 	}
13255344Spendry 
13355344Spendry 	*lenp = strlen(buf);
13455344Spendry 	return (0);
13555344Spendry }
13655344Spendry 
13755344Spendry static int
13855344Spendry kernfs_xwrite(kt, buf, len)
13955344Spendry 	struct kern_target *kt;
14055344Spendry 	char *buf;
14155344Spendry 	int len;
14255344Spendry {
14355344Spendry 	switch (kt->kt_tag) {
14455344Spendry 	case KTT_HOSTNAME: {
14555344Spendry 		if (buf[len-1] == '\n')
14655344Spendry 			--len;
14755344Spendry 		bcopy(buf, hostname, len);
14859556Spendry 		hostname[len] = '\0';
14959556Spendry 		hostnamelen = len;
15055344Spendry 		return (0);
15155344Spendry 	}
15255344Spendry 
15355344Spendry 	default:
15455344Spendry 		return (EIO);
15555344Spendry 	}
15655344Spendry }
15755344Spendry 
15855344Spendry 
15955344Spendry /*
16055344Spendry  * vp is the current namei directory
16155344Spendry  * ndp is the name to locate in that directory...
16255344Spendry  */
16355344Spendry kernfs_lookup(ap)
16455344Spendry 	struct vop_lookup_args /* {
16555344Spendry 		struct vnode * a_dvp;
16655344Spendry 		struct vnode ** a_vpp;
16755344Spendry 		struct componentname * a_cnp;
16855344Spendry 	} */ *ap;
16955344Spendry {
17055344Spendry 	struct vnode **vpp = ap->a_vpp;
17155344Spendry 	struct vnode *dvp = ap->a_dvp;
17255344Spendry 	struct componentname *cnp = ap->a_cnp;
17365446Sbostic 	struct vnode *fvp;
17465446Sbostic 	int error, i;
17555344Spendry 	char *pname;
17655344Spendry 
17755344Spendry #ifdef KERNFS_DIAGNOSTIC
17855344Spendry 	printf("kernfs_lookup(%x)\n", ap);
17955344Spendry 	printf("kernfs_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp);
18055344Spendry #endif
18155344Spendry 	pname = cnp->cn_nameptr;
18255344Spendry #ifdef KERNFS_DIAGNOSTIC
18355344Spendry 	printf("kernfs_lookup(%s)\n", pname);
18455344Spendry #endif
18555344Spendry 	if (cnp->cn_namelen == 1 && *pname == '.') {
18655344Spendry 		*vpp = dvp;
18755350Spendry 		VREF(dvp);
18855344Spendry 		/*VOP_LOCK(dvp);*/
18955344Spendry 		return (0);
19055344Spendry 	}
19155344Spendry 
19259556Spendry #if 0
19355344Spendry 	if (cnp->cn_namelen == 4 && bcmp(pname, "root", 4) == 0) {
19455344Spendry 		*vpp = rootdir;
19555344Spendry 		VREF(rootdir);
19655344Spendry 		VOP_LOCK(rootdir);
19755344Spendry 		return (0);
19855344Spendry 	}
19959556Spendry #endif
20055350Spendry 
20155344Spendry 	/*
20255344Spendry 	 * /kern/rootdev is the root device
20355344Spendry 	 */
20455344Spendry 	if (cnp->cn_namelen == 7 && bcmp(pname, "rootdev", 7) == 0) {
20555344Spendry 		*vpp = rootvp;
20655344Spendry 		VREF(rootvp);
20755344Spendry 		VOP_LOCK(rootvp);
20855344Spendry 		return (0);
20955344Spendry 	}
21055344Spendry 
21155356Spendry 	/*
21255356Spendry 	 * /kern/rrootdev is the raw root device
21355356Spendry 	 */
21455356Spendry 	if (cnp->cn_namelen == 8 && bcmp(pname, "rrootdev", 8) == 0) {
21555356Spendry 		if (rrootvp) {
21655356Spendry 			*vpp = rrootvp;
21755356Spendry 			VREF(rrootvp);
21855356Spendry 			VOP_LOCK(rrootvp);
21955356Spendry 			return (0);
22055356Spendry 		}
22155356Spendry 		error = ENXIO;
22255356Spendry 		goto bad;
22355356Spendry 	}
22455356Spendry 
22555355Spendry 	error = ENOENT;
22655355Spendry 
22755344Spendry 	for (i = 0; i < nkern_targets; i++) {
22855344Spendry 		struct kern_target *kt = &kern_targets[i];
22955344Spendry 		if (cnp->cn_namelen == strlen(kt->kt_name) &&
23055344Spendry 		    bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) {
23155344Spendry 			error = 0;
23255344Spendry 			break;
23355344Spendry 		}
23455344Spendry 	}
23555344Spendry 
23655344Spendry #ifdef KERNFS_DIAGNOSTIC
23755344Spendry 	printf("kernfs_lookup: i = %d, error = %d\n", i, error);
23855344Spendry #endif
23955344Spendry 
24055344Spendry 	if (error)
24155344Spendry 		goto bad;
24255344Spendry 
24355344Spendry #ifdef KERNFS_DIAGNOSTIC
24455344Spendry 	printf("kernfs_lookup: allocate new vnode\n");
24555344Spendry #endif
24665380Spendry 	error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p, &fvp);
24755344Spendry 	if (error)
24855344Spendry 		goto bad;
24955344Spendry 	MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, M_WAITOK);
25055344Spendry 	VTOKERN(fvp)->kf_kt = &kern_targets[i];
25155344Spendry 	fvp->v_type = VTOKERN(fvp)->kf_kt->kt_vtype;
25255344Spendry 	*vpp = fvp;
25355344Spendry #ifdef KERNFS_DIAGNOSTIC
25455344Spendry 	printf("kernfs_lookup: newvp = %x\n", fvp);
25555344Spendry #endif
25655344Spendry 	return (0);
25755344Spendry 
25855344Spendry bad:;
25955344Spendry 	*vpp = NULL;
26055344Spendry #ifdef KERNFS_DIAGNOSTIC
26155344Spendry 	printf("kernfs_lookup: error = %d\n", error);
26255344Spendry #endif
26355344Spendry 	return (error);
26455344Spendry }
26555344Spendry 
26655344Spendry kernfs_open(ap)
26755344Spendry 	struct vop_open_args /* {
26855344Spendry 		struct vnode *a_vp;
26955344Spendry 		int  a_mode;
27055344Spendry 		struct ucred *a_cred;
27155344Spendry 		struct proc *a_p;
27255344Spendry 	} */ *ap;
27355344Spendry {
27455344Spendry 	struct vnode *vp = ap->a_vp;
27555344Spendry 
27655344Spendry 	/*
27755344Spendry 	 * Can always open the root (modulo perms)
27855344Spendry 	 */
27955344Spendry 	if (vp->v_flag & VROOT)
28055344Spendry 		return (0);
28155344Spendry 
28255344Spendry #ifdef KERNFS_DIAGNOSTIC
28355344Spendry 	printf("kernfs_open, mode = %x, file = %s\n",
28455344Spendry 			ap->a_mode, VTOKERN(vp)->kf_kt->kt_name);
28555344Spendry #endif
28655344Spendry 
28755496Spendry 	if ((ap->a_mode & FWRITE) && !(VTOKERN(vp)->kf_kt->kt_rw & VWRITE))
28859556Spendry 		return (EOPNOTSUPP);
28955344Spendry 
29055344Spendry 	return (0);
29155344Spendry }
29255344Spendry 
29355344Spendry static int
29455344Spendry kernfs_access(ap)
29555344Spendry 	struct vop_access_args /* {
29655344Spendry 		struct vnode *a_vp;
29755344Spendry 		int  a_mode;
29855344Spendry 		struct ucred *a_cred;
29955344Spendry 		struct proc *a_p;
30055344Spendry 	} */ *ap;
30155344Spendry {
30255344Spendry 	struct vnode *vp = ap->a_vp;
30355344Spendry 	struct ucred *cred = ap->a_cred;
30455344Spendry 	mode_t mode = ap->a_mode;
30555344Spendry 
30655344Spendry 	if (mode & VEXEC) {
30755344Spendry 		if (vp->v_flag & VROOT)
30855344Spendry 			return (0);
30955344Spendry 		return (EACCES);
31055344Spendry 	}
31155344Spendry 
31255344Spendry 	if (cred->cr_uid == 0) {
31356497Smckusick 		if ((vp->v_flag & VROOT) == 0) {
31456497Smckusick 			struct kern_target *kt = VTOKERN(vp)->kf_kt;
31556497Smckusick 
31656497Smckusick 			if ((mode & VWRITE) && !(kt->kt_rw & VWRITE))
31756497Smckusick 				return (EROFS);
31856497Smckusick 		}
31955344Spendry 		return (0);
32055344Spendry 	}
32155344Spendry 
32255344Spendry 	if (mode & VWRITE)
32355344Spendry 		return (EACCES);
32455344Spendry 
32555344Spendry 	return (0);
32655344Spendry }
32755344Spendry 
32855344Spendry 
32955344Spendry kernfs_getattr(ap)
33055344Spendry 	struct vop_getattr_args /* {
33155344Spendry 		struct vnode *a_vp;
33255344Spendry 		struct vattr *a_vap;
33355344Spendry 		struct ucred *a_cred;
33455344Spendry 		struct proc *a_p;
33555344Spendry 	} */ *ap;
33655344Spendry {
33755344Spendry 	struct vnode *vp = ap->a_vp;
33855344Spendry 	struct vattr *vap = ap->a_vap;
33955344Spendry 	int error = 0;
34055344Spendry 	char strbuf[KSTRING];
34155344Spendry 
34255344Spendry 	bzero((caddr_t) vap, sizeof(*vap));
34355344Spendry 	vattr_null(vap);
34455344Spendry 	vap->va_uid = 0;
34555344Spendry 	vap->va_gid = 0;
34655344Spendry 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
34755344Spendry 	/* vap->va_qsize = 0; */
34855344Spendry 	vap->va_blocksize = DEV_BSIZE;
34955344Spendry 	microtime(&vap->va_atime);
35055344Spendry 	vap->va_mtime = vap->va_atime;
35155344Spendry 	vap->va_ctime = vap->va_ctime;
35255344Spendry 	vap->va_gen = 0;
35355344Spendry 	vap->va_flags = 0;
35455344Spendry 	vap->va_rdev = 0;
35555344Spendry 	/* vap->va_qbytes = 0; */
35655344Spendry 	vap->va_bytes = 0;
35755344Spendry 
35855344Spendry 	if (vp->v_flag & VROOT) {
35955344Spendry #ifdef KERNFS_DIAGNOSTIC
36055344Spendry 		printf("kernfs_getattr: stat rootdir\n");
36155344Spendry #endif
36255344Spendry 		vap->va_type = VDIR;
36355356Spendry 		vap->va_mode = DIR_MODE;
36455344Spendry 		vap->va_nlink = 2;
36555344Spendry 		vap->va_fileid = 2;
36655344Spendry 		vap->va_size = DEV_BSIZE;
36755344Spendry 	} else {
36856497Smckusick 		struct kern_target *kt = VTOKERN(vp)->kf_kt;
36955344Spendry 		int nbytes;
37055344Spendry #ifdef KERNFS_DIAGNOSTIC
37155344Spendry 		printf("kernfs_getattr: stat target %s\n", kt->kt_name);
37255344Spendry #endif
37355344Spendry 		vap->va_type = kt->kt_vtype;
37455356Spendry 		vap->va_mode = (kt->kt_rw & VWRITE ? WRITE_MODE : READ_MODE);
37555344Spendry 		vap->va_nlink = 1;
37655344Spendry 		vap->va_fileid = 3 + (kt - kern_targets) / sizeof(*kt);
37755344Spendry 		error = kernfs_xread(kt, strbuf, sizeof(strbuf), &nbytes);
37855344Spendry 		vap->va_size = nbytes;
37955344Spendry 	}
38055344Spendry 
38155344Spendry 	vp->v_type = vap->va_type;
38255344Spendry #ifdef KERNFS_DIAGNOSTIC
38355344Spendry 	printf("kernfs_getattr: return error %d\n", error);
38455344Spendry #endif
38555344Spendry 	return (error);
38655344Spendry }
38755344Spendry 
38855344Spendry kernfs_setattr(ap)
38955344Spendry 	struct vop_setattr_args /* {
39055344Spendry 		struct vnode *a_vp;
39155344Spendry 		struct vattr *a_vap;
39255344Spendry 		struct ucred *a_cred;
39355344Spendry 		struct proc *a_p;
39455344Spendry 	} */ *ap;
39555344Spendry {
39655344Spendry 
39755344Spendry 	/*
39855344Spendry 	 * Silently ignore attribute changes.
39955344Spendry 	 * This allows for open with truncate to have no
40055344Spendry 	 * effect until some data is written.  I want to
40155344Spendry 	 * do it this way because all writes are atomic.
40255344Spendry 	 */
40355344Spendry 	return (0);
40455344Spendry }
40555344Spendry 
40655344Spendry static int
40755344Spendry kernfs_read(ap)
40855344Spendry 	struct vop_read_args /* {
40955344Spendry 		struct vnode *a_vp;
41055344Spendry 		struct uio *a_uio;
41155344Spendry 		int  a_ioflag;
41255344Spendry 		struct ucred *a_cred;
41355344Spendry 	} */ *ap;
41455344Spendry {
41555344Spendry 	struct vnode *vp = ap->a_vp;
41655344Spendry 	struct uio *uio = ap->a_uio;
41756497Smckusick 	struct kern_target *kt;
41855344Spendry 	char strbuf[KSTRING];
41955344Spendry 	int off = uio->uio_offset;
42065446Sbostic 	int error, len;
42165446Sbostic 	char *cp;
42256497Smckusick 
42356497Smckusick 	if (vp->v_flag & VROOT)
42466052Spendry 		return (EOPNOTSUPP);
42556497Smckusick 
42656497Smckusick 	kt = VTOKERN(vp)->kf_kt;
42756497Smckusick 
42855344Spendry #ifdef KERNFS_DIAGNOSTIC
42955344Spendry 	printf("kern_read %s\n", kt->kt_name);
43055344Spendry #endif
43155344Spendry 
43265446Sbostic 	len = 0;
43355344Spendry 	error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len);
43455344Spendry 	if (error)
43555344Spendry 		return (error);
43655344Spendry 	cp = strbuf + off;
43755344Spendry 	len -= off;
43855344Spendry 	return (uiomove(cp, len, uio));
43955344Spendry }
44055344Spendry 
44155344Spendry static int
44255344Spendry kernfs_write(ap)
44355344Spendry 	struct vop_write_args /* {
44455344Spendry 		struct vnode *a_vp;
44555344Spendry 		struct uio *a_uio;
44655344Spendry 		int  a_ioflag;
44755344Spendry 		struct ucred *a_cred;
44855344Spendry 	} */ *ap;
44955344Spendry {
45055344Spendry 	struct vnode *vp = ap->a_vp;
45155344Spendry 	struct uio *uio = ap->a_uio;
45256497Smckusick 	struct kern_target *kt;
45365446Sbostic 	int error, xlen;
45455344Spendry 	char strbuf[KSTRING];
45555344Spendry 
45656497Smckusick 	if (vp->v_flag & VROOT)
45756497Smckusick 		return (0);
45856497Smckusick 
45956497Smckusick 	kt = VTOKERN(vp)->kf_kt;
46056497Smckusick 
46155344Spendry 	if (uio->uio_offset != 0)
46255344Spendry 		return (EINVAL);
46355344Spendry 
46455344Spendry 	xlen = min(uio->uio_resid, KSTRING-1);
46555344Spendry 	error = uiomove(strbuf, xlen, uio);
46655344Spendry 	if (error)
46755344Spendry 		return (error);
46855344Spendry 
46955344Spendry 	if (uio->uio_resid != 0)
47055344Spendry 		return (EIO);
47155344Spendry 
47255344Spendry 	strbuf[xlen] = '\0';
47359556Spendry 	xlen = strlen(strbuf);
47455344Spendry 	return (kernfs_xwrite(kt, strbuf, xlen));
47555344Spendry }
47655344Spendry 
47755344Spendry 
47855344Spendry kernfs_readdir(ap)
47955344Spendry 	struct vop_readdir_args /* {
48055344Spendry 		struct vnode *a_vp;
48155344Spendry 		struct uio *a_uio;
48255344Spendry 		struct ucred *a_cred;
483*67365Smckusick 		int *a_eofflag;
484*67365Smckusick 		u_long *a_cookies;
485*67365Smckusick 		int a_ncookies;
48655344Spendry 	} */ *ap;
48755344Spendry {
48855344Spendry 	struct uio *uio = ap->a_uio;
48955344Spendry 	int i;
49055344Spendry 	int error;
49155344Spendry 
492*67365Smckusick 	/*
493*67365Smckusick 	 * We don't allow exporting kernfs mounts, and currently local
494*67365Smckusick 	 * requests do not need cookies.
495*67365Smckusick 	 */
496*67365Smckusick 	if (ap->a_ncookies)
497*67365Smckusick 		panic("kernfs_readdir: not hungry");
498*67365Smckusick 
49955344Spendry 	i = uio->uio_offset / UIO_MX;
50055344Spendry 	error = 0;
50155344Spendry 	while (uio->uio_resid > 0 && i < nkern_targets) {
50255344Spendry 		struct dirent d;
50355344Spendry 		struct dirent *dp = &d;
50455344Spendry 		struct kern_target *kt = &kern_targets[i];
50555344Spendry #ifdef KERNFS_DIAGNOSTIC
50655344Spendry 		printf("kernfs_readdir: i = %d\n", i);
50755344Spendry #endif
50855344Spendry 
50955344Spendry 		bzero((caddr_t) dp, UIO_MX);
51055344Spendry 
51155344Spendry 		dp->d_namlen = strlen(kt->kt_name);
51255344Spendry 		bcopy(kt->kt_name, dp->d_name, dp->d_namlen+1);
51355344Spendry 
51455344Spendry #ifdef KERNFS_DIAGNOSTIC
51555344Spendry 		printf("kernfs_readdir: name = %s, len = %d\n",
51655344Spendry 				dp->d_name, dp->d_namlen);
51755344Spendry #endif
51855344Spendry 		/*
51955344Spendry 		 * Fill in the remaining fields
52055344Spendry 		 */
52155344Spendry 		dp->d_reclen = UIO_MX;
52255344Spendry 		dp->d_fileno = i + 3;
52355344Spendry 		dp->d_type = DT_UNKNOWN;	/* XXX */
52455344Spendry 		/*
52555344Spendry 		 * And ship to userland
52655344Spendry 		 */
52755344Spendry 		error = uiomove((caddr_t) dp, UIO_MX, uio);
52855344Spendry 		if (error)
52955344Spendry 			break;
53055344Spendry 		i++;
53155344Spendry 	}
53255344Spendry 
53355344Spendry 	uio->uio_offset = i * UIO_MX;
53455344Spendry 
53555344Spendry 	return (error);
53655344Spendry }
53755344Spendry 
53855344Spendry kernfs_inactive(ap)
53955344Spendry 	struct vop_inactive_args /* {
54055344Spendry 		struct vnode *a_vp;
54155344Spendry 	} */ *ap;
54255344Spendry {
54355344Spendry 	struct vnode *vp = ap->a_vp;
54455344Spendry 
54555344Spendry 	/*
54655344Spendry 	 * Clear out the v_type field to avoid
54755344Spendry 	 * nasty things happening in vgone().
54855344Spendry 	 */
54955344Spendry 	vp->v_type = VNON;
55055344Spendry #ifdef KERNFS_DIAGNOSTIC
55155344Spendry 	printf("kernfs_inactive(%x)\n", vp);
55255344Spendry #endif
55355344Spendry 	return (0);
55455344Spendry }
55555344Spendry 
55655344Spendry kernfs_reclaim(ap)
55755344Spendry 	struct vop_reclaim_args /* {
55855344Spendry 		struct vnode *a_vp;
55955344Spendry 	} */ *ap;
56055344Spendry {
56155344Spendry 	struct vnode *vp = ap->a_vp;
56260618Smckusick #ifdef KERNFS_DIAGNOSTIC
56355344Spendry 	printf("kernfs_reclaim(%x)\n", vp);
56460618Smckusick #endif
56555344Spendry 	if (vp->v_data) {
56655344Spendry 		FREE(vp->v_data, M_TEMP);
56755344Spendry 		vp->v_data = 0;
56855344Spendry 	}
56955344Spendry 	return (0);
57055344Spendry }
57155344Spendry 
57255344Spendry /*
57365742Spendry  * Return POSIX pathconf information applicable to special devices.
57465742Spendry  */
57565742Spendry kernfs_pathconf(ap)
57665742Spendry 	struct vop_pathconf_args /* {
57765742Spendry 		struct vnode *a_vp;
57865742Spendry 		int a_name;
57965742Spendry 		int *a_retval;
58065742Spendry 	} */ *ap;
58165742Spendry {
58265742Spendry 
58365742Spendry 	switch (ap->a_name) {
58465742Spendry 	case _PC_LINK_MAX:
58565742Spendry 		*ap->a_retval = LINK_MAX;
58665742Spendry 		return (0);
58765742Spendry 	case _PC_MAX_CANON:
58865742Spendry 		*ap->a_retval = MAX_CANON;
58965742Spendry 		return (0);
59065742Spendry 	case _PC_MAX_INPUT:
59165742Spendry 		*ap->a_retval = MAX_INPUT;
59265742Spendry 		return (0);
59365742Spendry 	case _PC_PIPE_BUF:
59465742Spendry 		*ap->a_retval = PIPE_BUF;
59565742Spendry 		return (0);
59665742Spendry 	case _PC_CHOWN_RESTRICTED:
59765742Spendry 		*ap->a_retval = 1;
59865742Spendry 		return (0);
59965742Spendry 	case _PC_VDISABLE:
60065742Spendry 		*ap->a_retval = _POSIX_VDISABLE;
60165742Spendry 		return (0);
60265742Spendry 	default:
60365742Spendry 		return (EINVAL);
60465742Spendry 	}
60565742Spendry 	/* NOTREACHED */
60665742Spendry }
60765742Spendry 
60865742Spendry /*
60955344Spendry  * Print out the contents of a /dev/fd vnode.
61055344Spendry  */
61155344Spendry /* ARGSUSED */
61255344Spendry kernfs_print(ap)
61355344Spendry 	struct vop_print_args /* {
61455344Spendry 		struct vnode *a_vp;
61555344Spendry 	} */ *ap;
61655344Spendry {
61755344Spendry 
61865380Spendry 	printf("tag VT_KERNFS, kernfs vnode\n");
61955344Spendry 	return (0);
62055344Spendry }
62155344Spendry 
62255344Spendry /*void*/
62355344Spendry kernfs_vfree(ap)
62455344Spendry 	struct vop_vfree_args /* {
62555344Spendry 		struct vnode *a_pvp;
62655344Spendry 		ino_t a_ino;
62755344Spendry 		int a_mode;
62855344Spendry 	} */ *ap;
62955344Spendry {
63055344Spendry 
63155344Spendry 	return (0);
63255344Spendry }
63355344Spendry 
63455344Spendry /*
63555344Spendry  * /dev/fd vnode unsupported operation
63655344Spendry  */
63755344Spendry kernfs_enotsupp()
63855344Spendry {
63955344Spendry 
64055344Spendry 	return (EOPNOTSUPP);
64155344Spendry }
64255344Spendry 
64355344Spendry /*
64455344Spendry  * /dev/fd "should never get here" operation
64555344Spendry  */
64655344Spendry kernfs_badop()
64755344Spendry {
64855344Spendry 
64955344Spendry 	panic("kernfs: bad op");
65055344Spendry 	/* NOTREACHED */
65155344Spendry }
65255344Spendry 
65355344Spendry /*
65455350Spendry  * kernfs vnode null operation
65555344Spendry  */
65655344Spendry kernfs_nullop()
65755344Spendry {
65855344Spendry 
65955344Spendry 	return (0);
66055344Spendry }
66155344Spendry 
66255344Spendry #define kernfs_create ((int (*) __P((struct  vop_create_args *)))kernfs_enotsupp)
66355344Spendry #define kernfs_mknod ((int (*) __P((struct  vop_mknod_args *)))kernfs_enotsupp)
66455344Spendry #define kernfs_close ((int (*) __P((struct  vop_close_args *)))nullop)
66555344Spendry #define kernfs_ioctl ((int (*) __P((struct  vop_ioctl_args *)))kernfs_enotsupp)
66655344Spendry #define kernfs_select ((int (*) __P((struct  vop_select_args *)))kernfs_enotsupp)
66755344Spendry #define kernfs_mmap ((int (*) __P((struct  vop_mmap_args *)))kernfs_enotsupp)
66855344Spendry #define kernfs_fsync ((int (*) __P((struct  vop_fsync_args *)))nullop)
66955344Spendry #define kernfs_seek ((int (*) __P((struct  vop_seek_args *)))nullop)
67055344Spendry #define kernfs_remove ((int (*) __P((struct  vop_remove_args *)))kernfs_enotsupp)
67155344Spendry #define kernfs_link ((int (*) __P((struct  vop_link_args *)))kernfs_enotsupp)
67255344Spendry #define kernfs_rename ((int (*) __P((struct  vop_rename_args *)))kernfs_enotsupp)
67355344Spendry #define kernfs_mkdir ((int (*) __P((struct  vop_mkdir_args *)))kernfs_enotsupp)
67455344Spendry #define kernfs_rmdir ((int (*) __P((struct  vop_rmdir_args *)))kernfs_enotsupp)
67555344Spendry #define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))kernfs_enotsupp)
67655344Spendry #define kernfs_readlink \
67755344Spendry 	((int (*) __P((struct  vop_readlink_args *)))kernfs_enotsupp)
67855344Spendry #define kernfs_abortop ((int (*) __P((struct  vop_abortop_args *)))nullop)
67955344Spendry #define kernfs_lock ((int (*) __P((struct  vop_lock_args *)))nullop)
68055344Spendry #define kernfs_unlock ((int (*) __P((struct  vop_unlock_args *)))nullop)
68155344Spendry #define kernfs_bmap ((int (*) __P((struct  vop_bmap_args *)))kernfs_badop)
68255344Spendry #define kernfs_strategy ((int (*) __P((struct  vop_strategy_args *)))kernfs_badop)
68355344Spendry #define kernfs_islocked ((int (*) __P((struct  vop_islocked_args *)))nullop)
68455344Spendry #define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))kernfs_enotsupp)
68555344Spendry #define kernfs_blkatoff \
68655344Spendry 	((int (*) __P((struct  vop_blkatoff_args *)))kernfs_enotsupp)
68755344Spendry #define kernfs_valloc ((int(*) __P(( \
68855344Spendry 		struct vnode *pvp, \
68955344Spendry 		int mode, \
69055344Spendry 		struct ucred *cred, \
69155344Spendry 		struct vnode **vpp))) kernfs_enotsupp)
69255344Spendry #define kernfs_truncate \
69355344Spendry 	((int (*) __P((struct  vop_truncate_args *)))kernfs_enotsupp)
69455344Spendry #define kernfs_update ((int (*) __P((struct  vop_update_args *)))kernfs_enotsupp)
69555344Spendry #define kernfs_bwrite ((int (*) __P((struct  vop_bwrite_args *)))kernfs_enotsupp)
69655344Spendry 
69755344Spendry int (**kernfs_vnodeop_p)();
69855344Spendry struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = {
69955344Spendry 	{ &vop_default_desc, vn_default_error },
70055344Spendry 	{ &vop_lookup_desc, kernfs_lookup },	/* lookup */
70155344Spendry 	{ &vop_create_desc, kernfs_create },	/* create */
70255344Spendry 	{ &vop_mknod_desc, kernfs_mknod },	/* mknod */
70365742Spendry 	{ &vop_open_desc, kernfs_open },	/* open */
70455344Spendry 	{ &vop_close_desc, kernfs_close },	/* close */
70555344Spendry 	{ &vop_access_desc, kernfs_access },	/* access */
70655344Spendry 	{ &vop_getattr_desc, kernfs_getattr },	/* getattr */
70755344Spendry 	{ &vop_setattr_desc, kernfs_setattr },	/* setattr */
70865742Spendry 	{ &vop_read_desc, kernfs_read },	/* read */
70955344Spendry 	{ &vop_write_desc, kernfs_write },	/* write */
71055344Spendry 	{ &vop_ioctl_desc, kernfs_ioctl },	/* ioctl */
71155344Spendry 	{ &vop_select_desc, kernfs_select },	/* select */
71265742Spendry 	{ &vop_mmap_desc, kernfs_mmap },	/* mmap */
71355344Spendry 	{ &vop_fsync_desc, kernfs_fsync },	/* fsync */
71465742Spendry 	{ &vop_seek_desc, kernfs_seek },	/* seek */
71555344Spendry 	{ &vop_remove_desc, kernfs_remove },	/* remove */
71665742Spendry 	{ &vop_link_desc, kernfs_link },	/* link */
71755344Spendry 	{ &vop_rename_desc, kernfs_rename },	/* rename */
71855344Spendry 	{ &vop_mkdir_desc, kernfs_mkdir },	/* mkdir */
71955344Spendry 	{ &vop_rmdir_desc, kernfs_rmdir },	/* rmdir */
72055344Spendry 	{ &vop_symlink_desc, kernfs_symlink },	/* symlink */
72155344Spendry 	{ &vop_readdir_desc, kernfs_readdir },	/* readdir */
72265742Spendry 	{ &vop_readlink_desc, kernfs_readlink },/* readlink */
72355344Spendry 	{ &vop_abortop_desc, kernfs_abortop },	/* abortop */
72465742Spendry 	{ &vop_inactive_desc, kernfs_inactive },/* inactive */
72555344Spendry 	{ &vop_reclaim_desc, kernfs_reclaim },	/* reclaim */
72665742Spendry 	{ &vop_lock_desc, kernfs_lock },	/* lock */
72755344Spendry 	{ &vop_unlock_desc, kernfs_unlock },	/* unlock */
72865742Spendry 	{ &vop_bmap_desc, kernfs_bmap },	/* bmap */
72965742Spendry 	{ &vop_strategy_desc, kernfs_strategy },/* strategy */
73055344Spendry 	{ &vop_print_desc, kernfs_print },	/* print */
73165742Spendry 	{ &vop_islocked_desc, kernfs_islocked },/* islocked */
73265742Spendry 	{ &vop_pathconf_desc, kernfs_pathconf },/* pathconf */
73355344Spendry 	{ &vop_advlock_desc, kernfs_advlock },	/* advlock */
73465742Spendry 	{ &vop_blkatoff_desc, kernfs_blkatoff },/* blkatoff */
73555344Spendry 	{ &vop_valloc_desc, kernfs_valloc },	/* valloc */
73655344Spendry 	{ &vop_vfree_desc, kernfs_vfree },	/* vfree */
73765742Spendry 	{ &vop_truncate_desc, kernfs_truncate },/* truncate */
73855344Spendry 	{ &vop_update_desc, kernfs_update },	/* update */
73955344Spendry 	{ &vop_bwrite_desc, kernfs_bwrite },	/* bwrite */
74055344Spendry 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
74155344Spendry };
74255344Spendry struct vnodeopv_desc kernfs_vnodeop_opv_desc =
74355344Spendry 	{ &kernfs_vnodeop_p, kernfs_vnodeop_entries };
744