null_vfsops.c revision 1.1.1.1 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 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94
37 *
38 * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92
39 * $Id: null_vfsops.c,v 1.1.1.1 1998/03/01 02:09:59 fvdl Exp $
40 */
41
42 /*
43 * Null Layer
44 * (See null_vnops.c for a description of what this does.)
45 */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/time.h>
50 #include <sys/types.h>
51 #include <sys/vnode.h>
52 #include <sys/mount.h>
53 #include <sys/namei.h>
54 #include <sys/malloc.h>
55 #include <miscfs/nullfs/null.h>
56
57 /*
58 * Mount null layer
59 */
60 int
61 nullfs_mount(mp, path, data, ndp, p)
62 struct mount *mp;
63 char *path;
64 caddr_t data;
65 struct nameidata *ndp;
66 struct proc *p;
67 {
68 int error = 0;
69 struct null_args args;
70 struct vnode *lowerrootvp, *vp;
71 struct vnode *nullm_rootvp;
72 struct null_mount *xmp;
73 u_int size;
74
75 #ifdef NULLFS_DIAGNOSTIC
76 printf("nullfs_mount(mp = %x)\n", mp);
77 #endif
78
79 /*
80 * Update is a no-op
81 */
82 if (mp->mnt_flag & MNT_UPDATE) {
83 return (EOPNOTSUPP);
84 /* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/
85 }
86
87 /*
88 * Get argument
89 */
90 if (error = copyin(data, (caddr_t)&args, sizeof(struct null_args)))
91 return (error);
92
93 /*
94 * Find lower node
95 */
96 NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
97 UIO_USERSPACE, args.target, p);
98 if (error = namei(ndp))
99 return (error);
100
101 /*
102 * Sanity check on lower vnode
103 */
104 lowerrootvp = ndp->ni_vp;
105
106 vrele(ndp->ni_dvp);
107 ndp->ni_dvp = NULL;
108
109 xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
110 M_UFSMNT, M_WAITOK); /* XXX */
111
112 /*
113 * Save reference to underlying FS
114 */
115 xmp->nullm_vfs = lowerrootvp->v_mount;
116
117 /*
118 * Save reference. Each mount also holds
119 * a reference on the root vnode.
120 */
121 error = null_node_create(mp, lowerrootvp, &vp);
122 /*
123 * Unlock the node (either the lower or the alias)
124 */
125 VOP_UNLOCK(vp);
126 /*
127 * Make sure the node alias worked
128 */
129 if (error) {
130 vrele(lowerrootvp);
131 free(xmp, M_UFSMNT); /* XXX */
132 return (error);
133 }
134
135 /*
136 * Keep a held reference to the root vnode.
137 * It is vrele'd in nullfs_unmount.
138 */
139 nullm_rootvp = vp;
140 nullm_rootvp->v_flag |= VROOT;
141 xmp->nullm_rootvp = nullm_rootvp;
142 if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
143 mp->mnt_flag |= MNT_LOCAL;
144 mp->mnt_data = (qaddr_t) xmp;
145 getnewfsid(mp, MOUNT_LOFS);
146
147 (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
148 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
149 (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
150 &size);
151 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
152 #ifdef NULLFS_DIAGNOSTIC
153 printf("nullfs_mount: lower %s, alias at %s\n",
154 mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
155 #endif
156 return (0);
157 }
158
159 /*
160 * VFS start. Nothing needed here - the start routine
161 * on the underlying filesystem will have been called
162 * when that filesystem was mounted.
163 */
164 int
165 nullfs_start(mp, flags, p)
166 struct mount *mp;
167 int flags;
168 struct proc *p;
169 {
170 return (0);
171 /* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */
172 }
173
174 /*
175 * Free reference to null layer
176 */
177 int
178 nullfs_unmount(mp, mntflags, p)
179 struct mount *mp;
180 int mntflags;
181 struct proc *p;
182 {
183 struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
184 int error;
185 int flags = 0;
186 extern int doforce;
187
188 #ifdef NULLFS_DIAGNOSTIC
189 printf("nullfs_unmount(mp = %x)\n", mp);
190 #endif
191
192 if (mntflags & MNT_FORCE) {
193 /* lofs can never be rootfs so don't check for it */
194 if (!doforce)
195 return (EINVAL);
196 flags |= FORCECLOSE;
197 }
198
199 /*
200 * Clear out buffer cache. I don't think we
201 * ever get anything cached at this level at the
202 * moment, but who knows...
203 */
204 #if 0
205 mntflushbuf(mp, 0);
206 if (mntinvalbuf(mp, 1))
207 return (EBUSY);
208 #endif
209 if (nullm_rootvp->v_usecount > 1)
210 return (EBUSY);
211 if (error = vflush(mp, nullm_rootvp, flags))
212 return (error);
213
214 #ifdef NULLFS_DIAGNOSTIC
215 vprint("alias root of lower", nullm_rootvp);
216 #endif
217 /*
218 * Release reference on underlying root vnode
219 */
220 vrele(nullm_rootvp);
221 /*
222 * And blow it away for future re-use
223 */
224 vgone(nullm_rootvp);
225 /*
226 * Finally, throw away the null_mount structure
227 */
228 free(mp->mnt_data, M_UFSMNT); /* XXX */
229 mp->mnt_data = 0;
230 return 0;
231 }
232
233 int
234 nullfs_root(mp, vpp)
235 struct mount *mp;
236 struct vnode **vpp;
237 {
238 struct vnode *vp;
239
240 #ifdef NULLFS_DIAGNOSTIC
241 printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp,
242 MOUNTTONULLMOUNT(mp)->nullm_rootvp,
243 NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
244 );
245 #endif
246
247 /*
248 * Return locked reference to root.
249 */
250 vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
251 VREF(vp);
252 VOP_LOCK(vp);
253 *vpp = vp;
254 return 0;
255 }
256
257 int
258 nullfs_quotactl(mp, cmd, uid, arg, p)
259 struct mount *mp;
260 int cmd;
261 uid_t uid;
262 caddr_t arg;
263 struct proc *p;
264 {
265 return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p);
266 }
267
268 int
269 nullfs_statfs(mp, sbp, p)
270 struct mount *mp;
271 struct statfs *sbp;
272 struct proc *p;
273 {
274 int error;
275 struct statfs mstat;
276
277 #ifdef NULLFS_DIAGNOSTIC
278 printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp,
279 MOUNTTONULLMOUNT(mp)->nullm_rootvp,
280 NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
281 );
282 #endif
283
284 bzero(&mstat, sizeof(mstat));
285
286 error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p);
287 if (error)
288 return (error);
289
290 /* now copy across the "interesting" information and fake the rest */
291 sbp->f_type = mstat.f_type;
292 sbp->f_flags = mstat.f_flags;
293 sbp->f_bsize = mstat.f_bsize;
294 sbp->f_iosize = mstat.f_iosize;
295 sbp->f_blocks = mstat.f_blocks;
296 sbp->f_bfree = mstat.f_bfree;
297 sbp->f_bavail = mstat.f_bavail;
298 sbp->f_files = mstat.f_files;
299 sbp->f_ffree = mstat.f_ffree;
300 if (sbp != &mp->mnt_stat) {
301 bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
302 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
303 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
304 }
305 return (0);
306 }
307
308 int
309 nullfs_sync(mp, waitfor, cred, p)
310 struct mount *mp;
311 int waitfor;
312 struct ucred *cred;
313 struct proc *p;
314 {
315 /*
316 * XXX - Assumes no data cached at null layer.
317 */
318 return (0);
319 }
320
321 int
322 nullfs_vget(mp, ino, vpp)
323 struct mount *mp;
324 ino_t ino;
325 struct vnode **vpp;
326 {
327
328 return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
329 }
330
331 int
332 nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
333 struct mount *mp;
334 struct fid *fidp;
335 struct mbuf *nam;
336 struct vnode **vpp;
337 int *exflagsp;
338 struct ucred**credanonp;
339 {
340
341 return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp);
342 }
343
344 int
345 nullfs_vptofh(vp, fhp)
346 struct vnode *vp;
347 struct fid *fhp;
348 {
349 return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp);
350 }
351
352 int nullfs_init __P((void));
353
354 struct vfsops null_vfsops = {
355 nullfs_mount,
356 nullfs_start,
357 nullfs_unmount,
358 nullfs_root,
359 nullfs_quotactl,
360 nullfs_statfs,
361 nullfs_sync,
362 nullfs_vget,
363 nullfs_fhtovp,
364 nullfs_vptofh,
365 nullfs_init,
366 };
367