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