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
lofs_mount(mp,path,data,ndp,p)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
lofs_start(mp,flags,p)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
lofs_unmount(mp,mntflags,p)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
lofs_root(mp,vpp)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
lofs_quotactl(mp,cmd,uid,arg,p)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
lofs_statfs(mp,sbp,p)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
lofs_sync(mp,waitfor)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
lofs_vget(mp,ino,vpp)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
lofs_fhtovp(mp,fhp,nam,vpp,exflagsp,credanonp)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
lofs_vptofh(vp,fhp)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