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*69599Smckusick  *	@(#)kernfs_vnops.c	8.15 (Berkeley) 05/21/95
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 {
4267387Spendry 	u_char kt_type;
4367387Spendry 	u_char kt_namlen;
4455344Spendry 	char *kt_name;
4555344Spendry 	void *kt_data;
4667387Spendry #define	KTT_NULL	 1
4767387Spendry #define	KTT_TIME	 5
4867387Spendry #define KTT_INT		17
4967387Spendry #define	KTT_STRING	31
5067387Spendry #define KTT_HOSTNAME	47
5167387Spendry #define KTT_AVENRUN	53
5267387Spendry #define KTT_DEVICE	71
5367387Spendry 	u_char kt_tag;
5467387Spendry 	u_char kt_vtype;
5567387Spendry 	mode_t kt_mode;
5655344Spendry } kern_targets[] = {
5755344Spendry /* NOTE: The name must be less than UIO_MX-16 chars in length */
5867387Spendry #define N(s) sizeof(s)-1, s
5967387Spendry      /*        name            data          tag           type  ro/rw */
6067387Spendry      { DT_DIR, N("."),         0,            KTT_NULL,     VDIR, DIR_MODE   },
6167387Spendry      { DT_DIR, N(".."),        0,            KTT_NULL,     VDIR, DIR_MODE   },
6267387Spendry      { DT_REG, N("boottime"),  &boottime.tv_sec, KTT_INT,  VREG, READ_MODE  },
6367387Spendry      { DT_REG, N("copyright"), copyright,    KTT_STRING,   VREG, READ_MODE  },
6467387Spendry      { DT_REG, N("hostname"),  0,            KTT_HOSTNAME, VREG, WRITE_MODE },
6567387Spendry      { DT_REG, N("hz"),        &hz,          KTT_INT,      VREG, READ_MODE  },
6667387Spendry      { DT_REG, N("loadavg"),   0,            KTT_AVENRUN,  VREG, READ_MODE  },
6767387Spendry      { DT_REG, N("pagesize"),  &cnt.v_page_size, KTT_INT,  VREG, READ_MODE  },
6867387Spendry      { DT_REG, N("physmem"),   &physmem,     KTT_INT,      VREG, READ_MODE  },
6959556Spendry #if 0
7067387Spendry      { DT_DIR, N("root"),      0,            KTT_NULL,     VDIR, DIR_MODE   },
7159556Spendry #endif
7267387Spendry      { DT_BLK, N("rootdev"),   &rootdev,     KTT_DEVICE,   VBLK, READ_MODE  },
7367387Spendry      { DT_CHR, N("rrootdev"),  &rrootdev,    KTT_DEVICE,   VCHR, READ_MODE  },
7467387Spendry      { DT_REG, N("time"),      0,            KTT_TIME,     VREG, READ_MODE  },
7567387Spendry      { DT_REG, N("version"),   version,      KTT_STRING,   VREG, READ_MODE  },
7667387Spendry #undef N
7755344Spendry };
7855344Spendry static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]);
7955344Spendry 
8055344Spendry static int
kernfs_xread(kt,buf,len,lenp)8155344Spendry kernfs_xread(kt, buf, len, lenp)
8255344Spendry 	struct kern_target *kt;
8355344Spendry 	char *buf;
8455344Spendry 	int len;
8555344Spendry 	int *lenp;
8655344Spendry {
8767387Spendry 
8855344Spendry 	switch (kt->kt_tag) {
8955344Spendry 	case KTT_TIME: {
9055344Spendry 		struct timeval tv;
9155344Spendry 		microtime(&tv);
9255344Spendry 		sprintf(buf, "%d %d\n", tv.tv_sec, tv.tv_usec);
9355344Spendry 		break;
9455344Spendry 	}
9555344Spendry 
9655344Spendry 	case KTT_INT: {
9755344Spendry 		int *ip = kt->kt_data;
9855344Spendry 		sprintf(buf, "%d\n", *ip);
9955344Spendry 		break;
10055344Spendry 	}
10155344Spendry 
10255344Spendry 	case KTT_STRING: {
10355344Spendry 		char *cp = kt->kt_data;
10455344Spendry 		int xlen = strlen(cp) + 1;
10555344Spendry 
10655344Spendry 		if (xlen >= len)
10755344Spendry 			return (EINVAL);
10855344Spendry 
10955344Spendry 		bcopy(cp, buf, xlen);
11055344Spendry 		break;
11155344Spendry 	}
11255344Spendry 
11355344Spendry 	case KTT_HOSTNAME: {
11455344Spendry 		char *cp = hostname;
11555344Spendry 		int xlen = hostnamelen;
11655344Spendry 
11759556Spendry 		if (xlen >= (len-2))
11855344Spendry 			return (EINVAL);
11955344Spendry 
12059556Spendry 		bcopy(cp, buf, xlen);
12159556Spendry 		buf[xlen] = '\n';
12259556Spendry 		buf[xlen+1] = '\0';
12355344Spendry 		break;
12455344Spendry 	}
12555344Spendry 
12655344Spendry 	case KTT_AVENRUN:
12755344Spendry 		sprintf(buf, "%ld %ld %ld %ld\n",
12867387Spendry 		    averunnable.ldavg[0], averunnable.ldavg[1],
12967387Spendry 		    averunnable.ldavg[2], averunnable.fscale);
13055344Spendry 		break;
13155344Spendry 
13255344Spendry 	default:
13367387Spendry 		return (EIO);
13455344Spendry 	}
13555344Spendry 
13655344Spendry 	*lenp = strlen(buf);
13755344Spendry 	return (0);
13855344Spendry }
13955344Spendry 
14055344Spendry static int
kernfs_xwrite(kt,buf,len)14155344Spendry kernfs_xwrite(kt, buf, len)
14255344Spendry 	struct kern_target *kt;
14355344Spendry 	char *buf;
14455344Spendry 	int len;
14555344Spendry {
14667387Spendry 
14755344Spendry 	switch (kt->kt_tag) {
14867387Spendry 	case KTT_HOSTNAME:
14955344Spendry 		if (buf[len-1] == '\n')
15055344Spendry 			--len;
15155344Spendry 		bcopy(buf, hostname, len);
15259556Spendry 		hostname[len] = '\0';
15359556Spendry 		hostnamelen = len;
15455344Spendry 		return (0);
15555344Spendry 
15655344Spendry 	default:
15755344Spendry 		return (EIO);
15855344Spendry 	}
15955344Spendry }
16055344Spendry 
16155344Spendry 
16255344Spendry /*
16355344Spendry  * vp is the current namei directory
16455344Spendry  * ndp is the name to locate in that directory...
16555344Spendry  */
16655344Spendry kernfs_lookup(ap)
16755344Spendry 	struct vop_lookup_args /* {
16855344Spendry 		struct vnode * a_dvp;
16955344Spendry 		struct vnode ** a_vpp;
17055344Spendry 		struct componentname * a_cnp;
17155344Spendry 	} */ *ap;
17255344Spendry {
17367387Spendry 	struct componentname *cnp = ap->a_cnp;
17455344Spendry 	struct vnode **vpp = ap->a_vpp;
17555344Spendry 	struct vnode *dvp = ap->a_dvp;
17667387Spendry 	char *pname = cnp->cn_nameptr;
17769436Smckusick 	struct proc *p = cnp->cn_proc;
17867387Spendry 	struct kern_target *kt;
17965446Sbostic 	struct vnode *fvp;
18065446Sbostic 	int error, i;
18155344Spendry 
18255344Spendry #ifdef KERNFS_DIAGNOSTIC
18355344Spendry 	printf("kernfs_lookup(%x)\n", ap);
18455344Spendry 	printf("kernfs_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp);
18555344Spendry 	printf("kernfs_lookup(%s)\n", pname);
18655344Spendry #endif
18767387Spendry 
18869349Smckusick 	*vpp = NULLVP;
18969349Smckusick 
19069349Smckusick 	if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
19169349Smckusick 		return (EROFS);
19269349Smckusick 
193*69599Smckusick 	VOP_UNLOCK(dvp, 0, p);
19455344Spendry 	if (cnp->cn_namelen == 1 && *pname == '.') {
19555344Spendry 		*vpp = dvp;
19655350Spendry 		VREF(dvp);
197*69599Smckusick 		vn_lock(dvp, LK_SHARED | LK_RETRY, p);
19855344Spendry 		return (0);
19955344Spendry 	}
20055344Spendry 
20159556Spendry #if 0
20255344Spendry 	if (cnp->cn_namelen == 4 && bcmp(pname, "root", 4) == 0) {
20355344Spendry 		*vpp = rootdir;
20455344Spendry 		VREF(rootdir);
205*69599Smckusick 		vn_lock(rootdir, LK_SHARED | LK_RETRY, p)
20655344Spendry 		return (0);
20755344Spendry 	}
20859556Spendry #endif
20955350Spendry 
21069349Smckusick 	for (kt = kern_targets, i = 0; i < nkern_targets; kt++, i++) {
21167387Spendry 		if (cnp->cn_namelen == kt->kt_namlen &&
21269349Smckusick 		    bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0)
21369349Smckusick 			goto found;
21455344Spendry 	}
21555344Spendry 
21655344Spendry #ifdef KERNFS_DIAGNOSTIC
21769349Smckusick 	printf("kernfs_lookup: i = %d, failed", i);
21855344Spendry #endif
21955344Spendry 
220*69599Smckusick 	vn_lock(dvp, LK_SHARED | LK_RETRY, p);
22169349Smckusick 	return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
22255344Spendry 
22369349Smckusick found:
22467387Spendry 	if (kt->kt_tag == KTT_DEVICE) {
22567387Spendry 		dev_t *dp = kt->kt_data;
22667387Spendry 	loop:
227*69599Smckusick 		if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) {
228*69599Smckusick 			vn_lock(dvp, LK_SHARED | LK_RETRY, p);
22967387Spendry 			return (ENOENT);
230*69599Smckusick 		}
23167387Spendry 		*vpp = fvp;
23269436Smckusick 		if (vget(fvp, LK_EXCLUSIVE, p))
23367387Spendry 			goto loop;
23467387Spendry 		return (0);
23567387Spendry 	}
23667387Spendry 
23755344Spendry #ifdef KERNFS_DIAGNOSTIC
23855344Spendry 	printf("kernfs_lookup: allocate new vnode\n");
23955344Spendry #endif
24067387Spendry 	if (error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p,
241*69599Smckusick 	    &fvp)) {
242*69599Smckusick 		vn_lock(dvp, LK_SHARED | LK_RETRY, p);
24367387Spendry 		return (error);
244*69599Smckusick 	}
24567387Spendry 
24667387Spendry 	MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP,
24767387Spendry 	    M_WAITOK);
24867387Spendry 	VTOKERN(fvp)->kf_kt = kt;
24967387Spendry 	fvp->v_type = kt->kt_vtype;
250*69599Smckusick 	vn_lock(fvp, LK_SHARED | LK_RETRY, p);
25155344Spendry 	*vpp = fvp;
25267387Spendry 
25355344Spendry #ifdef KERNFS_DIAGNOSTIC
25455344Spendry 	printf("kernfs_lookup: newvp = %x\n", fvp);
25555344Spendry #endif
25655344Spendry 	return (0);
25755344Spendry }
25855344Spendry 
25955344Spendry kernfs_open(ap)
26055344Spendry 	struct vop_open_args /* {
26155344Spendry 		struct vnode *a_vp;
26255344Spendry 		int  a_mode;
26355344Spendry 		struct ucred *a_cred;
26455344Spendry 		struct proc *a_p;
26555344Spendry 	} */ *ap;
26655344Spendry {
26755344Spendry 
26867387Spendry 	/* Only need to check access permissions. */
26955344Spendry 	return (0);
27055344Spendry }
27155344Spendry 
27255344Spendry static int
kernfs_access(ap)27355344Spendry kernfs_access(ap)
27455344Spendry 	struct vop_access_args /* {
27555344Spendry 		struct vnode *a_vp;
27655344Spendry 		int  a_mode;
27755344Spendry 		struct ucred *a_cred;
27855344Spendry 		struct proc *a_p;
27955344Spendry 	} */ *ap;
28055344Spendry {
28167387Spendry 	register struct vnode *vp = ap->a_vp;
28267387Spendry 	register struct ucred *cred = ap->a_cred;
28367387Spendry 	mode_t amode = ap->a_mode;
28467387Spendry 	mode_t fmode =
28567387Spendry 	    (vp->v_flag & VROOT) ? DIR_MODE : VTOKERN(vp)->kf_kt->kt_mode;
28667387Spendry 	mode_t mask = 0;
28767387Spendry 	register gid_t *gp;
28867387Spendry 	int i;
28955344Spendry 
29067387Spendry 	/* Some files are simply not modifiable. */
29167387Spendry 	if ((amode & VWRITE) && (fmode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0)
29267387Spendry 		return (EPERM);
29355344Spendry 
29467387Spendry 	/* Root can do anything else. */
29567387Spendry 	if (cred->cr_uid == 0)
29667387Spendry 		return (0);
29756497Smckusick 
29867387Spendry 	/* Check for group 0 (wheel) permissions. */
29967387Spendry 	for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
30067387Spendry 		if (*gp == 0) {
30167387Spendry 			if (amode & VEXEC)
30267387Spendry 				mask |= S_IXGRP;
30367387Spendry 			if (amode & VREAD)
30467387Spendry 				mask |= S_IRGRP;
30567387Spendry 			if (amode & VWRITE)
30667387Spendry 				mask |= S_IWGRP;
30767387Spendry 			return ((fmode & mask) == mask ?  0 : EACCES);
30856497Smckusick 		}
30955344Spendry 
31067387Spendry         /* Otherwise, check everyone else. */
31167387Spendry 	if (amode & VEXEC)
31267387Spendry 		mask |= S_IXOTH;
31367387Spendry 	if (amode & VREAD)
31467387Spendry 		mask |= S_IROTH;
31567387Spendry 	if (amode & VWRITE)
31667387Spendry 		mask |= S_IWOTH;
31767387Spendry 	return ((fmode & mask) == mask ? 0 : EACCES);
31855344Spendry }
31955344Spendry 
32055344Spendry kernfs_getattr(ap)
32155344Spendry 	struct vop_getattr_args /* {
32255344Spendry 		struct vnode *a_vp;
32355344Spendry 		struct vattr *a_vap;
32455344Spendry 		struct ucred *a_cred;
32555344Spendry 		struct proc *a_p;
32655344Spendry 	} */ *ap;
32755344Spendry {
32855344Spendry 	struct vnode *vp = ap->a_vp;
32955344Spendry 	struct vattr *vap = ap->a_vap;
33068173Scgd 	struct timeval tv;
33155344Spendry 	int error = 0;
33255344Spendry 	char strbuf[KSTRING];
33355344Spendry 
33455344Spendry 	bzero((caddr_t) vap, sizeof(*vap));
33555344Spendry 	vattr_null(vap);
33655344Spendry 	vap->va_uid = 0;
33755344Spendry 	vap->va_gid = 0;
33855344Spendry 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
33967387Spendry 	vap->va_size = 0;
34055344Spendry 	vap->va_blocksize = DEV_BSIZE;
34168173Scgd 	microtime(&tv);
34268173Scgd 	TIMEVAL_TO_TIMESPEC(&tv, &vap->va_atime);
34355344Spendry 	vap->va_mtime = vap->va_atime;
34455344Spendry 	vap->va_ctime = vap->va_ctime;
34555344Spendry 	vap->va_gen = 0;
34655344Spendry 	vap->va_flags = 0;
34755344Spendry 	vap->va_rdev = 0;
34855344Spendry 	vap->va_bytes = 0;
34955344Spendry 
35055344Spendry 	if (vp->v_flag & VROOT) {
35155344Spendry #ifdef KERNFS_DIAGNOSTIC
35255344Spendry 		printf("kernfs_getattr: stat rootdir\n");
35355344Spendry #endif
35455344Spendry 		vap->va_type = VDIR;
35555356Spendry 		vap->va_mode = DIR_MODE;
35655344Spendry 		vap->va_nlink = 2;
35755344Spendry 		vap->va_fileid = 2;
35855344Spendry 		vap->va_size = DEV_BSIZE;
35955344Spendry 	} else {
36056497Smckusick 		struct kern_target *kt = VTOKERN(vp)->kf_kt;
36155344Spendry 		int nbytes;
36255344Spendry #ifdef KERNFS_DIAGNOSTIC
36355344Spendry 		printf("kernfs_getattr: stat target %s\n", kt->kt_name);
36455344Spendry #endif
36555344Spendry 		vap->va_type = kt->kt_vtype;
36667387Spendry 		vap->va_mode = kt->kt_mode;
36755344Spendry 		vap->va_nlink = 1;
36867387Spendry 		vap->va_fileid = 1 + (kt - kern_targets) / sizeof(*kt);
36955344Spendry 		error = kernfs_xread(kt, strbuf, sizeof(strbuf), &nbytes);
37055344Spendry 		vap->va_size = nbytes;
37155344Spendry 	}
37255344Spendry 
37355344Spendry #ifdef KERNFS_DIAGNOSTIC
37455344Spendry 	printf("kernfs_getattr: return error %d\n", error);
37555344Spendry #endif
37655344Spendry 	return (error);
37755344Spendry }
37855344Spendry 
37955344Spendry kernfs_setattr(ap)
38055344Spendry 	struct vop_setattr_args /* {
38155344Spendry 		struct vnode *a_vp;
38255344Spendry 		struct vattr *a_vap;
38355344Spendry 		struct ucred *a_cred;
38455344Spendry 		struct proc *a_p;
38555344Spendry 	} */ *ap;
38655344Spendry {
38755344Spendry 
38855344Spendry 	/*
38955344Spendry 	 * Silently ignore attribute changes.
39055344Spendry 	 * This allows for open with truncate to have no
39155344Spendry 	 * effect until some data is written.  I want to
39255344Spendry 	 * do it this way because all writes are atomic.
39355344Spendry 	 */
39455344Spendry 	return (0);
39555344Spendry }
39655344Spendry 
39755344Spendry static int
kernfs_read(ap)39855344Spendry kernfs_read(ap)
39955344Spendry 	struct vop_read_args /* {
40055344Spendry 		struct vnode *a_vp;
40155344Spendry 		struct uio *a_uio;
40255344Spendry 		int  a_ioflag;
40355344Spendry 		struct ucred *a_cred;
40455344Spendry 	} */ *ap;
40555344Spendry {
40655344Spendry 	struct vnode *vp = ap->a_vp;
40755344Spendry 	struct uio *uio = ap->a_uio;
40856497Smckusick 	struct kern_target *kt;
40955344Spendry 	char strbuf[KSTRING];
41055344Spendry 	int off = uio->uio_offset;
41165446Sbostic 	int error, len;
41265446Sbostic 	char *cp;
41356497Smckusick 
41467387Spendry 	if (vp->v_type == VDIR)
41566052Spendry 		return (EOPNOTSUPP);
41656497Smckusick 
41756497Smckusick 	kt = VTOKERN(vp)->kf_kt;
41856497Smckusick 
41955344Spendry #ifdef KERNFS_DIAGNOSTIC
42055344Spendry 	printf("kern_read %s\n", kt->kt_name);
42155344Spendry #endif
42255344Spendry 
42365446Sbostic 	len = 0;
42467387Spendry 	if (error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len))
42555344Spendry 		return (error);
42667387Spendry 	if (len <= off)
42767387Spendry 		return (0);
42867387Spendry 	return (uiomove(&strbuf[off], len - off, uio));
42955344Spendry }
43055344Spendry 
43155344Spendry static int
kernfs_write(ap)43255344Spendry kernfs_write(ap)
43355344Spendry 	struct vop_write_args /* {
43455344Spendry 		struct vnode *a_vp;
43555344Spendry 		struct uio *a_uio;
43655344Spendry 		int  a_ioflag;
43755344Spendry 		struct ucred *a_cred;
43855344Spendry 	} */ *ap;
43955344Spendry {
44055344Spendry 	struct vnode *vp = ap->a_vp;
44155344Spendry 	struct uio *uio = ap->a_uio;
44256497Smckusick 	struct kern_target *kt;
44365446Sbostic 	int error, xlen;
44455344Spendry 	char strbuf[KSTRING];
44555344Spendry 
44667387Spendry 	if (vp->v_type == VDIR)
44767387Spendry 		return (EOPNOTSUPP);
44856497Smckusick 
44956497Smckusick 	kt = VTOKERN(vp)->kf_kt;
45056497Smckusick 
45155344Spendry 	if (uio->uio_offset != 0)
45255344Spendry 		return (EINVAL);
45355344Spendry 
45455344Spendry 	xlen = min(uio->uio_resid, KSTRING-1);
45567387Spendry 	if (error = uiomove(strbuf, xlen, uio))
45655344Spendry 		return (error);
45755344Spendry 
45855344Spendry 	if (uio->uio_resid != 0)
45955344Spendry 		return (EIO);
46055344Spendry 
46155344Spendry 	strbuf[xlen] = '\0';
46259556Spendry 	xlen = strlen(strbuf);
46355344Spendry 	return (kernfs_xwrite(kt, strbuf, xlen));
46455344Spendry }
46555344Spendry 
46655344Spendry kernfs_readdir(ap)
46755344Spendry 	struct vop_readdir_args /* {
46855344Spendry 		struct vnode *a_vp;
46955344Spendry 		struct uio *a_uio;
47055344Spendry 		struct ucred *a_cred;
47167365Smckusick 		int *a_eofflag;
47267365Smckusick 		u_long *a_cookies;
47367365Smckusick 		int a_ncookies;
47455344Spendry 	} */ *ap;
47555344Spendry {
47667387Spendry 	int error, i;
47755344Spendry 	struct uio *uio = ap->a_uio;
47867387Spendry 	struct kern_target *kt;
47967387Spendry 	struct dirent d;
48055344Spendry 
48167387Spendry 	if (ap->a_vp->v_type != VDIR)
48267387Spendry 		return (ENOTDIR);
48367387Spendry 
48467365Smckusick 	/*
48567365Smckusick 	 * We don't allow exporting kernfs mounts, and currently local
48667365Smckusick 	 * requests do not need cookies.
48767365Smckusick 	 */
48867387Spendry 	if (ap->a_ncookies != NULL)
48967365Smckusick 		panic("kernfs_readdir: not hungry");
49067365Smckusick 
49155344Spendry 	i = uio->uio_offset / UIO_MX;
49255344Spendry 	error = 0;
49367387Spendry 	for (kt = &kern_targets[i];
49467387Spendry 		uio->uio_resid >= UIO_MX && i < nkern_targets; kt++, i++) {
49555344Spendry 		struct dirent *dp = &d;
49655344Spendry #ifdef KERNFS_DIAGNOSTIC
49755344Spendry 		printf("kernfs_readdir: i = %d\n", i);
49855344Spendry #endif
49955344Spendry 
50067387Spendry 		if (kt->kt_tag == KTT_DEVICE) {
50167387Spendry 			dev_t *dp = kt->kt_data;
50267387Spendry 			struct vnode *fvp;
50355344Spendry 
50467387Spendry 			if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp))
50567387Spendry 				continue;
50667387Spendry 		}
50755344Spendry 
50867387Spendry 		bzero((caddr_t)dp, UIO_MX);
50967387Spendry 		dp->d_namlen = kt->kt_namlen;
51067387Spendry 		bcopy(kt->kt_name, dp->d_name, kt->kt_namlen+1);
51167387Spendry 
51255344Spendry #ifdef KERNFS_DIAGNOSTIC
51355344Spendry 		printf("kernfs_readdir: name = %s, len = %d\n",
51455344Spendry 				dp->d_name, dp->d_namlen);
51555344Spendry #endif
51655344Spendry 		/*
51755344Spendry 		 * Fill in the remaining fields
51855344Spendry 		 */
51955344Spendry 		dp->d_reclen = UIO_MX;
52055344Spendry 		dp->d_fileno = i + 3;
52167387Spendry 		dp->d_type = kt->kt_type;
52255344Spendry 		/*
52355344Spendry 		 * And ship to userland
52455344Spendry 		 */
52567387Spendry 		if (error = uiomove((caddr_t)dp, UIO_MX, uio))
52655344Spendry 			break;
52755344Spendry 	}
52855344Spendry 
52955344Spendry 	uio->uio_offset = i * UIO_MX;
53055344Spendry 
53155344Spendry 	return (error);
53255344Spendry }
53355344Spendry 
53455344Spendry kernfs_inactive(ap)
53555344Spendry 	struct vop_inactive_args /* {
53655344Spendry 		struct vnode *a_vp;
53769593Smckusick 		struct proc *a_p;
53855344Spendry 	} */ *ap;
53955344Spendry {
54055344Spendry 	struct vnode *vp = ap->a_vp;
54155344Spendry 
54267387Spendry #ifdef KERNFS_DIAGNOSTIC
54367387Spendry 	printf("kernfs_inactive(%x)\n", vp);
54467387Spendry #endif
54555344Spendry 	/*
54655344Spendry 	 * Clear out the v_type field to avoid
54755344Spendry 	 * nasty things happening in vgone().
54855344Spendry 	 */
54969593Smckusick 	VOP_UNLOCK(vp, 0, ap->a_p);
55055344Spendry 	vp->v_type = VNON;
55155344Spendry 	return (0);
55255344Spendry }
55355344Spendry 
55455344Spendry kernfs_reclaim(ap)
55555344Spendry 	struct vop_reclaim_args /* {
55655344Spendry 		struct vnode *a_vp;
55755344Spendry 	} */ *ap;
55855344Spendry {
55955344Spendry 	struct vnode *vp = ap->a_vp;
56067387Spendry 
56160618Smckusick #ifdef KERNFS_DIAGNOSTIC
56255344Spendry 	printf("kernfs_reclaim(%x)\n", vp);
56360618Smckusick #endif
56455344Spendry 	if (vp->v_data) {
56555344Spendry 		FREE(vp->v_data, M_TEMP);
56655344Spendry 		vp->v_data = 0;
56755344Spendry 	}
56855344Spendry 	return (0);
56955344Spendry }
57055344Spendry 
57155344Spendry /*
57265742Spendry  * Return POSIX pathconf information applicable to special devices.
57365742Spendry  */
57465742Spendry kernfs_pathconf(ap)
57565742Spendry 	struct vop_pathconf_args /* {
57665742Spendry 		struct vnode *a_vp;
57765742Spendry 		int a_name;
57865742Spendry 		int *a_retval;
57965742Spendry 	} */ *ap;
58065742Spendry {
58165742Spendry 
58265742Spendry 	switch (ap->a_name) {
58365742Spendry 	case _PC_LINK_MAX:
58465742Spendry 		*ap->a_retval = LINK_MAX;
58565742Spendry 		return (0);
58665742Spendry 	case _PC_MAX_CANON:
58765742Spendry 		*ap->a_retval = MAX_CANON;
58865742Spendry 		return (0);
58965742Spendry 	case _PC_MAX_INPUT:
59065742Spendry 		*ap->a_retval = MAX_INPUT;
59165742Spendry 		return (0);
59265742Spendry 	case _PC_PIPE_BUF:
59365742Spendry 		*ap->a_retval = PIPE_BUF;
59465742Spendry 		return (0);
59565742Spendry 	case _PC_CHOWN_RESTRICTED:
59665742Spendry 		*ap->a_retval = 1;
59765742Spendry 		return (0);
59865742Spendry 	case _PC_VDISABLE:
59965742Spendry 		*ap->a_retval = _POSIX_VDISABLE;
60065742Spendry 		return (0);
60165742Spendry 	default:
60265742Spendry 		return (EINVAL);
60365742Spendry 	}
60465742Spendry 	/* NOTREACHED */
60565742Spendry }
60665742Spendry 
60765742Spendry /*
60855344Spendry  * Print out the contents of a /dev/fd vnode.
60955344Spendry  */
61055344Spendry /* ARGSUSED */
61155344Spendry kernfs_print(ap)
61255344Spendry 	struct vop_print_args /* {
61355344Spendry 		struct vnode *a_vp;
61455344Spendry 	} */ *ap;
61555344Spendry {
61655344Spendry 
61765380Spendry 	printf("tag VT_KERNFS, kernfs vnode\n");
61855344Spendry 	return (0);
61955344Spendry }
62055344Spendry 
62155344Spendry /*void*/
62255344Spendry kernfs_vfree(ap)
62355344Spendry 	struct vop_vfree_args /* {
62455344Spendry 		struct vnode *a_pvp;
62555344Spendry 		ino_t a_ino;
62655344Spendry 		int a_mode;
62755344Spendry 	} */ *ap;
62855344Spendry {
62955344Spendry 
63055344Spendry 	return (0);
63155344Spendry }
63255344Spendry 
63355344Spendry /*
63455344Spendry  * /dev/fd "should never get here" operation
63555344Spendry  */
kernfs_badop()63655344Spendry kernfs_badop()
63755344Spendry {
63855344Spendry 
63955344Spendry 	panic("kernfs: bad op");
64055344Spendry 	/* NOTREACHED */
64155344Spendry }
64255344Spendry 
64355344Spendry /*
64455350Spendry  * kernfs vnode null operation
64555344Spendry  */
kernfs_nullop()64655344Spendry kernfs_nullop()
64755344Spendry {
64855344Spendry 
64955344Spendry 	return (0);
65055344Spendry }
65155344Spendry 
65268730Smckusick #define kernfs_create ((int (*) __P((struct  vop_create_args *)))eopnotsupp)
65368730Smckusick #define kernfs_mknod ((int (*) __P((struct  vop_mknod_args *)))eopnotsupp)
65455344Spendry #define kernfs_close ((int (*) __P((struct  vop_close_args *)))nullop)
65568730Smckusick #define kernfs_ioctl ((int (*) __P((struct  vop_ioctl_args *)))eopnotsupp)
65668730Smckusick #define kernfs_select ((int (*) __P((struct  vop_select_args *)))eopnotsupp)
65768730Smckusick #define kernfs_revoke vop_revoke
65868730Smckusick #define kernfs_mmap ((int (*) __P((struct  vop_mmap_args *)))eopnotsupp)
65955344Spendry #define kernfs_fsync ((int (*) __P((struct  vop_fsync_args *)))nullop)
66055344Spendry #define kernfs_seek ((int (*) __P((struct  vop_seek_args *)))nullop)
66168730Smckusick #define kernfs_remove ((int (*) __P((struct  vop_remove_args *)))eopnotsupp)
66268730Smckusick #define kernfs_link ((int (*) __P((struct  vop_link_args *)))eopnotsupp)
66368730Smckusick #define kernfs_rename ((int (*) __P((struct  vop_rename_args *)))eopnotsupp)
66468730Smckusick #define kernfs_mkdir ((int (*) __P((struct  vop_mkdir_args *)))eopnotsupp)
66568730Smckusick #define kernfs_rmdir ((int (*) __P((struct  vop_rmdir_args *)))eopnotsupp)
66668730Smckusick #define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))eopnotsupp)
66768730Smckusick #define kernfs_readlink ((int (*) __P((struct  vop_readlink_args *)))eopnotsupp)
66855344Spendry #define kernfs_abortop ((int (*) __P((struct  vop_abortop_args *)))nullop)
66969436Smckusick #define kernfs_lock ((int (*) __P((struct  vop_lock_args *)))vop_nolock)
67069436Smckusick #define kernfs_unlock ((int (*) __P((struct  vop_unlock_args *)))vop_nounlock)
67155344Spendry #define kernfs_bmap ((int (*) __P((struct  vop_bmap_args *)))kernfs_badop)
67268730Smckusick #define kernfs_strategy \
67368730Smckusick 	((int (*) __P((struct  vop_strategy_args *)))kernfs_badop)
67469436Smckusick #define kernfs_islocked \
67569436Smckusick 	((int (*) __P((struct vop_islocked_args *)))vop_noislocked)
67668730Smckusick #define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))eopnotsupp)
67768730Smckusick #define kernfs_blkatoff ((int (*) __P((struct  vop_blkatoff_args *)))eopnotsupp)
67855344Spendry #define kernfs_valloc ((int(*) __P(( \
67955344Spendry 		struct vnode *pvp, \
68055344Spendry 		int mode, \
68155344Spendry 		struct ucred *cred, \
68268730Smckusick 		struct vnode **vpp))) eopnotsupp)
68368730Smckusick #define kernfs_truncate ((int (*) __P((struct  vop_truncate_args *)))eopnotsupp)
68468730Smckusick #define kernfs_update ((int (*) __P((struct  vop_update_args *)))eopnotsupp)
68568730Smckusick #define kernfs_bwrite ((int (*) __P((struct  vop_bwrite_args *)))eopnotsupp)
68655344Spendry 
68755344Spendry int (**kernfs_vnodeop_p)();
68855344Spendry struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = {
68955344Spendry 	{ &vop_default_desc, vn_default_error },
69055344Spendry 	{ &vop_lookup_desc, kernfs_lookup },	/* lookup */
69155344Spendry 	{ &vop_create_desc, kernfs_create },	/* create */
69255344Spendry 	{ &vop_mknod_desc, kernfs_mknod },	/* mknod */
69365742Spendry 	{ &vop_open_desc, kernfs_open },	/* open */
69455344Spendry 	{ &vop_close_desc, kernfs_close },	/* close */
69555344Spendry 	{ &vop_access_desc, kernfs_access },	/* access */
69655344Spendry 	{ &vop_getattr_desc, kernfs_getattr },	/* getattr */
69755344Spendry 	{ &vop_setattr_desc, kernfs_setattr },	/* setattr */
69865742Spendry 	{ &vop_read_desc, kernfs_read },	/* read */
69955344Spendry 	{ &vop_write_desc, kernfs_write },	/* write */
70055344Spendry 	{ &vop_ioctl_desc, kernfs_ioctl },	/* ioctl */
70155344Spendry 	{ &vop_select_desc, kernfs_select },	/* select */
70268730Smckusick 	{ &vop_revoke_desc, kernfs_revoke },	/* revoke */
70365742Spendry 	{ &vop_mmap_desc, kernfs_mmap },	/* mmap */
70455344Spendry 	{ &vop_fsync_desc, kernfs_fsync },	/* fsync */
70565742Spendry 	{ &vop_seek_desc, kernfs_seek },	/* seek */
70655344Spendry 	{ &vop_remove_desc, kernfs_remove },	/* remove */
70765742Spendry 	{ &vop_link_desc, kernfs_link },	/* link */
70855344Spendry 	{ &vop_rename_desc, kernfs_rename },	/* rename */
70955344Spendry 	{ &vop_mkdir_desc, kernfs_mkdir },	/* mkdir */
71055344Spendry 	{ &vop_rmdir_desc, kernfs_rmdir },	/* rmdir */
71155344Spendry 	{ &vop_symlink_desc, kernfs_symlink },	/* symlink */
71255344Spendry 	{ &vop_readdir_desc, kernfs_readdir },	/* readdir */
71365742Spendry 	{ &vop_readlink_desc, kernfs_readlink },/* readlink */
71455344Spendry 	{ &vop_abortop_desc, kernfs_abortop },	/* abortop */
71565742Spendry 	{ &vop_inactive_desc, kernfs_inactive },/* inactive */
71655344Spendry 	{ &vop_reclaim_desc, kernfs_reclaim },	/* reclaim */
71765742Spendry 	{ &vop_lock_desc, kernfs_lock },	/* lock */
71855344Spendry 	{ &vop_unlock_desc, kernfs_unlock },	/* unlock */
71965742Spendry 	{ &vop_bmap_desc, kernfs_bmap },	/* bmap */
72065742Spendry 	{ &vop_strategy_desc, kernfs_strategy },/* strategy */
72155344Spendry 	{ &vop_print_desc, kernfs_print },	/* print */
72265742Spendry 	{ &vop_islocked_desc, kernfs_islocked },/* islocked */
72365742Spendry 	{ &vop_pathconf_desc, kernfs_pathconf },/* pathconf */
72455344Spendry 	{ &vop_advlock_desc, kernfs_advlock },	/* advlock */
72565742Spendry 	{ &vop_blkatoff_desc, kernfs_blkatoff },/* blkatoff */
72655344Spendry 	{ &vop_valloc_desc, kernfs_valloc },	/* valloc */
72755344Spendry 	{ &vop_vfree_desc, kernfs_vfree },	/* vfree */
72865742Spendry 	{ &vop_truncate_desc, kernfs_truncate },/* truncate */
72955344Spendry 	{ &vop_update_desc, kernfs_update },	/* update */
73055344Spendry 	{ &vop_bwrite_desc, kernfs_bwrite },	/* bwrite */
73155344Spendry 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
73255344Spendry };
73355344Spendry struct vnodeopv_desc kernfs_vnodeop_opv_desc =
73455344Spendry 	{ &kernfs_vnodeop_p, kernfs_vnodeop_entries };
735