2 * Copyright (c) 1992, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software donated to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
36 * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94
38 * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92
39 * $FreeBSD: src/sys/miscfs/nullfs/null_vfsops.c,v 1.35.2.3 2001/07/26 20:37:11 iedowse Exp $
40 * $DragonFly: src/sys/vfs/nullfs/null_vfsops.c,v 1.29.8.1 2008/09/25 02:20:55 dillon Exp $
45 * (See null_vnops.c for a description of what this does.)
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
52 #include <sys/malloc.h>
53 #include <sys/vnode.h>
54 #include <sys/mount.h>
55 #include <sys/nlookup.h>
56 #include <sys/mountctl.h>
59 extern struct vop_ops null_vnode_vops
;
61 static MALLOC_DEFINE(M_NULLFSMNT
, "NULLFS mount", "NULLFS mount structure");
63 static int nullfs_root(struct mount
*mp
, struct vnode
**vpp
);
64 static int nullfs_statfs(struct mount
*mp
, struct statfs
*sbp
,
71 nullfs_mount(struct mount
*mp
, char *path
, caddr_t data
, struct ucred
*cred
)
74 struct null_args args
;
76 struct null_mount
*xmp
;
78 struct nlookupdata nd
;
81 NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp
);
86 if (mp
->mnt_flag
& MNT_UPDATE
) {
93 error
= copyin(data
, (caddr_t
)&args
, sizeof(struct null_args
));
101 error
= nlookup_init(&nd
, args
.target
, UIO_USERSPACE
, NLC_FOLLOW
);
104 error
= nlookup(&nd
);
107 error
= cache_vget(&nd
.nl_nch
, nd
.nl_cred
, LK_EXCLUSIVE
, &rootvp
);
111 xmp
= (struct null_mount
*) kmalloc(sizeof(struct null_mount
),
112 M_NULLFSMNT
, M_WAITOK
| M_ZERO
);
115 * Save reference to underlying FS
117 * As lite stacking enters the scene, the old way of doing this
118 * -- via the vnode -- is not good enough anymore. Use the
119 * underlying filesystem's namecache handle as our mount point
120 * root, adjusting the mount to point to us.
122 * NCF_ISMOUNTPT is normally set on the mount point, but we also
123 * want to set it on the base directory being mounted to prevent
124 * that directory from being destroyed out from under the nullfs
127 * The forwarding mount pointer (xmp->nullm_vfs) must be set to
128 * the actual target filesystem. If the target filesystem was
129 * resolved via a nullfs mount nd.nl_nch.mount will be pointing
130 * to the nullfs mount structure instead of the target filesystem,
131 * which would otherwise cause the mount VOPS and VFSOPS to recurse
132 * endlessly. If we are mounting via a nullfs mount we inherit
133 * its read-only state, if set.
135 xmp
->nullm_vfs
= nd
.nl_nch
.mount
;
136 if (xmp
->nullm_vfs
!= rootvp
->v_mount
) {
137 if (xmp
->nullm_vfs
->mnt_flag
& MNT_RDONLY
)
138 mp
->mnt_flag
|= MNT_RDONLY
;
139 xmp
->nullm_vfs
= rootvp
->v_mount
;
143 * ncmountpt is the parent glue. When mounting a nullfs via a nullfs
144 * we retain the parent nullfs to create a unique chain tuple.
146 mp
->mnt_ncmountpt
= nd
.nl_nch
;
147 cache_changemount(&mp
->mnt_ncmountpt
, mp
);
148 mp
->mnt_ncmountpt
.ncp
->nc_flag
|= NCF_ISMOUNTPT
;
149 cache_unlock(&mp
->mnt_ncmountpt
);
150 cache_zero(&nd
.nl_nch
);
153 vfs_add_vnodeops(mp
, &null_vnode_vops
, &mp
->mnt_vn_norm_ops
);
155 vn_unlock(rootvp
); /* leave reference intact */
158 * Keep a held reference to the root vnode.
159 * It is vrele'd in nullfs_unmount.
161 xmp
->nullm_rootvp
= rootvp
;
163 * XXX What's the proper safety condition for querying
164 * the underlying mount? Is this flag tuning necessary
167 if (xmp
->nullm_vfs
->mnt_flag
& MNT_LOCAL
)
168 mp
->mnt_flag
|= MNT_LOCAL
;
169 mp
->mnt_data
= (qaddr_t
) xmp
;
172 * Try to create a unique but non-random fsid for the nullfs to
173 * allow it to be exported via NFS.
175 bzero(&fh
, sizeof(fh
));
176 fh
.fh_fsid
= rootvp
->v_mount
->mnt_stat
.f_fsid
;
177 if (VFS_VPTOFH(rootvp
, &fh
.fh_fid
) == 0) {
178 fh
.fh_fsid
.val
[1] ^= crc32(&fh
.fh_fid
, sizeof(fh
.fh_fid
));
179 vfs_setfsid(mp
, &fh
.fh_fsid
);
184 (void) copyinstr(args
.target
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1,
186 bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
187 (void)nullfs_statfs(mp
, &mp
->mnt_stat
, cred
);
188 NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n",
189 mp
->mnt_stat
.f_mntfromname
, mp
->mnt_stat
.f_mntfromname
);
192 * So unmount won't complain about namecache refs still existing
194 mp
->mnt_kern_flag
|= MNTK_NCALIASED
;
203 * Free reference to null layer
206 nullfs_unmount(struct mount
*mp
, int mntflags
)
208 struct null_mount
*xmp
;
211 NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp
);
213 if (mntflags
& MNT_FORCE
)
217 * Finally, throw away the null_mount structure
219 xmp
= (void *)mp
->mnt_data
;
221 if (xmp
->nullm_rootvp
) {
222 vrele(xmp
->nullm_rootvp
);
223 xmp
->nullm_rootvp
= NULL
;
225 kfree(xmp
, M_NULLFSMNT
);
230 nullfs_root(struct mount
*mp
, struct vnode
**vpp
)
235 NULLFSDEBUG("nullfs_root(mp = %p, vp = %p)\n", (void *)mp
,
236 (void *)MOUNTTONULLMOUNT(mp
)->nullm_rootvp
);
239 * Return locked reference to root.
241 vp
= MOUNTTONULLMOUNT(mp
)->nullm_rootvp
;
242 error
= vget(vp
, LK_EXCLUSIVE
| LK_RETRY
);
249 nullfs_quotactl(struct mount
*mp
, int cmd
, uid_t uid
, caddr_t arg
,
252 return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp
)->nullm_vfs
, cmd
, uid
, arg
, cred
);
256 nullfs_statfs(struct mount
*mp
, struct statfs
*sbp
, struct ucred
*cred
)
261 NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p)\n", (void *)mp
,
262 (void *)MOUNTTONULLMOUNT(mp
)->nullm_rootvp
);
264 bzero(&mstat
, sizeof(mstat
));
266 error
= VFS_STATFS(MOUNTTONULLMOUNT(mp
)->nullm_vfs
, &mstat
, cred
);
270 /* now copy across the "interesting" information and fake the rest */
271 sbp
->f_type
= mstat
.f_type
;
272 sbp
->f_flags
= mstat
.f_flags
;
273 sbp
->f_bsize
= mstat
.f_bsize
;
274 sbp
->f_iosize
= mstat
.f_iosize
;
275 sbp
->f_blocks
= mstat
.f_blocks
;
276 sbp
->f_bfree
= mstat
.f_bfree
;
277 sbp
->f_bavail
= mstat
.f_bavail
;
278 sbp
->f_files
= mstat
.f_files
;
279 sbp
->f_ffree
= mstat
.f_ffree
;
280 if (sbp
!= &mp
->mnt_stat
) {
281 bcopy(&mp
->mnt_stat
.f_fsid
, &sbp
->f_fsid
, sizeof(sbp
->f_fsid
));
282 bcopy(mp
->mnt_stat
.f_mntfromname
, sbp
->f_mntfromname
, MNAMELEN
);
288 * Implement NFS export tracking
291 nullfs_checkexp(struct mount
*mp
, struct sockaddr
*nam
, int *extflagsp
,
292 struct ucred
**credanonp
)
294 struct null_mount
*xmp
= (void *)mp
->mnt_data
;
298 np
= vfs_export_lookup(mp
, &xmp
->export
, nam
);
300 *extflagsp
= np
->netc_exflags
;
301 *credanonp
= &np
->netc_anon
;
308 return VFS_CHECKEXP(MOUNTTONULLMOUNT(mp
)->nullm_vfs
, nam
,
309 extflagsp
, credanonp
);
314 nullfs_export(struct mount
*mp
, int op
, const struct export_args
*export
)
316 struct null_mount
*xmp
= (void *)mp
->mnt_data
;
320 case MOUNTCTL_SET_EXPORT
:
321 error
= vfs_export(mp
, &xmp
->export
, export
);
331 * Pass through file handle conversion functions.
334 nullfs_vptofh(struct vnode
*vp
, struct fid
*fhp
)
336 return VFS_VPTOFH(vp
, fhp
);
340 * Pass through file handle conversion functions.
342 * NOTE: currently only HAMMER uses rootvp. HAMMER uses rootvp only
343 * to enforce PFS isolation.
346 nullfs_fhtovp(struct mount
*mp
, struct vnode
*rootvp
,
347 struct fid
*fhp
, struct vnode
**vpp
)
349 struct null_mount
*xmp
= MOUNTTONULLMOUNT(mp
);
351 return VFS_FHTOVP(xmp
->nullm_vfs
, xmp
->nullm_rootvp
, fhp
, vpp
);
355 nullfs_extattrctl(struct mount
*mp
, int cmd
, const char *attrname
, caddr_t arg
,
358 return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp
)->nullm_vfs
, cmd
, attrname
,
363 static struct vfsops null_vfsops
= {
364 .vfs_mount
= nullfs_mount
,
365 .vfs_unmount
= nullfs_unmount
,
366 .vfs_root
= nullfs_root
,
367 .vfs_quotactl
= nullfs_quotactl
,
368 .vfs_statfs
= nullfs_statfs
,
369 .vfs_sync
= vfs_stdsync
,
370 .vfs_extattrctl
= nullfs_extattrctl
,
371 .vfs_fhtovp
= nullfs_fhtovp
,
372 .vfs_vptofh
= nullfs_vptofh
,
373 .vfs_checkexp
= nullfs_checkexp
376 VFS_SET(null_vfsops
, null
, VFCF_LOOPBACK
);