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