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  *	@(#)lofs_vfsops.c	8.1 (Berkeley) 06/10/93
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 <miscfs/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 	if (rootvp->v_usecount > 1)
186 		return (EBUSY);
187 	if (error = vflush(mp, rootvp, flags))
188 		return (error);
189 
190 #ifdef LOFS_DIAGNOSTIC
191 	/*
192 	 * Flush any remaining vnode references
193 	 */
194 	lofs_flushmp(mp);
195 #endif
196 
197 #ifdef LOFS_DIAGNOSTIC
198 	vprint("alias root of target", rootvp);
199 #endif
200 	/*
201 	 * Release reference on underlying root vnode
202 	 */
203 	vrele(rootvp);
204 	/*
205 	 * And blow it away for future re-use
206 	 */
207 	vgone(rootvp);
208 	/*
209 	 * Finally, throw away the lofsmount structure
210 	 */
211 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
212 	mp->mnt_data = 0;
213 	return 0;
214 }
215 
216 lofs_root(mp, vpp)
217 	struct mount *mp;
218 	struct vnode **vpp;
219 {
220 	struct vnode *vp;
221 
222 #ifdef LOFS_DIAGNOSTIC
223 	printf("lofs_root(mp = %x, vp = %x->%x)\n", mp,
224 			VFSTOLOFS(mp)->rootvp,
225 			LOFSVP(VFSTOLOFS(mp)->rootvp)
226 			);
227 #endif
228 
229 	/*
230 	 * Return locked reference to root.
231 	 */
232 	vp = VFSTOLOFS(mp)->rootvp;
233 	VREF(vp);
234 	VOP_LOCK(vp);
235 	*vpp = vp;
236 	return 0;
237 }
238 
239 lofs_quotactl(mp, cmd, uid, arg, p)
240 	struct mount *mp;
241 	int cmd;
242 	uid_t uid;
243 	caddr_t arg;
244 	struct proc *p;
245 {
246 	return VFS_QUOTACTL(VFSTOLOFS(mp)->looped_vfs, cmd, uid, arg, p);
247 }
248 
249 lofs_statfs(mp, sbp, p)
250 	struct mount *mp;
251 	struct statfs *sbp;
252 	struct proc *p;
253 {
254 	int error;
255 	struct statfs mstat;
256 
257 #ifdef LOFS_DIAGNOSTIC
258 	printf("lofs_statfs(mp = %x, vp = %x->%x)\n", mp,
259 			VFSTOLOFS(mp)->rootvp,
260 			LOFSVP(VFSTOLOFS(mp)->rootvp)
261 			);
262 #endif
263 
264 	bzero(&mstat, sizeof(mstat));
265 
266 	error = VFS_STATFS(VFSTOLOFS(mp)->looped_vfs, &mstat, p);
267 	if (error)
268 		return (error);
269 
270 	/* now copy across the "interesting" information and fake the rest */
271 	sbp->f_type = mstat.f_type;
272 	sbp->f_flags = mstat.f_flags;
273 	sbp->f_bsize = mstat.f_bsize;
274 	sbp->f_iosize = mstat.f_iosize;
275 	sbp->f_blocks = mstat.f_blocks;
276 	sbp->f_bfree = mstat.f_bfree;
277 	sbp->f_bavail = mstat.f_bavail;
278 	sbp->f_files = mstat.f_files;
279 	sbp->f_ffree = mstat.f_ffree;
280 	if (sbp != &mp->mnt_stat) {
281 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
282 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
283 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
284 	}
285 	return (0);
286 }
287 
288 lofs_sync(mp, waitfor)
289 struct mount *mp;
290 int waitfor;
291 {
292 	return (0);
293 }
294 
295 /*
296  * LOFS flat namespace lookup.
297  * Currently unsupported.
298  */
299 lofs_vget(mp, ino, vpp)
300 	struct mount *mp;
301 	ino_t ino;
302 	struct vnode **vpp;
303 {
304 
305 	return (EOPNOTSUPP);
306 }
307 
308 lofs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
309 	register struct mount *mp;
310 	struct fid *fhp;
311 	struct mbuf *nam;
312 	struct vnode **vpp;
313 	int *exflagsp;
314 	struct ucred **credanonp;
315 {
316 	return VFS_FHTOVP(VFSTOLOFS(mp)->looped_vfs, fhp, nam, vpp, exflagsp, credanonp);
317 }
318 
319 lofs_vptofh(vp, fhp)
320 	struct vnode *vp;
321 	struct fid *fhp;
322 {
323 	return VFS_VPTOFH(LOFSVP(vp), fhp);
324 }
325 
326 int lofs_init __P((void));
327 
328 struct vfsops lofs_vfsops = {
329 	lofs_mount,
330 	lofs_start,
331 	lofs_unmount,
332 	lofs_root,
333 	lofs_quotactl,
334 	lofs_statfs,
335 	lofs_sync,
336 	lofs_vget,
337 	lofs_fhtovp,
338 	lofs_vptofh,
339 	lofs_init,
340 };
341