1 /*
2  * Copyright (c) 1992, 1993, 1995
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software donated to Berkeley by
6  * the UCLA Ficus project.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)umap_vfsops.c	8.8 (Berkeley) 05/14/95
11  *
12  * @(#)null_vfsops.c       1.5 (Berkeley) 7/10/92
13  */
14 
15 /*
16  * Umap Layer
17  * (See mount_umap(8) for a description of this layer.)
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/proc.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, 0, p);
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 	vfs_getnewfsid(mp);
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 
203 #ifdef UMAPFS_DIAGNOSTIC
204 	printf("umapfs_unmount(mp = %x)\n", mp);
205 #endif
206 
207 	if (mntflags & MNT_FORCE)
208 		flags |= FORCECLOSE;
209 
210 	/*
211 	 * Clear out buffer cache.  I don't think we
212 	 * ever get anything cached at this level at the
213 	 * moment, but who knows...
214 	 */
215 #ifdef notyet
216 	mntflushbuf(mp, 0);
217 	if (mntinvalbuf(mp, 1))
218 		return (EBUSY);
219 #endif
220 	if (umapm_rootvp->v_usecount > 1)
221 		return (EBUSY);
222 	if (error = vflush(mp, umapm_rootvp, flags))
223 		return (error);
224 
225 #ifdef UMAPFS_DIAGNOSTIC
226 	vprint("alias root of lower", umapm_rootvp);
227 #endif
228 	/*
229 	 * Release reference on underlying root vnode
230 	 */
231 	vrele(umapm_rootvp);
232 	/*
233 	 * And blow it away for future re-use
234 	 */
235 	vgone(umapm_rootvp);
236 	/*
237 	 * Finally, throw away the umap_mount structure
238 	 */
239 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
240 	mp->mnt_data = 0;
241 	return (0);
242 }
243 
244 int
245 umapfs_root(mp, vpp)
246 	struct mount *mp;
247 	struct vnode **vpp;
248 {
249 	struct proc *p = curproc;	/* XXX */
250 	struct vnode *vp;
251 
252 #ifdef UMAPFS_DIAGNOSTIC
253 	printf("umapfs_root(mp = %x, vp = %x->%x)\n", mp,
254 			MOUNTTOUMAPMOUNT(mp)->umapm_rootvp,
255 			UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp)
256 			);
257 #endif
258 
259 	/*
260 	 * Return locked reference to root.
261 	 */
262 	vp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp;
263 	VREF(vp);
264 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
265 	*vpp = vp;
266 	return (0);
267 }
268 
269 int
270 umapfs_quotactl(mp, cmd, uid, arg, p)
271 	struct mount *mp;
272 	int cmd;
273 	uid_t uid;
274 	caddr_t arg;
275 	struct proc *p;
276 {
277 	return (VFS_QUOTACTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, uid, arg, p));
278 }
279 
280 int
281 umapfs_statfs(mp, sbp, p)
282 	struct mount *mp;
283 	struct statfs *sbp;
284 	struct proc *p;
285 {
286 	int error;
287 	struct statfs mstat;
288 
289 #ifdef UMAPFS_DIAGNOSTIC
290 	printf("umapfs_statfs(mp = %x, vp = %x->%x)\n", mp,
291 			MOUNTTOUMAPMOUNT(mp)->umapm_rootvp,
292 			UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp)
293 			);
294 #endif
295 
296 	bzero(&mstat, sizeof(mstat));
297 
298 	error = VFS_STATFS(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, &mstat, p);
299 	if (error)
300 		return (error);
301 
302 	/* now copy across the "interesting" information and fake the rest */
303 	sbp->f_type = mstat.f_type;
304 	sbp->f_flags = mstat.f_flags;
305 	sbp->f_bsize = mstat.f_bsize;
306 	sbp->f_iosize = mstat.f_iosize;
307 	sbp->f_blocks = mstat.f_blocks;
308 	sbp->f_bfree = mstat.f_bfree;
309 	sbp->f_bavail = mstat.f_bavail;
310 	sbp->f_files = mstat.f_files;
311 	sbp->f_ffree = mstat.f_ffree;
312 	if (sbp != &mp->mnt_stat) {
313 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
314 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
315 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
316 	}
317 	return (0);
318 }
319 
320 int
321 umapfs_sync(mp, waitfor, cred, p)
322 	struct mount *mp;
323 	int waitfor;
324 	struct ucred *cred;
325 	struct proc *p;
326 {
327 	/*
328 	 * XXX - Assumes no data cached at umap layer.
329 	 */
330 	return (0);
331 }
332 
333 int
334 umapfs_vget(mp, ino, vpp)
335 	struct mount *mp;
336 	ino_t ino;
337 	struct vnode **vpp;
338 {
339 
340 	return (VFS_VGET(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, ino, vpp));
341 }
342 
343 int
344 umapfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
345 	struct mount *mp;
346 	struct fid *fidp;
347 	struct mbuf *nam;
348 	struct vnode **vpp;
349 	int *exflagsp;
350 	struct ucred**credanonp;
351 {
352 
353 	return (VFS_FHTOVP(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, fidp, nam, vpp, exflagsp,credanonp));
354 }
355 
356 int
357 umapfs_vptofh(vp, fhp)
358 	struct vnode *vp;
359 	struct fid *fhp;
360 {
361 	return (VFS_VPTOFH(UMAPVPTOLOWERVP(vp), fhp));
362 }
363 
364 int umapfs_init __P((struct vfsconf *));
365 #define umapfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
366 	    size_t, struct proc *)))eopnotsupp)
367 
368 struct vfsops umap_vfsops = {
369 	umapfs_mount,
370 	umapfs_start,
371 	umapfs_unmount,
372 	umapfs_root,
373 	umapfs_quotactl,
374 	umapfs_statfs,
375 	umapfs_sync,
376 	umapfs_vget,
377 	umapfs_fhtovp,
378 	umapfs_vptofh,
379 	umapfs_init,
380 	umapfs_sysctl,
381 };
382