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  * the UCLA Ficus project.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)umap_vfsops.c	8.2 (Berkeley) 01/13/94
12  *
13  * @(#)null_vfsops.c       1.5 (Berkeley) 7/10/92
14  */
15 
16 /*
17  * Umap Layer
18  * (See mount_umap(8) for a description of this layer.)
19  */
20 
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <sys/vnode.h>
26 #include <sys/mount.h>
27 #include <sys/namei.h>
28 #include <sys/malloc.h>
29 #include <miscfs/umapfs/umap.h>
30 
31 /*
32  * Mount umap layer
33  */
34 int
35 umapfs_mount(mp, path, data, ndp, p)
36 	struct mount *mp;
37 	char *path;
38 	caddr_t data;
39 	struct nameidata *ndp;
40 	struct proc *p;
41 {
42 	struct umap_args args;
43 	struct vnode *lowerrootvp, *vp;
44 	struct vnode *umapm_rootvp;
45 	struct umap_mount *amp;
46 	u_int size;
47 	int error;
48 
49 #ifdef UMAPFS_DIAGNOSTIC
50 	printf("umapfs_mount(mp = %x)\n", mp);
51 #endif
52 
53 	/*
54 	 * Update is a no-op
55 	 */
56 	if (mp->mnt_flag & MNT_UPDATE) {
57 		return (EOPNOTSUPP);
58 		/* return (VFS_MOUNT(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, path, data, ndp, p));*/
59 	}
60 
61 	/*
62 	 * Get argument
63 	 */
64 	if (error = copyin(data, (caddr_t)&args, sizeof(struct umap_args)))
65 		return (error);
66 
67 	/*
68 	 * Find lower node
69 	 */
70 	NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
71 		UIO_USERSPACE, args.target, p);
72 	if (error = namei(ndp))
73 		return (error);
74 
75 	/*
76 	 * Sanity check on lower vnode
77 	 */
78 	lowerrootvp = ndp->ni_vp;
79 #ifdef UMAPFS_DIAGNOSTIC
80 	printf("vp = %x, check for VDIR...\n", lowerrootvp);
81 #endif
82 	vrele(ndp->ni_dvp);
83 	ndp->ni_dvp = 0;
84 
85 	if (lowerrootvp->v_type != VDIR) {
86 		vput(lowerrootvp);
87 		return (EINVAL);
88 	}
89 
90 #ifdef UMAPFS_DIAGNOSTIC
91 	printf("mp = %x\n", mp);
92 #endif
93 
94 	amp = (struct umap_mount *) malloc(sizeof(struct umap_mount),
95 				M_UFSMNT, M_WAITOK);	/* XXX */
96 
97 	/*
98 	 * Save reference to underlying FS
99 	 */
100 	amp->umapm_vfs = lowerrootvp->v_mount;
101 
102 	/*
103 	 * Now copy in the number of entries and maps for umap mapping.
104 	 */
105 	amp->info_nentries = args.nentries;
106 	amp->info_gnentries = args.gnentries;
107 	error = copyin(args.mapdata, (caddr_t)amp->info_mapdata,
108 	    2*sizeof(u_long)*args.nentries);
109 	if (error)
110 		return (error);
111 
112 #ifdef UMAP_DIAGNOSTIC
113 	printf("umap_mount:nentries %d\n",args.nentries);
114 	for (i = 0; i < args.nentries; i++)
115 		printf("   %d maps to %d\n", amp->info_mapdata[i][0],
116 	 	    amp->info_mapdata[i][1]);
117 #endif
118 
119 	error = copyin(args.gmapdata, (caddr_t)amp->info_gmapdata,
120 	    2*sizeof(u_long)*args.nentries);
121 	if (error)
122 		return (error);
123 
124 #ifdef UMAP_DIAGNOSTIC
125 	printf("umap_mount:gnentries %d\n",args.gnentries);
126 	for (i = 0; i < args.gnentries; i++)
127 		printf("	group %d maps to %d\n",
128 		    amp->info_gmapdata[i][0],
129 	 	    amp->info_gmapdata[i][1]);
130 #endif
131 
132 
133 	/*
134 	 * Save reference.  Each mount also holds
135 	 * a reference on the root vnode.
136 	 */
137 	error = umap_node_create(mp, lowerrootvp, &vp);
138 	/*
139 	 * Unlock the node (either the lower or the alias)
140 	 */
141 	VOP_UNLOCK(vp);
142 	/*
143 	 * Make sure the node alias worked
144 	 */
145 	if (error) {
146 		vrele(lowerrootvp);
147 		free(amp, M_UFSMNT);	/* XXX */
148 		return (error);
149 	}
150 
151 	/*
152 	 * Keep a held reference to the root vnode.
153 	 * It is vrele'd in umapfs_unmount.
154 	 */
155 	umapm_rootvp = vp;
156 	umapm_rootvp->v_flag |= VROOT;
157 	amp->umapm_rootvp = umapm_rootvp;
158 	if (UMAPVPTOLOWERVP(umapm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
159 		mp->mnt_flag |= MNT_LOCAL;
160 	mp->mnt_data = (qaddr_t) amp;
161 	getnewfsid(mp, MOUNT_LOFS);
162 
163 	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
164 	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
165 	(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
166 	    &size);
167 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
168 #ifdef UMAPFS_DIAGNOSTIC
169 	printf("umapfs_mount: lower %s, alias at %s\n",
170 		mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
171 #endif
172 	return (0);
173 }
174 
175 /*
176  * VFS start.  Nothing needed here - the start routine
177  * on the underlying filesystem will have been called
178  * when that filesystem was mounted.
179  */
180 int
181 umapfs_start(mp, flags, p)
182 	struct mount *mp;
183 	int flags;
184 	struct proc *p;
185 {
186 	return (0);
187 	/* return (VFS_START(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, flags, p)); */
188 }
189 
190 /*
191  * Free reference to umap layer
192  */
193 int
194 umapfs_unmount(mp, mntflags, p)
195 	struct mount *mp;
196 	int mntflags;
197 	struct proc *p;
198 {
199 	struct vnode *umapm_rootvp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp;
200 	int error;
201 	int flags = 0;
202 	extern int doforce;
203 
204 #ifdef UMAPFS_DIAGNOSTIC
205 	printf("umapfs_unmount(mp = %x)\n", mp);
206 #endif
207 
208 	if (mntflags & MNT_FORCE) {
209 		/* lofs can never be rootfs so don't check for it */
210 		if (!doforce)
211 			return (EINVAL);
212 		flags |= FORCECLOSE;
213 	}
214 
215 	/*
216 	 * Clear out buffer cache.  I don't think we
217 	 * ever get anything cached at this level at the
218 	 * moment, but who knows...
219 	 */
220 #ifdef notyet
221 	mntflushbuf(mp, 0);
222 	if (mntinvalbuf(mp, 1))
223 		return (EBUSY);
224 #endif
225 	if (umapm_rootvp->v_usecount > 1)
226 		return (EBUSY);
227 	if (error = vflush(mp, umapm_rootvp, flags))
228 		return (error);
229 
230 #ifdef UMAPFS_DIAGNOSTIC
231 	vprint("alias root of lower", umapm_rootvp);
232 #endif
233 	/*
234 	 * Release reference on underlying root vnode
235 	 */
236 	vrele(umapm_rootvp);
237 	/*
238 	 * And blow it away for future re-use
239 	 */
240 	vgone(umapm_rootvp);
241 	/*
242 	 * Finally, throw away the umap_mount structure
243 	 */
244 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
245 	mp->mnt_data = 0;
246 	return (0);
247 }
248 
249 int
250 umapfs_root(mp, vpp)
251 	struct mount *mp;
252 	struct vnode **vpp;
253 {
254 	struct vnode *vp;
255 
256 #ifdef UMAPFS_DIAGNOSTIC
257 	printf("umapfs_root(mp = %x, vp = %x->%x)\n", mp,
258 			MOUNTTOUMAPMOUNT(mp)->umapm_rootvp,
259 			UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp)
260 			);
261 #endif
262 
263 	/*
264 	 * Return locked reference to root.
265 	 */
266 	vp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp;
267 	VREF(vp);
268 	VOP_LOCK(vp);
269 	*vpp = vp;
270 	return (0);
271 }
272 
273 int
274 umapfs_quotactl(mp, cmd, uid, arg, p)
275 	struct mount *mp;
276 	int cmd;
277 	uid_t uid;
278 	caddr_t arg;
279 	struct proc *p;
280 {
281 	return (VFS_QUOTACTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, uid, arg, p));
282 }
283 
284 int
285 umapfs_statfs(mp, sbp, p)
286 	struct mount *mp;
287 	struct statfs *sbp;
288 	struct proc *p;
289 {
290 	int error;
291 	struct statfs mstat;
292 
293 #ifdef UMAPFS_DIAGNOSTIC
294 	printf("umapfs_statfs(mp = %x, vp = %x->%x)\n", mp,
295 			MOUNTTOUMAPMOUNT(mp)->umapm_rootvp,
296 			UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp)
297 			);
298 #endif
299 
300 	bzero(&mstat, sizeof(mstat));
301 
302 	error = VFS_STATFS(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, &mstat, p);
303 	if (error)
304 		return (error);
305 
306 	/* now copy across the "interesting" information and fake the rest */
307 	sbp->f_type = mstat.f_type;
308 	sbp->f_flags = mstat.f_flags;
309 	sbp->f_bsize = mstat.f_bsize;
310 	sbp->f_iosize = mstat.f_iosize;
311 	sbp->f_blocks = mstat.f_blocks;
312 	sbp->f_bfree = mstat.f_bfree;
313 	sbp->f_bavail = mstat.f_bavail;
314 	sbp->f_files = mstat.f_files;
315 	sbp->f_ffree = mstat.f_ffree;
316 	if (sbp != &mp->mnt_stat) {
317 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
318 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
319 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
320 	}
321 	return (0);
322 }
323 
324 int
325 umapfs_sync(mp, waitfor, cred, p)
326 	struct mount *mp;
327 	int waitfor;
328 	struct ucred *cred;
329 	struct proc *p;
330 {
331 	/*
332 	 * XXX - Assumes no data cached at umap layer.
333 	 */
334 	return (0);
335 }
336 
337 int
338 umapfs_vget(mp, ino, vpp)
339 	struct mount *mp;
340 	ino_t ino;
341 	struct vnode **vpp;
342 {
343 
344 	return (VFS_VGET(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, ino, vpp));
345 }
346 
347 int
348 umapfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
349 	struct mount *mp;
350 	struct fid *fidp;
351 	struct mbuf *nam;
352 	struct vnode **vpp;
353 	int *exflagsp;
354 	struct ucred**credanonp;
355 {
356 
357 	return (VFS_FHTOVP(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, fidp, nam, vpp, exflagsp,credanonp));
358 }
359 
360 int
361 umapfs_vptofh(vp, fhp)
362 	struct vnode *vp;
363 	struct fid *fhp;
364 {
365 	return (VFS_VPTOFH(UMAPVPTOLOWERVP(vp), fhp));
366 }
367 
368 int umapfs_init __P((void));
369 
370 struct vfsops umap_vfsops = {
371 	umapfs_mount,
372 	umapfs_start,
373 	umapfs_unmount,
374 	umapfs_root,
375 	umapfs_quotactl,
376 	umapfs_statfs,
377 	umapfs_sync,
378 	umapfs_vget,
379 	umapfs_fhtovp,
380 	umapfs_vptofh,
381 	umapfs_init,
382 };
383