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