null_vfsops.c revision 222167
1186681Sed/*-
2186681Sed * Copyright (c) 1992, 1993, 1995
3186681Sed *	The Regents of the University of California.  All rights reserved.
4186681Sed *
5186681Sed * This code is derived from software donated to Berkeley by
6186681Sed * Jan-Simon Pendry.
7186681Sed *
8186681Sed * Redistribution and use in source and binary forms, with or without
9186681Sed * modification, are permitted provided that the following conditions
10186681Sed * are met:
11186681Sed * 1. Redistributions of source code must retain the above copyright
12186681Sed *    notice, this list of conditions and the following disclaimer.
13186681Sed * 2. Redistributions in binary form must reproduce the above copyright
14186681Sed *    notice, this list of conditions and the following disclaimer in the
15186681Sed *    documentation and/or other materials provided with the distribution.
16186681Sed * 4. Neither the name of the University nor the names of its contributors
17186681Sed *    may be used to endorse or promote products derived from this software
18186681Sed *    without specific prior written permission.
19186681Sed *
20186681Sed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21186681Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22186681Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23186681Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24186681Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25186681Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26186681Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27186681Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28186681Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29186681Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30186681Sed * SUCH DAMAGE.
31186681Sed *
32186681Sed *	@(#)null_vfsops.c	8.2 (Berkeley) 1/21/94
33186681Sed *
34186681Sed * @(#)lofs_vfsops.c	1.2 (Berkeley) 6/18/92
35186681Sed * $FreeBSD: head/sys/fs/nullfs/null_vfsops.c 222167 2011-05-22 01:07:54Z rmacklem $
36186681Sed */
37186681Sed
38206141Sed/*
39186681Sed * Null Layer
40186681Sed * (See null_vnops.c for a description of what this does.)
41186681Sed */
42186681Sed
43186681Sed#include <sys/param.h>
44221698Sed#include <sys/systm.h>
45221698Sed#include <sys/fcntl.h>
46221698Sed#include <sys/kernel.h>
47186681Sed#include <sys/lock.h>
48199171Sed#include <sys/malloc.h>
49199171Sed#include <sys/mount.h>
50199171Sed#include <sys/namei.h>
51199171Sed#include <sys/proc.h>
52199171Sed#include <sys/vnode.h>
53199171Sed
54199171Sed#include <fs/nullfs/null.h>
55199171Sed
56199171Sedstatic MALLOC_DEFINE(M_NULLFSMNT, "nullfs_mount", "NULLFS mount structure");
57186681Sed
58186681Sedstatic vfs_fhtovp_t	nullfs_fhtovp;
59186681Sedstatic vfs_mount_t	nullfs_mount;
60186681Sedstatic vfs_quotactl_t	nullfs_quotactl;
61197470Sedstatic vfs_root_t	nullfs_root;
62197470Sedstatic vfs_sync_t	nullfs_sync;
63197470Sedstatic vfs_statfs_t	nullfs_statfs;
64197470Sedstatic vfs_unmount_t	nullfs_unmount;
65186681Sedstatic vfs_vget_t	nullfs_vget;
66186681Sedstatic vfs_extattrctl_t	nullfs_extattrctl;
67186681Sed
68186681Sed/*
69186681Sed * Mount null layer
70186681Sed */
71186681Sedstatic int
72186681Sednullfs_mount(struct mount *mp)
73186681Sed{
74186681Sed	int error = 0;
75186681Sed	struct vnode *lowerrootvp, *vp;
76186681Sed	struct vnode *nullm_rootvp;
77186681Sed	struct null_mount *xmp;
78186681Sed	char *target;
79186681Sed	int isvnunlocked = 0, len;
80186681Sed	struct nameidata nd, *ndp = &nd;
81186681Sed
82186681Sed	NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp);
83186681Sed
84186681Sed	if (mp->mnt_flag & MNT_ROOTFS)
85186681Sed		return (EOPNOTSUPP);
86186681Sed	/*
87186681Sed	 * Update is a no-op
88186681Sed	 */
89186681Sed	if (mp->mnt_flag & MNT_UPDATE) {
90186681Sed		/*
91186681Sed		 * Only support update mounts for NFS export.
92186681Sed		 */
93186681Sed		if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0))
94186681Sed			return (0);
95186681Sed		else
96186681Sed			return (EOPNOTSUPP);
97186681Sed	}
98186681Sed
99186681Sed	/*
100186681Sed	 * Get argument
101186681Sed	 */
102186681Sed	error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len);
103186681Sed	if (error || target[len - 1] != '\0')
104186681Sed		return (EINVAL);
105186681Sed
106186681Sed	/*
107186681Sed	 * Unlock lower node to avoid deadlock.
108186681Sed	 * (XXX) VOP_ISLOCKED is needed?
109186681Sed	 */
110186681Sed	if ((mp->mnt_vnodecovered->v_op == &null_vnodeops) &&
111186681Sed		VOP_ISLOCKED(mp->mnt_vnodecovered)) {
112186681Sed		VOP_UNLOCK(mp->mnt_vnodecovered, 0);
113186681Sed		isvnunlocked = 1;
114186681Sed	}
115186681Sed	/*
116186681Sed	 * Find lower node
117186681Sed	 */
118186681Sed	NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, curthread);
119186681Sed	error = namei(ndp);
120186681Sed	/*
121186681Sed	 * Re-lock vnode.
122186681Sed	 */
123186681Sed	if (isvnunlocked && !VOP_ISLOCKED(mp->mnt_vnodecovered))
124186681Sed		vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY);
125186681Sed
126186681Sed	if (error)
127193184Sed		return (error);
128186681Sed	NDFREE(ndp, NDF_ONLY_PNBUF);
129186681Sed
130186681Sed	/*
131186681Sed	 * Sanity check on lower vnode
132186681Sed	 */
133186681Sed	lowerrootvp = ndp->ni_vp;
134186681Sed
135186681Sed	/*
136186681Sed	 * Check multi null mount to avoid `lock against myself' panic.
137186681Sed	 */
138186681Sed	if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) {
139186681Sed		NULLFSDEBUG("nullfs_mount: multi null mount?\n");
140186681Sed		vput(lowerrootvp);
141186681Sed		return (EDEADLK);
142186681Sed	}
143186681Sed
144186681Sed	xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
145186681Sed				M_NULLFSMNT, M_WAITOK);	/* XXX */
146186681Sed
147186681Sed	/*
148186681Sed	 * Save reference to underlying FS
149186681Sed	 */
150186681Sed	xmp->nullm_vfs = lowerrootvp->v_mount;
151186681Sed
152186681Sed	/*
153186681Sed	 * Save reference.  Each mount also holds
154186681Sed	 * a reference on the root vnode.
155186681Sed	 */
156197117Sed	error = null_nodeget(mp, lowerrootvp, &vp);
157197117Sed	/*
158186681Sed	 * Make sure the node alias worked
159186681Sed	 */
160186681Sed	if (error) {
161186681Sed		VOP_UNLOCK(vp, 0);
162186681Sed		vrele(lowerrootvp);
163186681Sed		free(xmp, M_NULLFSMNT);	/* XXX */
164186681Sed		return (error);
165186681Sed	}
166186681Sed
167186681Sed	/*
168186681Sed	 * Keep a held reference to the root vnode.
169186681Sed	 * It is vrele'd in nullfs_unmount.
170186681Sed	 */
171197853Sed	nullm_rootvp = vp;
172197853Sed	nullm_rootvp->v_vflag |= VV_ROOT;
173197853Sed	xmp->nullm_rootvp = nullm_rootvp;
174197853Sed
175197853Sed	/*
176197853Sed	 * Unlock the node (either the lower or the alias)
177197853Sed	 */
178197853Sed	VOP_UNLOCK(vp, 0);
179197853Sed
180197853Sed	if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) {
181197853Sed		MNT_ILOCK(mp);
182197853Sed		mp->mnt_flag |= MNT_LOCAL;
183197853Sed		MNT_IUNLOCK(mp);
184197853Sed	}
185197853Sed	MNT_ILOCK(mp);
186197853Sed	mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE;
187197853Sed	MNT_IUNLOCK(mp);
188197853Sed	mp->mnt_data =  xmp;
189186681Sed	vfs_getnewfsid(mp);
190186681Sed
191186681Sed	vfs_mountedfrom(mp, target);
192186681Sed
193186681Sed	NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n",
194186681Sed		mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
195186681Sed	return (0);
196186681Sed}
197186681Sed
198186681Sed/*
199186681Sed * Free reference to null layer
200186681Sed */
201186681Sedstatic int
202186798Sednullfs_unmount(mp, mntflags)
203186798Sed	struct mount *mp;
204186798Sed	int mntflags;
205187469Sed{
206197117Sed	void *mntdata;
207197117Sed	int error;
208197117Sed	int flags = 0;
209197520Sed
210187469Sed	NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp);
211187469Sed
212197117Sed	if (mntflags & MNT_FORCE)
213197117Sed		flags |= FORCECLOSE;
214197117Sed
215197520Sed	/* There is 1 extra root vnode reference (nullm_rootvp). */
216187469Sed	error = vflush(mp, 1, flags, curthread);
217186681Sed	if (error)
218186681Sed		return (error);
219186681Sed
220186681Sed	/*
221186681Sed	 * Finally, throw away the null_mount structure
222186681Sed	 */
223186681Sed	mntdata = mp->mnt_data;
224186681Sed	mp->mnt_data = 0;
225186681Sed	free(mntdata, M_NULLFSMNT);
226186681Sed	return 0;
227186681Sed}
228186681Sed
229186681Sedstatic int
230186681Sednullfs_root(mp, flags, vpp)
231186681Sed	struct mount *mp;
232186681Sed	int flags;
233186681Sed	struct vnode **vpp;
234186681Sed{
235186681Sed	struct vnode *vp;
236186681Sed
237186681Sed	NULLFSDEBUG("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp,
238186681Sed	    (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp,
239186681Sed	    (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp));
240186681Sed
241186681Sed	/*
242186681Sed	 * Return locked reference to root.
243186681Sed	 */
244186681Sed	vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
245186681Sed	VREF(vp);
246186681Sed
247186681Sed#ifdef NULLFS_DEBUG
248186681Sed	if (VOP_ISLOCKED(vp))
249186681Sed		panic("root vnode is locked.\n");
250186681Sed#endif
251197117Sed	vn_lock(vp, flags | LK_RETRY);
252186681Sed	*vpp = vp;
253186681Sed	return 0;
254186681Sed}
255186681Sed
256186681Sedstatic int
257186681Sednullfs_quotactl(mp, cmd, uid, arg)
258186681Sed	struct mount *mp;
259186681Sed	int cmd;
260186681Sed	uid_t uid;
261186681Sed	void *arg;
262186681Sed{
263186681Sed	return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg);
264186681Sed}
265186681Sed
266186681Sedstatic int
267186681Sednullfs_statfs(mp, sbp)
268186681Sed	struct mount *mp;
269186681Sed	struct statfs *sbp;
270186681Sed{
271186681Sed	int error;
272186681Sed	struct statfs mstat;
273194293Sed
274186681Sed	NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp,
275186681Sed	    (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp,
276186681Sed	    (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp));
277186681Sed
278186681Sed	bzero(&mstat, sizeof(mstat));
279186681Sed
280186681Sed	error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat);
281186681Sed	if (error)
282186681Sed		return (error);
283186681Sed
284186681Sed	/* now copy across the "interesting" information and fake the rest */
285186681Sed	sbp->f_type = mstat.f_type;
286186681Sed	sbp->f_flags = mstat.f_flags;
287186681Sed	sbp->f_bsize = mstat.f_bsize;
288197117Sed	sbp->f_iosize = mstat.f_iosize;
289197117Sed	sbp->f_blocks = mstat.f_blocks;
290197117Sed	sbp->f_bfree = mstat.f_bfree;
291197117Sed	sbp->f_bavail = mstat.f_bavail;
292197117Sed	sbp->f_files = mstat.f_files;
293197117Sed	sbp->f_ffree = mstat.f_ffree;
294197117Sed	return (0);
295186681Sed}
296186681Sed
297186681Sedstatic int
298186681Sednullfs_sync(mp, waitfor)
299186681Sed	struct mount *mp;
300186681Sed	int waitfor;
301186681Sed{
302186681Sed	/*
303186681Sed	 * XXX - Assumes no data cached at null layer.
304186681Sed	 */
305186681Sed	return (0);
306188391Sed}
307188391Sed
308188391Sedstatic int
309188391Sednullfs_vget(mp, ino, flags, vpp)
310188391Sed	struct mount *mp;
311188391Sed	ino_t ino;
312188391Sed	int flags;
313189617Sed	struct vnode **vpp;
314189617Sed{
315189617Sed	int error;
316189617Sed	error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, flags, vpp);
317189617Sed	if (error)
318189617Sed		return (error);
319189617Sed
320188391Sed	return (null_nodeget(mp, *vpp, vpp));
321188391Sed}
322188391Sed
323188391Sedstatic int
324188391Sednullfs_fhtovp(mp, fidp, flags, vpp)
325188391Sed	struct mount *mp;
326188391Sed	struct fid *fidp;
327186681Sed	int flags;
328186681Sed	struct vnode **vpp;
329186681Sed{
330186681Sed	int error;
331186681Sed	error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, LK_EXCLUSIVE,
332186681Sed	    vpp);
333186681Sed	if (error)
334197117Sed		return (error);
335197117Sed
336197117Sed	return (null_nodeget(mp, *vpp, vpp));
337197117Sed}
338197117Sed
339197117Sedstatic int
340197117Sednullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname)
341186681Sed	struct mount *mp;
342186681Sed	int cmd;
343186681Sed	struct vnode *filename_vp;
344186681Sed	int namespace;
345186681Sed	const char *attrname;
346197114Sed{
347186681Sed	return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp,
348186681Sed	    namespace, attrname);
349197115Sed}
350259016Sray
351259016Sray
352259016Sraystatic struct vfsops null_vfsops = {
353259016Sray	.vfs_extattrctl =	nullfs_extattrctl,
354259016Sray	.vfs_fhtovp =		nullfs_fhtovp,
355259016Sray	.vfs_init =		nullfs_init,
356259016Sray	.vfs_mount =		nullfs_mount,
357259016Sray	.vfs_quotactl =		nullfs_quotactl,
358197115Sed	.vfs_root =		nullfs_root,
359197115Sed	.vfs_statfs =		nullfs_statfs,
360197115Sed	.vfs_sync =		nullfs_sync,
361197117Sed	.vfs_uninit =		nullfs_uninit,
362197115Sed	.vfs_unmount =		nullfs_unmount,
363197115Sed	.vfs_vget =		nullfs_vget,
364197117Sed};
365197117Sed
366197117SedVFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK);
367197117Sed