1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software donated to Berkeley by
6  * Jan-Simon Pendry.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)kernfs_vfsops.c	8.6 (Berkeley) 02/23/95
11  */
12 
13 /*
14  * Kernel params Filesystem
15  */
16 
17 #include <sys/param.h>
18 #include <sys/systm.h>
19 #include <sys/conf.h>
20 #include <sys/types.h>
21 #include <sys/proc.h>
22 #include <sys/vnode.h>
23 #include <sys/mount.h>
24 #include <sys/namei.h>
25 #include <sys/malloc.h>
26 
27 #include <miscfs/specfs/specdev.h>
28 #include <miscfs/kernfs/kernfs.h>
29 
30 dev_t rrootdev = NODEV;
31 
32 kernfs_init()
33 {
34 
35 }
36 
37 void
38 kernfs_get_rrootdev()
39 {
40 	static int tried = 0;
41 	int cmaj;
42 
43 	if (tried) {
44 		/* Already did it once. */
45 		return;
46 	}
47 	tried = 1;
48 
49 	if (rootdev == NODEV)
50 		return;
51 	for (cmaj = 0; cmaj < nchrdev; cmaj++) {
52 		rrootdev = makedev(cmaj, minor(rootdev));
53 		if (chrtoblk(rrootdev) == rootdev)
54 			return;
55 	}
56 	rrootdev = NODEV;
57 	printf("kernfs_get_rrootdev: no raw root device\n");
58 }
59 
60 /*
61  * Mount the Kernel params filesystem
62  */
63 kernfs_mount(mp, path, data, ndp, p)
64 	struct mount *mp;
65 	char *path;
66 	caddr_t data;
67 	struct nameidata *ndp;
68 	struct proc *p;
69 {
70 	int error = 0;
71 	u_int size;
72 	struct kernfs_mount *fmp;
73 	struct vnode *rvp;
74 
75 #ifdef KERNFS_DIAGNOSTIC
76 	printf("kernfs_mount(mp = %x)\n", mp);
77 #endif
78 
79 	/*
80 	 * Update is a no-op
81 	 */
82 	if (mp->mnt_flag & MNT_UPDATE)
83 		return (EOPNOTSUPP);
84 
85 	error = getnewvnode(VT_KERNFS, mp, kernfs_vnodeop_p, &rvp);	/* XXX */
86 	if (error)
87 		return (error);
88 
89 	MALLOC(fmp, struct kernfs_mount *, sizeof(struct kernfs_mount),
90 				M_UFSMNT, M_WAITOK);	/* XXX */
91 	rvp->v_type = VDIR;
92 	rvp->v_flag |= VROOT;
93 #ifdef KERNFS_DIAGNOSTIC
94 	printf("kernfs_mount: root vp = %x\n", rvp);
95 #endif
96 	fmp->kf_root = rvp;
97 	mp->mnt_flag |= MNT_LOCAL;
98 	mp->mnt_data = (qaddr_t) fmp;
99 	getnewfsid(mp, MOUNT_KERNFS);
100 
101 	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
102 	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
103 	bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
104 	bcopy("kernfs", mp->mnt_stat.f_mntfromname, sizeof("kernfs"));
105 #ifdef KERNFS_DIAGNOSTIC
106 	printf("kernfs_mount: at %s\n", mp->mnt_stat.f_mntonname);
107 #endif
108 
109 	kernfs_get_rrootdev();
110 	return (0);
111 }
112 
113 kernfs_start(mp, flags, p)
114 	struct mount *mp;
115 	int flags;
116 	struct proc *p;
117 {
118 	return (0);
119 }
120 
121 kernfs_unmount(mp, mntflags, p)
122 	struct mount *mp;
123 	int mntflags;
124 	struct proc *p;
125 {
126 	int error;
127 	int flags = 0;
128 	extern int doforce;
129 	struct vnode *rootvp = VFSTOKERNFS(mp)->kf_root;
130 
131 #ifdef KERNFS_DIAGNOSTIC
132 	printf("kernfs_unmount(mp = %x)\n", mp);
133 #endif
134 
135 	if (mntflags & MNT_FORCE) {
136 		/* kernfs can never be rootfs so don't check for it */
137 		if (!doforce)
138 			return (EINVAL);
139 		flags |= FORCECLOSE;
140 	}
141 
142 	/*
143 	 * Clear out buffer cache.  I don't think we
144 	 * ever get anything cached at this level at the
145 	 * moment, but who knows...
146 	 */
147 	if (rootvp->v_usecount > 1)
148 		return (EBUSY);
149 #ifdef KERNFS_DIAGNOSTIC
150 	printf("kernfs_unmount: calling vflush\n");
151 #endif
152 	if (error = vflush(mp, rootvp, flags))
153 		return (error);
154 
155 #ifdef KERNFS_DIAGNOSTIC
156 	vprint("kernfs root", rootvp);
157 #endif
158 	/*
159 	 * Release reference on underlying root vnode
160 	 */
161 	vrele(rootvp);
162 	/*
163 	 * And blow it away for future re-use
164 	 */
165 	VOP_REVOKE(rootvp, 0);
166 	/*
167 	 * Finally, throw away the kernfs_mount structure
168 	 */
169 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
170 	mp->mnt_data = 0;
171 	return 0;
172 }
173 
174 kernfs_root(mp, vpp)
175 	struct mount *mp;
176 	struct vnode **vpp;
177 {
178 	struct vnode *vp;
179 
180 #ifdef KERNFS_DIAGNOSTIC
181 	printf("kernfs_root(mp = %x)\n", mp);
182 #endif
183 
184 	/*
185 	 * Return locked reference to root.
186 	 */
187 	vp = VFSTOKERNFS(mp)->kf_root;
188 	VREF(vp);
189 	VOP_LOCK(vp);
190 	*vpp = vp;
191 	return (0);
192 }
193 
194 kernfs_quotactl(mp, cmd, uid, arg, p)
195 	struct mount *mp;
196 	int cmd;
197 	uid_t uid;
198 	caddr_t arg;
199 	struct proc *p;
200 {
201 	return (EOPNOTSUPP);
202 }
203 
204 kernfs_statfs(mp, sbp, p)
205 	struct mount *mp;
206 	struct statfs *sbp;
207 	struct proc *p;
208 {
209 #ifdef KERNFS_DIAGNOSTIC
210 	printf("kernfs_statfs(mp = %x)\n", mp);
211 #endif
212 
213 	sbp->f_type = MOUNT_KERNFS;
214 	sbp->f_flags = 0;
215 	sbp->f_bsize = DEV_BSIZE;
216 	sbp->f_iosize = DEV_BSIZE;
217 	sbp->f_blocks = 2;		/* 1K to keep df happy */
218 	sbp->f_bfree = 0;
219 	sbp->f_bavail = 0;
220 	sbp->f_files = 0;
221 	sbp->f_ffree = 0;
222 	if (sbp != &mp->mnt_stat) {
223 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
224 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
225 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
226 	}
227 	return (0);
228 }
229 
230 kernfs_sync(mp, waitfor)
231 	struct mount *mp;
232 	int waitfor;
233 {
234 	return (0);
235 }
236 
237 /*
238  * Kernfs flat namespace lookup.
239  * Currently unsupported.
240  */
241 kernfs_vget(mp, ino, vpp)
242 	struct mount *mp;
243 	ino_t ino;
244 	struct vnode **vpp;
245 {
246 
247 	return (EOPNOTSUPP);
248 }
249 
250 
251 kernfs_fhtovp(mp, fhp, setgen, vpp)
252 	struct mount *mp;
253 	struct fid *fhp;
254 	int setgen;
255 	struct vnode **vpp;
256 {
257 	return (EOPNOTSUPP);
258 }
259 
260 kernfs_vptofh(vp, fhp)
261 	struct vnode *vp;
262 	struct fid *fhp;
263 {
264 	return (EOPNOTSUPP);
265 }
266 
267 struct vfsops kernfs_vfsops = {
268 	kernfs_mount,
269 	kernfs_start,
270 	kernfs_unmount,
271 	kernfs_root,
272 	kernfs_quotactl,
273 	kernfs_statfs,
274 	kernfs_sync,
275 	kernfs_vget,
276 	kernfs_fhtovp,
277 	kernfs_vptofh,
278 	kernfs_init,
279 };
280