2 * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
3 * Copyright (c) 2019 The DragonFly Project
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/device.h>
31 #include <sys/devfs.h>
32 #include <sys/nlookup.h>
34 #include <sys/sysctl.h>
35 #include <sys/statvfs.h>
40 SYSCTL_NODE(_vfs, OID_AUTO, fuse, CTLFLAG_RD, 0, "FUSE");
42 SYSCTL_INT(_vfs_fuse, OID_AUTO, version_major, CTLFLAG_RD, NULL,
43 FUSE_KERNEL_VERSION, "FUSE kernel version (major)");
44 SYSCTL_INT(_vfs_fuse, OID_AUTO, version_minor, CTLFLAG_RD, NULL,
45 FUSE_KERNEL_MINOR_VERSION, "FUSE kernel version (minor)");
47 SYSCTL_INT(_vfs_fuse, OID_AUTO, debug, CTLFLAG_RW, &fuse_debug, 1, "");
50 fuse_cmp_version(struct fuse_mount *fmp, uint32_t major, uint32_t minor)
52 if (fmp->abi_major == major && fmp->abi_minor == minor)
55 if (fmp->abi_major > major ||
56 (fmp->abi_major == major && fmp->abi_minor > minor))
63 fuse_mount_kill(struct fuse_mount *fmp)
65 if (!fuse_test_dead(fmp)) {
68 KNOTE(&fmp->kq.ki_note, 0);
76 fuse_mount_free(struct fuse_mount *fmp)
78 if (refcount_release(&fmp->refcnt)) {
79 fuse_dbg("fmp=%p free\n", fmp);
80 mtx_uninit(&fmp->ipc_lock);
81 mtx_uninit(&fmp->mnt_lock);
86 fuse_dbg("fmp=%p %u refcnt left\n", fmp, fmp->refcnt);
92 fuse_mount(struct mount *mp, char *mntpt, caddr_t data, struct ucred *cred)
94 struct statfs *sbp = &mp->mnt_stat;
97 struct nlookupdata nd;
98 struct fuse_mount_info args;
99 struct fuse_mount *fmp;
100 struct fuse_ipc *fip;
101 struct fuse_init_in *fii;
102 struct fuse_init_out *fio;
106 if (mp->mnt_flag & MNT_UPDATE)
109 error = copyin(data, &args, sizeof(args));
112 memcpy(sbp->f_mntfromname, args.from, sizeof(sbp->f_mntfromname));
114 memset(sbp->f_mntfromname, 0, sizeof(sbp->f_mntfromname));
115 error = copyinstr(args.from, sbp->f_mntfromname,
116 sizeof(sbp->f_mntfromname), NULL);
120 memset(sbp->f_mntonname, 0, sizeof(sbp->f_mntonname));
121 error = copyinstr(mntpt, sbp->f_mntonname, sizeof(sbp->f_mntonname),
126 memset(subtype, 0, sizeof(subtype));
127 error = copyinstr(args.subtype, subtype, sizeof(subtype), NULL);
130 if (strlen(subtype)) {
131 strlcat(sbp->f_fstypename, ".", sizeof(sbp->f_fstypename));
132 strlcat(sbp->f_fstypename, subtype, sizeof(sbp->f_fstypename));
135 error = nlookup_init(&nd, sbp->f_mntfromname, UIO_SYSSPACE, NLC_FOLLOW);
137 error = nlookup(&nd);
139 error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
147 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
148 error = VOP_ACCESS(devvp, VREAD | VWRITE, cred);
150 error = priv_check_cred(cred, PRIV_ROOT, 0);
157 fuse_dbg("fd=%d\n", args.fd);
158 file = holdfp_fdp(curthread->td_proc->p_fd, args.fd, FREAD | FWRITE);
163 error = devfs_get_cdevpriv(file, (void**)&fmp);
164 dropfp(curthread, args.fd, file);
173 mtx_init(&fmp->mnt_lock, "fuse_mnt_lock");
174 mtx_init(&fmp->ipc_lock, "fuse_ipc_lock");
175 TAILQ_INIT(&fmp->request_head);
176 TAILQ_INIT(&fmp->reply_head);
178 fmp->cred = crhold(cred);
179 KKASSERT(fmp->refcnt > 0);
180 refcount_acquire(&fmp->refcnt);
182 mp->mnt_flag |= MNT_LOCAL;
183 mp->mnt_kern_flag |= MNTK_ALL_MPSAFE;
184 mp->mnt_data = (qaddr_t)fmp;
186 fuse_node_new(fmp, FUSE_ROOT_ID, VDIR, &fmp->rfnp);
187 KKASSERT(fmp->rfnp->ino == FUSE_ROOT_ID);
190 vfs_add_vnodeops(mp, &fuse_vnode_vops, &mp->mnt_vn_norm_ops);
191 vfs_add_vnodeops(mp, &fuse_spec_vops, &mp->mnt_vn_spec_ops);
193 fip = fuse_ipc_get(fmp, sizeof(*fii));
194 fii = fuse_ipc_fill(fip, FUSE_INIT, FUSE_ROOT_ID, NULL);
195 fii->major = FUSE_KERNEL_VERSION;
196 fii->minor = FUSE_KERNEL_MINOR_VERSION;
197 fii->max_readahead = FUSE_BLKSIZE;
201 error = fuse_ipc_tx(fip);
207 fio = fuse_out_data(fip);
208 fmp->abi_major = fio->major;
209 fmp->abi_minor = fio->minor;
210 fmp->max_write = fio->max_write;
212 if (fuse_cmp_version(fmp, 7, 0) < 0) {
215 return EPROTONOSUPPORT;
221 //fio->max_background
222 //fio->congestion_threshold
225 fuse_print("FUSE UABI %d.%d\n", fmp->abi_major, fmp->abi_minor);
229 VFS_STATFS(mp, &mp->mnt_stat, cred);
235 fuse_unmount(struct mount *mp, int mntflags)
237 struct fuse_mount *fmp = VFSTOFUSE(mp);
238 struct fuse_ipc *fip;
239 int error, flags = 0;
241 mtx_lock(&fmp->mnt_lock);
242 if (mntflags & MNT_FORCE)
245 error = vflush(mp, 0, flags);
247 mtx_unlock(&fmp->mnt_lock);
248 fuse_dbg("vflush error=%d\n", error);
252 if (!fuse_test_dead(fmp)) {
253 fuse_dbg("not dead yet, destroying\n");
254 fip = fuse_ipc_get(fmp, 0);
255 fuse_ipc_fill(fip, FUSE_DESTROY, FUSE_ROOT_ID, NULL);
256 if (!fuse_ipc_tx(fip))
258 fuse_mount_kill(fmp);
261 /* The userspace fs will exit anyway after FUSE_DESTROY. */
262 vn_lock(fmp->devvp, LK_EXCLUSIVE | LK_RETRY);
263 VOP_CLOSE(fmp->devvp, FREAD | FWRITE, NULL);
264 vn_unlock(fmp->devvp);
267 mtx_unlock(&fmp->mnt_lock);
269 fuse_mount_free(fmp);
271 mp->mnt_flag &= ~MNT_LOCAL;
273 fuse_dbg("unmount done\n");
279 fuse_root(struct mount *mp, struct vnode **vpp)
281 struct fuse_mount *fmp = VFSTOFUSE(mp);
284 KASSERT(fmp->rfnp, ("no root node"));
285 KKASSERT(fmp->rfnp->fmp);
287 error = fuse_node_vn(fmp->rfnp, LK_EXCLUSIVE, vpp);
289 struct vnode *vp = *vpp;
291 KKASSERT(vp->v_type == VDIR);
298 fuse_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
300 struct fuse_mount *fmp = VFSTOFUSE(mp);
301 struct fuse_ipc *fip;
302 struct fuse_statfs_out *fso;
305 fip = fuse_ipc_get(fmp, 0);
306 fuse_ipc_fill(fip, FUSE_STATFS, FUSE_ROOT_ID, cred);
307 error = fuse_ipc_tx(fip);
311 fso = fuse_out_data(fip);
313 mtx_lock(&fmp->mnt_lock);
314 sbp->f_bsize = fso->st.frsize;
315 sbp->f_iosize = FUSE_BLKSIZE;
316 sbp->f_blocks = fso->st.blocks;
317 sbp->f_bfree = fso->st.bfree;
318 sbp->f_bavail = fso->st.bavail;
319 sbp->f_files = fso->st.files;
320 sbp->f_ffree = fso->st.ffree;
321 mtx_unlock(&fmp->mnt_lock);
329 fuse_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
331 struct fuse_mount *fmp = VFSTOFUSE(mp);
332 struct fuse_ipc *fip;
333 struct fuse_statfs_out *fso;
336 fip = fuse_ipc_get(fmp, 0);
337 fuse_ipc_fill(fip, FUSE_STATFS, FUSE_ROOT_ID, cred);
338 error = fuse_ipc_tx(fip);
342 fso = fuse_out_data(fip);
344 mtx_lock(&fmp->mnt_lock);
345 sbp->f_bsize = fso->st.frsize;
346 sbp->f_frsize = FUSE_BLKSIZE;
347 sbp->f_blocks = fso->st.blocks;
348 sbp->f_bfree = fso->st.bfree;
349 sbp->f_bavail = fso->st.bavail;
350 sbp->f_files = fso->st.files;
351 sbp->f_ffree = fso->st.ffree;
352 mtx_unlock(&fmp->mnt_lock);
360 fuse_init(struct vfsconf *vfsp)
368 error = fuse_device_init();
376 fuse_print("FUSE ABI %d.%d\n", FUSE_KERNEL_VERSION,
377 FUSE_KERNEL_MINOR_VERSION);
383 fuse_uninit(struct vfsconf *vfsp)
388 fuse_device_cleanup();
393 static struct vfsops fuse_vfsops = {
394 .vfs_init = fuse_init,
395 .vfs_uninit = fuse_uninit,
396 .vfs_mount = fuse_mount,
397 .vfs_unmount = fuse_unmount,
398 .vfs_root = fuse_root,
399 .vfs_statfs = fuse_statfs,
400 .vfs_statvfs = fuse_statvfs,
403 VFS_SET(fuse_vfsops, fuse, VFCF_SYNTHETIC | VFCF_MPSAFE);
404 MODULE_VERSION(fuse, 1);