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
, 20,
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 KTR_INFO(KTR_DIRFS
, dirfs
, mount
, 21,
69 "DIRFS(mount path=%s dmp=%p mp=%p error=%d)",
70 char *path
, dirfs_mount_t dmp
, struct mount
*mp
, int error
);
72 KTR_INFO(KTR_DIRFS
, dirfs
, unmount
, 22,
73 "DIRFS(unmount dmp=%p mp=%p error=%d)",
74 dirfs_mount_t dmp
, struct mount
*mp
, int error
);
76 /* System wide sysctl stuff */
78 int dirfs_fd_limit
= 100;
79 int dirfs_fd_used
= 0;
80 long passive_fd_list_miss
= 0;
81 long passive_fd_list_hits
= 0;
83 SYSCTL_NODE(_vfs
, OID_AUTO
, dirfs
, CTLFLAG_RW
, 0,
84 "dirfs filesystem for vkernels");
85 SYSCTL_INT(_vfs_dirfs
, OID_AUTO
, debug
, CTLFLAG_RW
,
86 &debuglvl
, 0, "dirfs debug level");
87 SYSCTL_INT(_vfs_dirfs
, OID_AUTO
, fd_limit
, CTLFLAG_RW
,
88 &dirfs_fd_limit
, 0, "Maximum number of passive nodes to cache");
89 SYSCTL_INT(_vfs_dirfs
, OID_AUTO
, fd_used
, CTLFLAG_RD
,
90 &dirfs_fd_used
, 0, "Current number of passive nodes cached");
91 SYSCTL_LONG(_vfs_dirfs
, OID_AUTO
, passive_fd_list_miss
, CTLFLAG_RD
,
92 &passive_fd_list_miss
, 0, "Passive fd list cache misses");
93 SYSCTL_LONG(_vfs_dirfs
, OID_AUTO
, passive_fd_list_hits
, CTLFLAG_RD
,
94 &passive_fd_list_hits
, 0, "Passive fd list cache misses");
96 static int dirfs_statfs(struct mount
*, struct statfs
*, struct ucred
*);
99 dirfs_mount(struct mount
*mp
, char *path
, caddr_t data
, struct ucred
*cred
)
108 if (mp
->mnt_flag
& MNT_UPDATE
) {
109 dmp
= VFS_TO_DIRFS(mp
);
110 if (dmp
->dm_rdonly
== 0 && (mp
->mnt_flag
& MNT_RDONLY
)) {
111 /* XXX We should make sure all writes are synced */
113 debug(2, "dirfs read-write -> read-only\n");
116 if (dmp
->dm_rdonly
&& (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
117 debug(2, "dirfs read-only -> read-write\n");
123 dmp
= kmalloc(sizeof(*dmp
), M_DIRFS
, M_WAITOK
| M_ZERO
);
124 mp
->mnt_data
= (qaddr_t
)dmp
;
127 error
= copyinstr(data
, &dmp
->dm_path
, MAXPATHLEN
, &done
);
129 /* Attempt to copy from kernel address */
130 error
= copystr(data
, &dmp
->dm_path
, MAXPATHLEN
, &done
);
137 /* Strip / character at the end to avoid problems */
138 nlen
= strnlen(dmp
->dm_path
, MAXPATHLEN
);
139 if (dmp
->dm_path
[nlen
-1] == '/')
140 dmp
->dm_path
[nlen
-1] = 0;
142 /* Make sure host directory exists and it is indeed a directory. */
143 if ((stat(dmp
->dm_path
, &st
)) == 0) {
144 if (!S_ISDIR(st
.st_mode
)) {
154 lockinit(&dmp
->dm_lock
, "dfsmnt", 0, LK_CANRECURSE
);
156 vfs_add_vnodeops(mp
, &dirfs_vnode_vops
, &mp
->mnt_vn_norm_ops
);
159 /* Who is running the vkernel */
160 dmp
->dm_uid
= getuid();
161 dmp
->dm_gid
= getgid();
163 TAILQ_INIT(&dmp
->dm_fdlist
);
164 RB_INIT(&dmp
->dm_inotree
);
166 kmalloc_raise_limit(M_DIRFS_NODE
, 0);
168 dirfs_statfs(mp
, &mp
->mnt_stat
, cred
);
171 KTR_LOG(dirfs_mount
, (dmp
->dm_path
) ? dmp
->dm_path
: "NULL",
178 dirfs_unmount(struct mount
*mp
, int mntflags
)
187 dmp
= VFS_TO_DIRFS(mp
);
189 error
= vflush(mp
, 0, 0);
194 * Clean up dm_fdlist. There should be no vnodes left so the
195 * only ref should be from the fdlist.
197 while ((dnp
= TAILQ_FIRST(&dmp
->dm_fdlist
)) != NULL
) {
198 dirfs_node_setpassive(dmp
, dnp
, 0);
202 * Cleanup root node. In the case the filesystem is mounted
203 * but no operation is done on it, there will be no call to
204 * VFS_ROOT() so better check dnp is not NULL before attempting
209 dirfs_close_helper(dnp
);
211 dirfs_node_drop(dmp
, dnp
); /* last ref should free structure */
214 mp
->mnt_data
= (qaddr_t
) 0;
217 KTR_LOG(dirfs_unmount
, dmp
, mp
, error
);
223 dirfs_root(struct mount
*mp
, struct vnode
**vpp
)
232 dmp
= VFS_TO_DIRFS(mp
);
233 KKASSERT(dmp
!= NULL
);
235 if (dmp
->dm_root
== NULL
) {
237 * dm_root holds the root dirfs node. Allocate a new one since
238 * there is none. Also attempt to lstat(2) it, in order to set
239 * data for VOP_ACCESS()
241 dnp
= dirfs_node_alloc(mp
);
242 error
= dirfs_node_stat(DIRFS_NOFD
, dmp
->dm_path
, dnp
);
244 dirfs_node_free(dmp
, dnp
);
247 dirfs_node_ref(dnp
); /* leave inact for life of mount */
249 /* Root inode's parent is NULL, used for verification */
250 dnp
->dn_parent
= NULL
;
252 dirfs_node_setflags(dnp
, DIRFS_ROOT
);
255 * Maintain an open descriptor on the root dnp. The
256 * normal open/close/cache does not apply for the root
257 * so the descriptor is ALWAYS available.
259 fd
= open(dmp
->dm_path
, O_DIRECTORY
);
261 dbg(9, "failed to open ROOT node\n");
262 dirfs_free_vp(dmp
, dnp
);
263 dirfs_node_free(dmp
, dnp
);
273 * Acquire the root vnode (dn_type already set above). This
274 * call will handle any races and return a locked vnode.
276 dirfs_alloc_vp(mp
, vpp
, LK_CANRECURSE
, dnp
);
277 KTR_LOG(dirfs_root
, dnp
, *vpp
, dmp
->dm_path
, dnp
->dn_fd
, error
);
283 dirfs_fhtovp(struct mount
*mp
, struct vnode
*rootvp
, struct fid
*fhp
, struct vnode
**vpp
)
291 dirfs_statfs(struct mount
*mp
, struct statfs
*sbp
, struct ucred
*cred
)
293 dirfs_mount_t dmp
= VFS_TO_DIRFS(mp
);
298 if((statfs(dmp
->dm_path
, &st
)) == -1)
301 ksnprintf(st
.f_mntfromname
, MNAMELEN
- 1, "dirfs@%s", dmp
->dm_path
);
302 bcopy(&st
, sbp
, sizeof(st
));
303 strlcpy(sbp
->f_fstypename
, mp
->mnt_vfc
->vfc_name
, MFSNAMELEN
);
304 dbg(5, "iosize = %zd\n", sbp
->f_iosize
);
310 dirfs_statvfs(struct mount
*mp
, struct statvfs
*sbp
, struct ucred
*cred
)
312 dirfs_mount_t dmp
= VFS_TO_DIRFS(mp
);
317 if ((statvfs(dmp
->dm_path
, &st
)) == -1)
320 bcopy(&st
, sbp
, sizeof(st
));
326 dirfs_vptofh(struct vnode
*vp
, struct fid
*fhp
)
330 dnp
= VP_TO_NODE(vp
);
338 dirfs_checkexp(struct mount
*mp
, struct sockaddr
*nam
, int *exflagsp
,
339 struct ucred
**credanonp
)
346 static struct vfsops dirfs_vfsops
= {
347 .vfs_mount
= dirfs_mount
,
348 .vfs_unmount
= dirfs_unmount
,
349 .vfs_root
= dirfs_root
,
350 .vfs_vget
= vfs_stdvget
,
351 .vfs_statfs
= dirfs_statfs
,
352 .vfs_statvfs
= dirfs_statvfs
,
353 .vfs_fhtovp
= dirfs_fhtovp
,
354 .vfs_vptofh
= dirfs_vptofh
,
355 .vfs_checkexp
= dirfs_checkexp
358 VFS_SET(dirfs_vfsops
, dirfs
, 0);
359 MODULE_VERSION(dirfs
, 1);