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