1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
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	8.2 (Berkeley) 01/04/94
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 = ENXIO;
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_KERNFS, 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 (rootvp->v_usecount > 1)
173 		return (EBUSY);
174 #ifdef KERNFS_DIAGNOSTIC
175 	printf("kernfs_unmount: calling vflush\n");
176 #endif
177 	if (error = vflush(mp, rootvp, flags))
178 		return (error);
179 
180 #ifdef KERNFS_DIAGNOSTIC
181 	vprint("kernfs root", rootvp);
182 #endif
183 	/*
184 	 * Release reference on underlying root vnode
185 	 */
186 	vrele(rootvp);
187 	/*
188 	 * And blow it away for future re-use
189 	 */
190 	vgone(rootvp);
191 	/*
192 	 * Finally, throw away the kernfs_mount structure
193 	 */
194 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
195 	mp->mnt_data = 0;
196 	return 0;
197 }
198 
199 kernfs_root(mp, vpp)
200 	struct mount *mp;
201 	struct vnode **vpp;
202 {
203 	struct vnode *vp;
204 	int error;
205 
206 #ifdef KERNFS_DIAGNOSTIC
207 	printf("kernfs_root(mp = %x)\n", mp);
208 #endif
209 
210 	/*
211 	 * Return locked reference to root.
212 	 */
213 	vp = VFSTOKERNFS(mp)->kf_root;
214 	VREF(vp);
215 	VOP_LOCK(vp);
216 	*vpp = vp;
217 	return (0);
218 }
219 
220 kernfs_quotactl(mp, cmd, uid, arg, p)
221 	struct mount *mp;
222 	int cmd;
223 	uid_t uid;
224 	caddr_t arg;
225 	struct proc *p;
226 {
227 	return (EOPNOTSUPP);
228 }
229 
230 kernfs_statfs(mp, sbp, p)
231 	struct mount *mp;
232 	struct statfs *sbp;
233 	struct proc *p;
234 {
235 #ifdef KERNFS_DIAGNOSTIC
236 	printf("kernfs_statfs(mp = %x)\n", mp);
237 #endif
238 
239 	sbp->f_type = MOUNT_KERNFS;
240 	sbp->f_flags = 0;
241 	sbp->f_bsize = DEV_BSIZE;
242 	sbp->f_iosize = DEV_BSIZE;
243 	sbp->f_blocks = 2;		/* 1K to keep df happy */
244 	sbp->f_bfree = 0;
245 	sbp->f_bavail = 0;
246 	sbp->f_files = 0;
247 	sbp->f_ffree = 0;
248 	if (sbp != &mp->mnt_stat) {
249 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
250 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
251 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
252 	}
253 	return (0);
254 }
255 
256 kernfs_sync(mp, waitfor)
257 	struct mount *mp;
258 	int waitfor;
259 {
260 	return (0);
261 }
262 
263 /*
264  * Kernfs flat namespace lookup.
265  * Currently unsupported.
266  */
267 kernfs_vget(mp, ino, vpp)
268 	struct mount *mp;
269 	ino_t ino;
270 	struct vnode **vpp;
271 {
272 
273 	return (EOPNOTSUPP);
274 }
275 
276 
277 kernfs_fhtovp(mp, fhp, setgen, vpp)
278 	struct mount *mp;
279 	struct fid *fhp;
280 	int setgen;
281 	struct vnode **vpp;
282 {
283 	return (EOPNOTSUPP);
284 }
285 
286 kernfs_vptofh(vp, fhp)
287 	struct vnode *vp;
288 	struct fid *fhp;
289 {
290 	return (EOPNOTSUPP);
291 }
292 
293 struct vfsops kernfs_vfsops = {
294 	kernfs_mount,
295 	kernfs_start,
296 	kernfs_unmount,
297 	kernfs_root,
298 	kernfs_quotactl,
299 	kernfs_statfs,
300 	kernfs_sync,
301 	kernfs_vget,
302 	kernfs_fhtovp,
303 	kernfs_vptofh,
304 	kernfs_init,
305 };
306