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