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