2 * Copyright (c) 2013 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Antonio Huete Jimenez <tuxillo@quantumachine.net>
6 * by Matthew Dillon <dillon@dragonflybsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/vfsops.h>
38 #include <sys/mount.h>
39 #include <sys/types.h>
40 #include <sys/systm.h>
41 #include <sys/param.h>
42 #include <sys/module.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/sysctl.h>
46 #include <sys/queue.h>
47 #include <sys/spinlock2.h>
48 #include <sys/sysref2.h>
55 MALLOC_DEFINE(M_DIRFS, "dirfs", "dirfs mount allocation");
56 MALLOC_DEFINE(M_DIRFS_NODE, "dirfs nodes", "dirfs nodes memory allocation");
57 MALLOC_DEFINE(M_DIRFS_MISC, "dirfs misc", "dirfs miscellaneous allocation");
60 * Kernel tracing facilities
62 KTR_INFO_MASTER(dirfs);
64 KTR_INFO(KTR_DIRFS, dirfs, root, 31,
65 "DIRFS(root dnp=%p vnode=%p hostdir=%s fd=%d error=%d)",
66 dirfs_node_t dnp, struct vnode *vp, char *hostdir, int fd, int error);
68 /* System wide sysctl stuff */
70 int dirfs_fd_limit = 100;
71 int dirfs_fd_used = 0;
72 long passive_fd_list_miss = 0;
73 long passive_fd_list_hits = 0;
75 SYSCTL_NODE(_vfs, OID_AUTO, dirfs, CTLFLAG_RW, 0,
76 "dirfs filesystem for vkernels");
77 SYSCTL_INT(_vfs_dirfs, OID_AUTO, debug, CTLFLAG_RW,
78 &debuglvl, 0, "dirfs debug level");
79 SYSCTL_INT(_vfs_dirfs, OID_AUTO, fd_limit, CTLFLAG_RW,
80 &dirfs_fd_limit, 0, "Maximum number of passive nodes to cache");
81 SYSCTL_INT(_vfs_dirfs, OID_AUTO, fd_used, CTLFLAG_RD,
82 &dirfs_fd_used, 0, "Current number of passive nodes cached");
83 SYSCTL_LONG(_vfs_dirfs, OID_AUTO, passive_fd_list_miss, CTLFLAG_RD,
84 &passive_fd_list_miss, 0, "Passive fd list cache misses");
85 SYSCTL_LONG(_vfs_dirfs, OID_AUTO, passive_fd_list_hits, CTLFLAG_RD,
86 &passive_fd_list_hits, 0, "Passive fd list cache misses");
88 static int dirfs_statfs(struct mount *, struct statfs *, struct ucred *);
91 dirfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
100 if (mp->mnt_flag & MNT_UPDATE) {
101 dmp = VFS_TO_DIRFS(mp);
102 if (dmp->dm_rdonly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
103 /* XXX We should make sure all writes are synced */
105 debug(2, "dirfs read-write -> read-only\n");
108 if (dmp->dm_rdonly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
109 debug(2, "dirfs read-only -> read-write\n");
115 dmp = kmalloc(sizeof(*dmp), M_DIRFS, M_WAITOK | M_ZERO);
116 mp->mnt_data = (qaddr_t)dmp;
119 error = copyinstr(data, &dmp->dm_path, MAXPATHLEN, &done);
121 /* Attempt to copy from kernel address */
122 error = copystr(data, &dmp->dm_path, MAXPATHLEN, &done);
129 /* Strip / character at the end to avoid problems */
130 nlen = strnlen(dmp->dm_path, MAXPATHLEN);
131 if (dmp->dm_path[nlen-1] == '/')
132 dmp->dm_path[nlen-1] = 0;
134 /* Make sure host directory exists and it is indeed a directory. */
135 if ((stat(dmp->dm_path, &st)) == 0) {
136 if (!S_ISDIR(st.st_mode)) {
144 lockinit(&dmp->dm_lock, "dfsmnt", 0, LK_CANRECURSE);
146 vfs_add_vnodeops(mp, &dirfs_vnode_vops, &mp->mnt_vn_norm_ops);
149 TAILQ_INIT(&dmp->dm_fdlist);
150 RB_INIT(&dmp->dm_inotree);
152 kmalloc_raise_limit(M_DIRFS_NODE, 0);
154 dirfs_statfs(mp, &mp->mnt_stat, cred);
156 dbg(5, "%s mounted. dmp=%p mp=%p\n", dmp->dm_path, dmp, mp);
162 dirfs_unmount(struct mount *mp, int mntflags)
171 dmp = VFS_TO_DIRFS(mp);
173 error = vflush(mp, 0, 0);
178 * Clean up dm_fdlist. There should be no vnodes left so the
179 * only ref should be from the fdlist.
181 while ((dnp = TAILQ_FIRST(&dmp->dm_fdlist)) != NULL) {
182 dirfs_node_setpassive(dmp, dnp, 0);
189 dirfs_close_helper(dnp);
191 dirfs_node_drop(dmp, dnp); /* last ref should free structure */
194 mp->mnt_data = (qaddr_t) 0;
196 dbg(5, "dirfs umounted successfully\n");
202 dirfs_root(struct mount *mp, struct vnode **vpp)
211 dmp = VFS_TO_DIRFS(mp);
212 KKASSERT(dmp != NULL);
214 if (dmp->dm_root == NULL) {
216 * dm_root holds the root dirfs node. Allocate a new one since
217 * there is none. Also attempt to lstat(2) it, in order to set
218 * data for VOP_ACCESS()
220 dnp = dirfs_node_alloc(mp);
221 error = dirfs_node_stat(DIRFS_NOFD, dmp->dm_path, dnp);
223 dirfs_node_free(dmp, dnp);
226 dirfs_node_ref(dnp); /* leave inact for life of mount */
228 /* Root inode's parent is NULL, used for verification */
229 dnp->dn_parent = NULL;
231 dirfs_node_setflags(dnp, DIRFS_ROOT);
234 * Maintain an open descriptor on the root dnp. The
235 * normal open/close/cache does not apply for the root
236 * so the descriptor is ALWAYS available.
238 fd = open(dmp->dm_path, O_DIRECTORY);
240 dbg(5, "failed to open ROOT node\n");
241 dirfs_free_vp(dmp, dnp);
242 dirfs_node_free(dmp, dnp);
252 * Acquire the root vnode (dn_type already set above). This
253 * call will handle any races and return a locked vnode.
255 dirfs_alloc_vp(mp, vpp, LK_CANRECURSE, dnp);
256 KTR_LOG(dirfs_root, dnp, *vpp, dmp->dm_path, dnp->dn_fd, error);
262 dirfs_fhtovp(struct mount *mp, struct vnode *rootvp, struct fid *fhp, struct vnode **vpp)
270 dirfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
272 dirfs_mount_t dmp = VFS_TO_DIRFS(mp);
277 if((statfs(dmp->dm_path, &st)) == -1)
280 ksnprintf(st.f_mntfromname, MNAMELEN - 1, "dirfs@%s", dmp->dm_path);
281 bcopy(&st, sbp, sizeof(st));
282 strlcpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
283 dbg(5, "iosize = %zd\n", sbp->f_iosize);
289 dirfs_vptofh(struct vnode *vp, struct fid *fhp)
293 dnp = VP_TO_NODE(vp);
301 dirfs_checkexp(struct mount *mp, struct sockaddr *nam, int *exflagsp,
302 struct ucred **credanonp)
309 static struct vfsops dirfs_vfsops = {
310 .vfs_mount = dirfs_mount,
311 .vfs_unmount = dirfs_unmount,
312 .vfs_root = dirfs_root,
313 .vfs_vget = vfs_stdvget,
314 .vfs_statfs = dirfs_statfs,
315 .vfs_fhtovp = dirfs_fhtovp,
316 .vfs_vptofh = dirfs_vptofh,
317 .vfs_sync = vfs_stdsync,
318 .vfs_checkexp = dirfs_checkexp
321 VFS_SET(dirfs_vfsops, dirfs, 0);
322 MODULE_VERSION(dirfs, 1);