null_vfsops.c revision 1541
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: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $
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 */
60int
61nullfs_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 */
164int
165nullfs_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 */
177int
178nullfs_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
233int
234nullfs_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
257int
258nullfs_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
268int
269nullfs_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
308int
309nullfs_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
321int
322nullfs_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
331int
332nullfs_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
344int
345nullfs_vptofh(vp, fhp)
346	struct vnode *vp;
347	struct fid *fhp;
348{
349	return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp);
350}
351
352int nullfs_init __P((void));
353
354struct 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