null_vfsops.c revision 2979
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.2 1994/09/21 03:47:01 wollman 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/kernel.h>
50#include <sys/time.h>
51#include <sys/types.h>
52#include <sys/vnode.h>
53#include <sys/mount.h>
54#include <sys/namei.h>
55#include <sys/malloc.h>
56#include <miscfs/nullfs/null.h>
57
58/*
59 * Mount null layer
60 */
61int
62nullfs_mount(mp, path, data, ndp, p)
63	struct mount *mp;
64	char *path;
65	caddr_t data;
66	struct nameidata *ndp;
67	struct proc *p;
68{
69	int error = 0;
70	struct null_args args;
71	struct vnode *lowerrootvp, *vp;
72	struct vnode *nullm_rootvp;
73	struct null_mount *xmp;
74	u_int size;
75
76#ifdef NULLFS_DIAGNOSTIC
77	printf("nullfs_mount(mp = %x)\n", mp);
78#endif
79
80	/*
81	 * Update is a no-op
82	 */
83	if (mp->mnt_flag & MNT_UPDATE) {
84		return (EOPNOTSUPP);
85		/* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/
86	}
87
88	/*
89	 * Get argument
90	 */
91	if (error = copyin(data, (caddr_t)&args, sizeof(struct null_args)))
92		return (error);
93
94	/*
95	 * Find lower node
96	 */
97	NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
98		UIO_USERSPACE, args.target, p);
99	if (error = namei(ndp))
100		return (error);
101
102	/*
103	 * Sanity check on lower vnode
104	 */
105	lowerrootvp = ndp->ni_vp;
106
107	vrele(ndp->ni_dvp);
108	ndp->ni_dvp = NULL;
109
110	xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
111				M_UFSMNT, M_WAITOK);	/* XXX */
112
113	/*
114	 * Save reference to underlying FS
115	 */
116	xmp->nullm_vfs = lowerrootvp->v_mount;
117
118	/*
119	 * Save reference.  Each mount also holds
120	 * a reference on the root vnode.
121	 */
122	error = null_node_create(mp, lowerrootvp, &vp);
123	/*
124	 * Unlock the node (either the lower or the alias)
125	 */
126	VOP_UNLOCK(vp);
127	/*
128	 * Make sure the node alias worked
129	 */
130	if (error) {
131		vrele(lowerrootvp);
132		free(xmp, M_UFSMNT);	/* XXX */
133		return (error);
134	}
135
136	/*
137	 * Keep a held reference to the root vnode.
138	 * It is vrele'd in nullfs_unmount.
139	 */
140	nullm_rootvp = vp;
141	nullm_rootvp->v_flag |= VROOT;
142	xmp->nullm_rootvp = nullm_rootvp;
143	if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
144		mp->mnt_flag |= MNT_LOCAL;
145	mp->mnt_data = (qaddr_t) xmp;
146	getnewfsid(mp, MOUNT_LOFS);
147
148	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
149	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
150	(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
151	    &size);
152	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
153#ifdef NULLFS_DIAGNOSTIC
154	printf("nullfs_mount: lower %s, alias at %s\n",
155		mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
156#endif
157	return (0);
158}
159
160/*
161 * VFS start.  Nothing needed here - the start routine
162 * on the underlying filesystem will have been called
163 * when that filesystem was mounted.
164 */
165int
166nullfs_start(mp, flags, p)
167	struct mount *mp;
168	int flags;
169	struct proc *p;
170{
171	return (0);
172	/* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */
173}
174
175/*
176 * Free reference to null layer
177 */
178int
179nullfs_unmount(mp, mntflags, p)
180	struct mount *mp;
181	int mntflags;
182	struct proc *p;
183{
184	struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
185	int error;
186	int flags = 0;
187	extern int doforce;
188
189#ifdef NULLFS_DIAGNOSTIC
190	printf("nullfs_unmount(mp = %x)\n", mp);
191#endif
192
193	if (mntflags & MNT_FORCE) {
194		/* lofs can never be rootfs so don't check for it */
195		if (!doforce)
196			return (EINVAL);
197		flags |= FORCECLOSE;
198	}
199
200	/*
201	 * Clear out buffer cache.  I don't think we
202	 * ever get anything cached at this level at the
203	 * moment, but who knows...
204	 */
205#if 0
206	mntflushbuf(mp, 0);
207	if (mntinvalbuf(mp, 1))
208		return (EBUSY);
209#endif
210	if (nullm_rootvp->v_usecount > 1)
211		return (EBUSY);
212	if (error = vflush(mp, nullm_rootvp, flags))
213		return (error);
214
215#ifdef NULLFS_DIAGNOSTIC
216	vprint("alias root of lower", nullm_rootvp);
217#endif
218	/*
219	 * Release reference on underlying root vnode
220	 */
221	vrele(nullm_rootvp);
222	/*
223	 * And blow it away for future re-use
224	 */
225	vgone(nullm_rootvp);
226	/*
227	 * Finally, throw away the null_mount structure
228	 */
229	free(mp->mnt_data, M_UFSMNT);	/* XXX */
230	mp->mnt_data = 0;
231	return 0;
232}
233
234int
235nullfs_root(mp, vpp)
236	struct mount *mp;
237	struct vnode **vpp;
238{
239	struct vnode *vp;
240
241#ifdef NULLFS_DIAGNOSTIC
242	printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp,
243			MOUNTTONULLMOUNT(mp)->nullm_rootvp,
244			NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
245			);
246#endif
247
248	/*
249	 * Return locked reference to root.
250	 */
251	vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
252	VREF(vp);
253	VOP_LOCK(vp);
254	*vpp = vp;
255	return 0;
256}
257
258int
259nullfs_quotactl(mp, cmd, uid, arg, p)
260	struct mount *mp;
261	int cmd;
262	uid_t uid;
263	caddr_t arg;
264	struct proc *p;
265{
266	return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p);
267}
268
269int
270nullfs_statfs(mp, sbp, p)
271	struct mount *mp;
272	struct statfs *sbp;
273	struct proc *p;
274{
275	int error;
276	struct statfs mstat;
277
278#ifdef NULLFS_DIAGNOSTIC
279	printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp,
280			MOUNTTONULLMOUNT(mp)->nullm_rootvp,
281			NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
282			);
283#endif
284
285	bzero(&mstat, sizeof(mstat));
286
287	error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p);
288	if (error)
289		return (error);
290
291	/* now copy across the "interesting" information and fake the rest */
292	sbp->f_type = mstat.f_type;
293	sbp->f_flags = mstat.f_flags;
294	sbp->f_bsize = mstat.f_bsize;
295	sbp->f_iosize = mstat.f_iosize;
296	sbp->f_blocks = mstat.f_blocks;
297	sbp->f_bfree = mstat.f_bfree;
298	sbp->f_bavail = mstat.f_bavail;
299	sbp->f_files = mstat.f_files;
300	sbp->f_ffree = mstat.f_ffree;
301	if (sbp != &mp->mnt_stat) {
302		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
303		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
304		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
305	}
306	return (0);
307}
308
309int
310nullfs_sync(mp, waitfor, cred, p)
311	struct mount *mp;
312	int waitfor;
313	struct ucred *cred;
314	struct proc *p;
315{
316	/*
317	 * XXX - Assumes no data cached at null layer.
318	 */
319	return (0);
320}
321
322int
323nullfs_vget(mp, ino, vpp)
324	struct mount *mp;
325	ino_t ino;
326	struct vnode **vpp;
327{
328
329	return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
330}
331
332int
333nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
334	struct mount *mp;
335	struct fid *fidp;
336	struct mbuf *nam;
337	struct vnode **vpp;
338	int *exflagsp;
339	struct ucred**credanonp;
340{
341
342	return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp);
343}
344
345int
346nullfs_vptofh(vp, fhp)
347	struct vnode *vp;
348	struct fid *fhp;
349{
350	return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp);
351}
352
353int nullfs_init __P((void));
354
355struct vfsops null_vfsops = {
356	nullfs_mount,
357	nullfs_start,
358	nullfs_unmount,
359	nullfs_root,
360	nullfs_quotactl,
361	nullfs_statfs,
362	nullfs_sync,
363	nullfs_vget,
364	nullfs_fhtovp,
365	nullfs_vptofh,
366	nullfs_init,
367};
368
369VFS_SET(null_vfsops, null, MOUNT_NULL, 0);
370