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.31 2008/09/17 21:44:25 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 error
= copyin(data
, (caddr_t
)&args
, sizeof(struct null_args
));
91 * XXX: Should we process mount export info ?
92 * If not, returning zero here is enough as the actual ro/rw update is
93 * being done in sys_mount().
95 if (mp
->mnt_flag
& MNT_UPDATE
) {
96 xmp
= MOUNTTONULLMOUNT(mp
);
97 error
= vfs_export(mp
, &xmp
->export
, &args
.export
);
105 error
= nlookup_init(&nd
, args
.target
, UIO_USERSPACE
, NLC_FOLLOW
);
108 error
= nlookup(&nd
);
111 error
= cache_vget(&nd
.nl_nch
, nd
.nl_cred
, LK_EXCLUSIVE
, &rootvp
);
115 xmp
= (struct null_mount
*) kmalloc(sizeof(struct null_mount
),
116 M_NULLFSMNT
, M_WAITOK
| M_ZERO
);
119 * Save reference to underlying FS
121 * As lite stacking enters the scene, the old way of doing this
122 * -- via the vnode -- is not good enough anymore. Use the
123 * underlying filesystem's namecache handle as our mount point
124 * root, adjusting the mount to point to us.
126 * NCF_ISMOUNTPT is normally set on the mount point, but we also
127 * want to set it on the base directory being mounted to prevent
128 * that directory from being destroyed out from under the nullfs
131 * The forwarding mount pointer (xmp->nullm_vfs) must be set to
132 * the actual target filesystem. If the target filesystem was
133 * resolved via a nullfs mount nd.nl_nch.mount will be pointing
134 * to the nullfs mount structure instead of the target filesystem,
135 * which would otherwise cause the mount VOPS and VFSOPS to recurse
136 * endlessly. If we are mounting via a nullfs mount we inherit
137 * its read-only state, if set.
139 xmp
->nullm_vfs
= nd
.nl_nch
.mount
;
140 if (xmp
->nullm_vfs
!= rootvp
->v_mount
) {
141 if (xmp
->nullm_vfs
->mnt_flag
& MNT_RDONLY
)
142 mp
->mnt_flag
|= MNT_RDONLY
;
143 xmp
->nullm_vfs
= rootvp
->v_mount
;
147 * ncmountpt is the parent glue. When mounting a nullfs via a nullfs
148 * we retain the parent nullfs to create a unique chain tuple.
150 mp
->mnt_ncmountpt
= nd
.nl_nch
;
151 cache_changemount(&mp
->mnt_ncmountpt
, mp
);
152 mp
->mnt_ncmountpt
.ncp
->nc_flag
|= NCF_ISMOUNTPT
;
153 cache_unlock(&mp
->mnt_ncmountpt
);
154 cache_zero(&nd
.nl_nch
);
157 vfs_add_vnodeops(mp
, &null_vnode_vops
, &mp
->mnt_vn_norm_ops
);
159 vn_unlock(rootvp
); /* leave reference intact */
162 * Keep a held reference to the root vnode.
163 * It is vrele'd in nullfs_unmount.
165 xmp
->nullm_rootvp
= rootvp
;
167 * XXX What's the proper safety condition for querying
168 * the underlying mount? Is this flag tuning necessary
171 if (xmp
->nullm_vfs
->mnt_flag
& MNT_LOCAL
)
172 mp
->mnt_flag
|= MNT_LOCAL
;
173 mp
->mnt_data
= (qaddr_t
) xmp
;
176 * Try to create a unique but non-random fsid for the nullfs to
177 * allow it to be exported via NFS.
179 bzero(&fh
, sizeof(fh
));
180 fh
.fh_fsid
= rootvp
->v_mount
->mnt_stat
.f_fsid
;
181 if (VFS_VPTOFH(rootvp
, &fh
.fh_fid
) == 0) {
182 fh
.fh_fsid
.val
[1] ^= crc32(&fh
.fh_fid
, sizeof(fh
.fh_fid
));
183 vfs_setfsid(mp
, &fh
.fh_fsid
);
188 (void) copyinstr(args
.target
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1,
190 bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
191 (void)nullfs_statfs(mp
, &mp
->mnt_stat
, cred
);
192 NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n",
193 mp
->mnt_stat
.f_mntfromname
, mp
->mnt_stat
.f_mntfromname
);
196 * So unmount won't complain about namecache refs still existing
198 mp
->mnt_kern_flag
|= MNTK_NCALIASED
;
207 * Free reference to null layer
210 nullfs_unmount(struct mount
*mp
, int mntflags
)
212 struct null_mount
*xmp
;
215 NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp
);
217 if (mntflags
& MNT_FORCE
)
221 * Finally, throw away the null_mount structure
223 xmp
= (void *)mp
->mnt_data
;
225 if (xmp
->nullm_rootvp
) {
226 vrele(xmp
->nullm_rootvp
);
227 xmp
->nullm_rootvp
= NULL
;
229 kfree(xmp
, M_NULLFSMNT
);
234 nullfs_root(struct mount
*mp
, struct vnode
**vpp
)
239 NULLFSDEBUG("nullfs_root(mp = %p, vp = %p)\n", (void *)mp
,
240 (void *)MOUNTTONULLMOUNT(mp
)->nullm_rootvp
);
243 * Return locked reference to root.
245 vp
= MOUNTTONULLMOUNT(mp
)->nullm_rootvp
;
246 error
= vget(vp
, LK_EXCLUSIVE
| LK_RETRY
);
253 nullfs_quotactl(struct mount
*mp
, int cmd
, uid_t uid
, caddr_t arg
,
256 return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp
)->nullm_vfs
, cmd
, uid
, arg
, cred
);
260 nullfs_statfs(struct mount
*mp
, struct statfs
*sbp
, struct ucred
*cred
)
265 NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p)\n", (void *)mp
,
266 (void *)MOUNTTONULLMOUNT(mp
)->nullm_rootvp
);
268 bzero(&mstat
, sizeof(mstat
));
270 error
= VFS_STATFS(MOUNTTONULLMOUNT(mp
)->nullm_vfs
, &mstat
, cred
);
274 /* now copy across the "interesting" information and fake the rest */
275 sbp
->f_type
= mstat
.f_type
;
276 sbp
->f_flags
= mstat
.f_flags
;
277 sbp
->f_bsize
= mstat
.f_bsize
;
278 sbp
->f_iosize
= mstat
.f_iosize
;
279 sbp
->f_blocks
= mstat
.f_blocks
;
280 sbp
->f_bfree
= mstat
.f_bfree
;
281 sbp
->f_bavail
= mstat
.f_bavail
;
282 sbp
->f_files
= mstat
.f_files
;
283 sbp
->f_ffree
= mstat
.f_ffree
;
284 if (sbp
!= &mp
->mnt_stat
) {
285 bcopy(&mp
->mnt_stat
.f_fsid
, &sbp
->f_fsid
, sizeof(sbp
->f_fsid
));
286 bcopy(mp
->mnt_stat
.f_mntfromname
, sbp
->f_mntfromname
, MNAMELEN
);
292 * Implement NFS export tracking
295 nullfs_checkexp(struct mount
*mp
, struct sockaddr
*nam
, int *extflagsp
,
296 struct ucred
**credanonp
)
298 struct null_mount
*xmp
= (void *)mp
->mnt_data
;
302 np
= vfs_export_lookup(mp
, &xmp
->export
, nam
);
304 *extflagsp
= np
->netc_exflags
;
305 *credanonp
= &np
->netc_anon
;
312 return VFS_CHECKEXP(MOUNTTONULLMOUNT(mp
)->nullm_vfs
, nam
,
313 extflagsp
, credanonp
);
318 nullfs_export(struct mount
*mp
, int op
, const struct export_args
*export
)
320 struct null_mount
*xmp
= (void *)mp
->mnt_data
;
324 case MOUNTCTL_SET_EXPORT
:
325 error
= vfs_export(mp
, &xmp
->export
, export
);
335 * Pass through file handle conversion functions.
338 nullfs_vptofh(struct vnode
*vp
, struct fid
*fhp
)
340 return VFS_VPTOFH(vp
, fhp
);
344 * Pass through file handle conversion functions.
346 * NOTE: currently only HAMMER uses rootvp. HAMMER uses rootvp only
347 * to enforce PFS isolation.
350 nullfs_fhtovp(struct mount
*mp
, struct vnode
*rootvp
,
351 struct fid
*fhp
, struct vnode
**vpp
)
353 struct null_mount
*xmp
= MOUNTTONULLMOUNT(mp
);
355 return VFS_FHTOVP(xmp
->nullm_vfs
, xmp
->nullm_rootvp
, fhp
, vpp
);
359 nullfs_extattrctl(struct mount
*mp
, int cmd
, const char *attrname
, caddr_t arg
,
362 return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp
)->nullm_vfs
, cmd
, attrname
,
367 static struct vfsops null_vfsops
= {
368 .vfs_mount
= nullfs_mount
,
369 .vfs_unmount
= nullfs_unmount
,
370 .vfs_root
= nullfs_root
,
371 .vfs_quotactl
= nullfs_quotactl
,
372 .vfs_statfs
= nullfs_statfs
,
373 .vfs_sync
= vfs_stdsync
,
374 .vfs_extattrctl
= nullfs_extattrctl
,
375 .vfs_fhtovp
= nullfs_fhtovp
,
376 .vfs_vptofh
= nullfs_vptofh
,
377 .vfs_checkexp
= nullfs_checkexp
380 VFS_SET(null_vfsops
, null
, VFCF_LOOPBACK
);