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