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  *	@(#)lofs_vfsops.c	1.3 (Berkeley) 07/12/92
12  *
13  * $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $
14  */
15 
16 /*
17  * Loopback Filesystem
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/vnode.h>
25 #include <sys/mount.h>
26 #include <sys/namei.h>
27 #include <sys/malloc.h>
28 #include <lofs/lofs.h>
29 
30 /*
31  * Mount loopback copy of existing name space
32  */
33 lofs_mount(mp, path, data, ndp, p)
34 	struct mount *mp;
35 	char *path;
36 	caddr_t data;
37 	struct nameidata *ndp;
38 	struct proc *p;
39 {
40 	int error = 0;
41 	struct lofs_args args;
42 	struct vnode *vp;
43 	struct vnode *rootvp;
44 	struct lofsmount *amp;
45 	u_int size;
46 
47 #ifdef LOFS_DIAGNOSTIC
48 	printf("lofs_mount(mp = %x)\n", mp);
49 #endif
50 
51 	/*
52 	 * Update is a no-op
53 	 */
54 	if (mp->mnt_flag & MNT_UPDATE) {
55 		return (EOPNOTSUPP);
56 		/* return VFS_MOUNT(VFSTOLOFS(mp)->looped_vfs, path, data, ndp, p);*/
57 	}
58 
59 	/*
60 	 * Get argument
61 	 */
62 	if (error = copyin(data, (caddr_t)&args, sizeof(struct lofs_args)))
63 		return (error);
64 
65 	/*
66 	 * Find target node
67 	 */
68 	NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
69 		UIO_USERSPACE, args.target, p);
70 	if (error = namei(ndp))
71 		return (error);
72 
73 	/*
74 	 * Sanity check on target vnode
75 	 */
76 	vp = ndp->ni_vp;
77 #ifdef LOFS_DIAGNOSTIC
78 	printf("vp = %x, check for VDIR...\n", vp);
79 #endif
80 	vrele(ndp->ni_dvp);
81 	ndp->ni_dvp = 0;
82 
83 	if (vp->v_type != VDIR) {
84 		vput(vp);
85 		return (EINVAL);
86 	}
87 
88 #ifdef LOFS_DIAGNOSTIC
89 	printf("mp = %x\n", mp);
90 #endif
91 
92 	amp = (struct lofsmount *) malloc(sizeof(struct lofsmount),
93 				M_UFSMNT, M_WAITOK);	/* XXX */
94 
95 	/*
96 	 * Save reference to underlying target FS
97 	 */
98 	amp->looped_vfs = vp->v_mount;
99 
100 	/*
101 	 * Save reference.  Each mount also holds
102 	 * a reference on the root vnode.
103 	 */
104 	error = make_lofs(mp, &vp);
105 	/*
106 	 * Unlock the node (either the target or the alias)
107 	 */
108 	VOP_UNLOCK(vp);
109 	/*
110 	 * Make sure the node alias worked
111 	 */
112 	if (error) {
113 		vrele(vp);
114 		free(amp, M_UFSMNT);	/* XXX */
115 		return (error);
116 	}
117 
118 	/*
119 	 * Keep a held reference to the root vnode.
120 	 * It is vrele'd in lofs_unmount.
121 	 */
122 	rootvp = vp;
123 	rootvp->v_flag |= VROOT;
124 	amp->rootvp = rootvp;
125 	if (LOFSVP(rootvp)->v_mount->mnt_flag & MNT_LOCAL)
126 		mp->mnt_flag |= MNT_LOCAL;
127 	mp->mnt_data = (qaddr_t) amp;
128 	getnewfsid(mp, MOUNT_LOFS);
129 
130 	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
131 	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
132 	(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
133 	    &size);
134 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
135 #ifdef LOFS_DIAGNOSTIC
136 	printf("lofs_mount: target %s, alias at %s\n",
137 		mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
138 #endif
139 	return (0);
140 }
141 
142 /*
143  * VFS start.  Nothing needed here - the start routine
144  * on the underlying filesystem will have been called
145  * when that filesystem was mounted.
146  */
147 lofs_start(mp, flags, p)
148 	struct mount *mp;
149 	int flags;
150 	struct proc *p;
151 {
152 	return (0);
153 	/* return VFS_START(VFSTOLOFS(mp)->looped_vfs, flags, p); */
154 }
155 
156 /*
157  * Free reference to looped FS
158  */
159 lofs_unmount(mp, mntflags, p)
160 	struct mount *mp;
161 	int mntflags;
162 	struct proc *p;
163 {
164 	struct vnode *rootvp = VFSTOLOFS(mp)->rootvp;
165 	int error;
166 	int flags = 0;
167 	extern int doforce;
168 
169 #ifdef LOFS_DIAGNOSTIC
170 	printf("lofs_unmount(mp = %x)\n", mp);
171 #endif
172 
173 	if (mntflags & MNT_FORCE) {
174 		/* lofs can never be rootfs so don't check for it */
175 		if (!doforce)
176 			return (EINVAL);
177 		flags |= FORCECLOSE;
178 	}
179 
180 	/*
181 	 * Clear out buffer cache.  I don't think we
182 	 * ever get anything cached at this level at the
183 	 * moment, but who knows...
184 	 */
185 	/* mntflushbuf(mp, 0);  */
186 	/* if (mntinvalbuf(mp, 1))
187 		return (EBUSY); */
188 	if (rootvp->v_usecount > 1)
189 		return (EBUSY);
190 	if (error = vflush(mp, rootvp, flags))
191 		return (error);
192 
193 #ifdef LOFS_DIAGNOSTIC
194 	/*
195 	 * Flush any remaining vnode references
196 	 */
197 	lofs_flushmp(mp);
198 #endif
199 
200 #ifdef LOFS_DIAGNOSTIC
201 	vprint("alias root of target", rootvp);
202 #endif
203 	/*
204 	 * Release reference on underlying root vnode
205 	 */
206 	vrele(rootvp);
207 	/*
208 	 * And blow it away for future re-use
209 	 */
210 	vgone(rootvp);
211 	/*
212 	 * Finally, throw away the lofsmount structure
213 	 */
214 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
215 	mp->mnt_data = 0;
216 	return 0;
217 }
218 
219 lofs_root(mp, vpp)
220 	struct mount *mp;
221 	struct vnode **vpp;
222 {
223 	struct vnode *vp;
224 
225 #ifdef LOFS_DIAGNOSTIC
226 	printf("lofs_root(mp = %x, vp = %x->%x)\n", mp,
227 			VFSTOLOFS(mp)->rootvp,
228 			LOFSVP(VFSTOLOFS(mp)->rootvp)
229 			);
230 #endif
231 
232 	/*
233 	 * Return locked reference to root.
234 	 */
235 	vp = VFSTOLOFS(mp)->rootvp;
236 	VREF(vp);
237 	VOP_LOCK(vp);
238 	*vpp = vp;
239 	return 0;
240 }
241 
242 lofs_quotactl(mp, cmd, uid, arg, p)
243 	struct mount *mp;
244 	int cmd;
245 	uid_t uid;
246 	caddr_t arg;
247 	struct proc *p;
248 {
249 	return VFS_QUOTACTL(VFSTOLOFS(mp)->looped_vfs, cmd, uid, arg, p);
250 }
251 
252 lofs_statfs(mp, sbp, p)
253 	struct mount *mp;
254 	struct statfs *sbp;
255 	struct proc *p;
256 {
257 	int error;
258 	struct statfs mstat;
259 
260 #ifdef LOFS_DIAGNOSTIC
261 	printf("lofs_statfs(mp = %x, vp = %x->%x)\n", mp,
262 			VFSTOLOFS(mp)->rootvp,
263 			LOFSVP(VFSTOLOFS(mp)->rootvp)
264 			);
265 #endif
266 
267 	bzero(&mstat, sizeof(mstat));
268 
269 	error = VFS_STATFS(VFSTOLOFS(mp)->looped_vfs, &mstat, p);
270 	if (error)
271 		return (error);
272 
273 	/* now copy across the "interesting" information and fake the rest */
274 	sbp->f_type = mstat.f_type;
275 	sbp->f_flags = mstat.f_flags;
276 	sbp->f_bsize = mstat.f_bsize;
277 	sbp->f_iosize = mstat.f_iosize;
278 	sbp->f_blocks = mstat.f_blocks;
279 	sbp->f_bfree = mstat.f_bfree;
280 	sbp->f_bavail = mstat.f_bavail;
281 	sbp->f_files = mstat.f_files;
282 	sbp->f_ffree = mstat.f_ffree;
283 	if (sbp != &mp->mnt_stat) {
284 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
285 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
286 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
287 	}
288 	return (0);
289 }
290 
291 lofs_sync(mp, waitfor)
292 struct mount *mp;
293 int waitfor;
294 {
295 	return (0);
296 }
297 
298 /*
299  * LOFS flat namespace lookup.
300  * Currently unsupported.
301  */
302 lofs_vget(mp, ino, vpp)
303 	struct mount *mp;
304 	ino_t ino;
305 	struct vnode **vpp;
306 {
307 
308 	return (EOPNOTSUPP);
309 }
310 
311 lofs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
312 	register struct mount *mp;
313 	struct fid *fhp;
314 	struct mbuf *nam;
315 	struct vnode **vpp;
316 	int *exflagsp;
317 	struct ucred **credanonp;
318 {
319 	return VFS_FHTOVP(VFSTOLOFS(mp)->looped_vfs, fhp, nam, vpp, exflagsp, credanonp);
320 }
321 
322 lofs_vptofh(vp, fhp)
323 	struct vnode *vp;
324 	struct fid *fhp;
325 {
326 	return VFS_VPTOFH(LOFSVP(vp), fhp);
327 }
328 
329 int lofs_init __P((void));
330 
331 struct vfsops lofs_vfsops = {
332 	lofs_mount,
333 	lofs_start,
334 	lofs_unmount,
335 	lofs_root,
336 	lofs_quotactl,
337 	lofs_statfs,
338 	lofs_sync,
339 	lofs_vget,
340 	lofs_fhtovp,
341 	lofs_vptofh,
342 	lofs_init,
343 };
344