1 /*- 2 * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org> 3 * Copyright (c) 2019 The DragonFly Project 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 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. 14 * 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 25 * SUCH DAMAGE. 26 */ 27 28 #include "fuse.h" 29 30 #include <sys/device.h> 31 #include <sys/devfs.h> 32 #include <sys/nlookup.h> 33 #include <sys/file.h> 34 #include <sys/sysctl.h> 35 #include <sys/statvfs.h> 36 #include <sys/caps.h> 37 #include <sys/spinlock.h> 38 39 #include <sys/spinlock2.h> 40 41 int fuse_debug = 0; 42 43 SYSCTL_NODE(_vfs, OID_AUTO, fuse, CTLFLAG_RD, 0, "FUSE"); 44 45 SYSCTL_INT(_vfs_fuse, OID_AUTO, version_major, CTLFLAG_RD, NULL, 46 FUSE_KERNEL_VERSION, "FUSE kernel version (major)"); 47 SYSCTL_INT(_vfs_fuse, OID_AUTO, version_minor, CTLFLAG_RD, NULL, 48 FUSE_KERNEL_MINOR_VERSION, "FUSE kernel version (minor)"); 49 50 SYSCTL_INT(_vfs_fuse, OID_AUTO, debug, CTLFLAG_RW, &fuse_debug, 1, ""); 51 52 int 53 fuse_cmp_version(struct fuse_mount *fmp, uint32_t major, uint32_t minor) 54 { 55 if (fmp->abi_major == major && fmp->abi_minor == minor) 56 return 0; 57 58 if (fmp->abi_major > major || 59 (fmp->abi_major == major && fmp->abi_minor > minor)) 60 return 1; 61 62 return -1; 63 } 64 65 int 66 fuse_mount_kill(struct fuse_mount *fmp) 67 { 68 if (!fuse_test_dead(fmp)) { 69 fuse_set_dead(fmp); 70 wakeup(fmp); 71 KNOTE(&fmp->kq.ki_note, 0); 72 return 0; 73 } 74 75 return -1; 76 } 77 78 int 79 fuse_mount_free(struct fuse_mount *fmp) 80 { 81 if (refcount_release(&fmp->refcnt)) { 82 fuse_dbg("fmp=%p free\n", fmp); 83 mtx_uninit(&fmp->ipc_lock); 84 mtx_uninit(&fmp->mnt_lock); 85 mtx_uninit(&fmp->ino_lock); 86 crfree(fmp->cred); 87 kfree(fmp, M_TEMP); 88 return 0; 89 } 90 fuse_dbg("fmp=%p %u refcnt left\n", fmp, fmp->refcnt); 91 92 return -1; 93 } 94 95 static int 96 fuse_mount(struct mount *mp, char *mntpt, caddr_t data, struct ucred *cred) 97 { 98 struct statfs *sbp = &mp->mnt_stat; 99 struct vnode *devvp; 100 struct file *file; 101 struct nlookupdata nd; 102 struct fuse_mount_info args; 103 struct fuse_mount *fmp; 104 struct fuse_ipc *fip; 105 struct fuse_init_in *fii; 106 struct fuse_init_out *fio; 107 char subtype[512]; 108 int error; 109 110 if (mp->mnt_flag & MNT_UPDATE) 111 return EOPNOTSUPP; 112 113 error = copyin(data, &args, sizeof(args)); 114 if (error) 115 return error; 116 117 memset(sbp->f_mntfromname, 0, sizeof(sbp->f_mntfromname)); 118 error = copyinstr(args.from, sbp->f_mntfromname, 119 sizeof(sbp->f_mntfromname), NULL); 120 if (error) 121 return error; 122 123 memset(sbp->f_mntonname, 0, sizeof(sbp->f_mntonname)); 124 error = copyinstr(mntpt, sbp->f_mntonname, sizeof(sbp->f_mntonname), 125 NULL); 126 if (error) 127 return error; 128 129 memset(subtype, 0, sizeof(subtype)); 130 if (args.subtype != NULL) { 131 error = copyinstr(args.subtype, subtype, sizeof(subtype), NULL); 132 if (error) 133 return error; 134 if (strlen(subtype)) { 135 strlcat(sbp->f_fstypename, ".", sizeof(sbp->f_fstypename)); 136 strlcat(sbp->f_fstypename, subtype, sizeof(sbp->f_fstypename)); 137 } 138 } 139 140 error = nlookup_init(&nd, sbp->f_mntfromname, UIO_SYSSPACE, NLC_FOLLOW); 141 if (!error) { 142 error = nlookup(&nd); 143 if (!error) 144 error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp); 145 nlookup_done(&nd); 146 } 147 if (error) 148 return error; 149 if (!devvp) 150 return ENODEV; 151 152 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 153 error = VOP_ACCESS(devvp, VREAD | VWRITE, cred); 154 if (error == 0) 155 error = caps_priv_check(cred, SYSCAP_NOMOUNT_FUSE); 156 if (error) { 157 vput(devvp); 158 return error; 159 } 160 vn_unlock(devvp); 161 162 fuse_dbg("fd=%d\n", args.fd); 163 file = holdfp_fdp(curthread->td_proc->p_fd, args.fd, FREAD | FWRITE); 164 if (!file) { 165 vrele(devvp); 166 return EBADF; 167 } 168 error = devfs_get_cdevpriv(file, (void**)&fmp); 169 dropfp(curthread, args.fd, file); 170 if (error) { 171 vrele(devvp); 172 return error; 173 } 174 KKASSERT(fmp); 175 176 fmp->mp = mp; 177 fmp->dead = false; 178 mtx_init(&fmp->mnt_lock, "fuse_mnt_lock"); 179 mtx_init(&fmp->ipc_lock, "fuse_ipc_lock"); 180 mtx_init(&fmp->ino_lock, "fuse_ino_lock"); 181 TAILQ_INIT(&fmp->request_head); 182 TAILQ_INIT(&fmp->reply_head); 183 RB_INIT(&fmp->node_head); 184 fmp->devvp = devvp; 185 fmp->cred = crhold(cred); 186 KKASSERT(fmp->refcnt > 0); 187 refcount_acquire(&fmp->refcnt); 188 189 mp->mnt_flag |= MNT_LOCAL; 190 mp->mnt_kern_flag |= MNTK_ALL_MPSAFE; 191 mp->mnt_kern_flag |= MNTK_THR_SYNC; 192 mp->mnt_data = (qaddr_t)fmp; 193 194 fuse_node_new(fmp, FUSE_ROOT_ID, VDIR, &fmp->rfnp); 195 KKASSERT(fmp->rfnp->ino == FUSE_ROOT_ID); 196 197 vfs_getnewfsid(mp); 198 vfs_add_vnodeops(mp, &fuse_vnode_vops, &mp->mnt_vn_norm_ops); 199 vfs_add_vnodeops(mp, &fuse_spec_vops, &mp->mnt_vn_spec_ops); 200 /* XXX fifo ops */ 201 202 fip = fuse_ipc_get(fmp, sizeof(*fii)); 203 fii = fuse_ipc_fill(fip, FUSE_INIT, FUSE_ROOT_ID, NULL); 204 fii->major = FUSE_KERNEL_VERSION; 205 fii->minor = FUSE_KERNEL_MINOR_VERSION; 206 fii->max_readahead = FUSE_BLKSIZE; 207 /* unused */ 208 //fii->flags = ...; 209 210 error = fuse_ipc_tx(fip); 211 if (error) { 212 vrele(devvp); 213 return error; 214 } 215 216 fio = fuse_out_data(fip); 217 fmp->abi_major = fio->major; 218 fmp->abi_minor = fio->minor; 219 fmp->max_write = fio->max_write; 220 221 if (fuse_cmp_version(fmp, 7, 0) < 0) { 222 fuse_ipc_put(fip); 223 vrele(devvp); 224 return EPROTONOSUPPORT; 225 } 226 227 /* unused */ 228 //fio->max_readahead 229 //fio->flags 230 //fio->max_background 231 //fio->congestion_threshold 232 //fio->time_gran 233 //fio->max_pages 234 fuse_print("FUSE UABI %d.%d\n", fmp->abi_major, fmp->abi_minor); 235 236 fuse_ipc_put(fip); 237 238 VFS_STATFS(mp, &mp->mnt_stat, cred); 239 240 spin_init(&fmp->helper_spin, "fuse_spin"); 241 TAILQ_INIT(&fmp->bioq); 242 lwkt_create(fuse_io_thread, fmp, &fmp->helper_td, 243 NULL, 0, -1, "fuse_helper"); 244 245 return 0; 246 } 247 248 static int 249 fuse_unmount(struct mount *mp, int mntflags) 250 { 251 struct fuse_mount *fmp = VFSTOFUSE(mp); 252 struct fuse_ipc *fip; 253 int error, flags = 0; 254 255 mtx_lock(&fmp->mnt_lock); 256 if (mntflags & MNT_FORCE) 257 flags |= FORCECLOSE; 258 259 error = vflush(mp, 0, flags); 260 if (error) { 261 mtx_unlock(&fmp->mnt_lock); 262 fuse_dbg("vflush error=%d\n", error); 263 return error; 264 } 265 266 if (!fuse_test_dead(fmp)) { 267 fuse_dbg("not dead yet, destroying\n"); 268 fip = fuse_ipc_get(fmp, 0); 269 fuse_ipc_fill(fip, FUSE_DESTROY, FUSE_ROOT_ID, NULL); 270 if (!fuse_ipc_tx(fip)) 271 fuse_ipc_put(fip); 272 fuse_mount_kill(fmp); 273 } 274 275 /* Wait for helper thread to exit */ 276 while (fmp->helper_td) { 277 wakeup(&fmp->helper_td); 278 tsleep(&fmp->helper_td, 0, "fusehumnt", 2); 279 } 280 281 KKASSERT(fmp->rfnp->vp == NULL); 282 fuse_node_free(fmp, fmp->rfnp); 283 fmp->rfnp = NULL; 284 285 /* The userspace fs will exit anyway after FUSE_DESTROY. */ 286 vn_lock(fmp->devvp, LK_EXCLUSIVE | LK_RETRY); 287 VOP_CLOSE(fmp->devvp, FREAD | FWRITE, NULL); 288 vn_unlock(fmp->devvp); 289 290 vrele(fmp->devvp); 291 mtx_unlock(&fmp->mnt_lock); 292 293 fuse_mount_free(fmp); 294 mp->mnt_data = NULL; 295 mp->mnt_flag &= ~MNT_LOCAL; 296 297 fuse_dbg("unmount done\n"); 298 299 return 0; 300 } 301 302 /* 303 * 304 * fuse_sync() and friends 305 * 306 * This is an alternative faster way for DragonFlyBSD to flush vnodes, 307 * but requires a bit of code structure. vsetisdirty() puts the vnode 308 * on a per-thread syncer list. When the list is non-empty, .vfs_sync() 309 * is called periodically to flush dirty vnodes. 310 * 311 * In the case of fuse, at the moment file writes are asynchronous and 312 * other attribute changes are synchronous so we only have to check for 313 * dirty buffers. 314 */ 315 static int fuse_sync_scan1(struct mount *mp, struct vnode *vp, void *data); 316 static int fuse_sync_scan2(struct mount *mp, struct vnode *vp, void *data); 317 318 struct scaninfo { 319 int rescan; 320 int waitfor; 321 int allerror; 322 }; 323 324 325 static int 326 fuse_sync(struct mount *mp, int waitfor) 327 { 328 struct scaninfo scaninfo; 329 330 scaninfo.allerror = 0; 331 scaninfo.rescan = 1; 332 scaninfo.waitfor = waitfor; 333 while (scaninfo.rescan) { 334 scaninfo.rescan = 0; 335 vmntvnodescan(mp, VMSC_GETVP|VMSC_NOWAIT, 336 fuse_sync_scan1, fuse_sync_scan2, &scaninfo); 337 } 338 return (scaninfo.allerror); 339 } 340 341 /* 342 * Fast pre-check requires flush? 343 */ 344 static int 345 fuse_sync_scan1(struct mount *mp, struct vnode *vp, void *data) 346 { 347 if (RB_EMPTY(&vp->v_rbdirty_tree)) 348 return -1; 349 return 0; 350 } 351 352 /* 353 * Main flush (re-check) 354 */ 355 static int 356 fuse_sync_scan2(struct mount *mp, struct vnode *vp, void *data) 357 { 358 struct scaninfo *info = data; 359 int error; 360 361 if ((error = VOP_FSYNC(vp, info->waitfor, 0)) != 0) 362 info->allerror = error; 363 return 0; 364 } 365 366 static int 367 fuse_root(struct mount *mp, struct vnode **vpp) 368 { 369 struct fuse_mount *fmp = VFSTOFUSE(mp); 370 int error; 371 372 KASSERT(fmp->rfnp, ("no root node")); 373 KKASSERT(fmp->rfnp->fmp); 374 375 error = fuse_node_vn(fmp->rfnp, vpp); 376 if (!error) { 377 struct vnode *vp = *vpp; 378 vsetflags(vp, VROOT); 379 KKASSERT(vp->v_type == VDIR); 380 } 381 382 return error; 383 } 384 385 static int 386 fuse_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 387 { 388 struct fuse_mount *fmp = VFSTOFUSE(mp); 389 struct fuse_ipc *fip; 390 struct fuse_statfs_out *fso; 391 int error; 392 393 fip = fuse_ipc_get(fmp, 0); 394 fuse_ipc_fill(fip, FUSE_STATFS, FUSE_ROOT_ID, cred); 395 error = fuse_ipc_tx(fip); 396 if (error) 397 return error; 398 399 fso = fuse_out_data(fip); 400 401 mtx_lock(&fmp->mnt_lock); 402 sbp->f_bsize = fso->st.frsize; 403 sbp->f_iosize = FUSE_BLKSIZE; 404 sbp->f_blocks = fso->st.blocks; 405 sbp->f_bfree = fso->st.bfree; 406 sbp->f_bavail = fso->st.bavail; 407 sbp->f_files = fso->st.files; 408 sbp->f_ffree = fso->st.ffree; 409 mtx_unlock(&fmp->mnt_lock); 410 411 fuse_ipc_put(fip); 412 413 return 0; 414 } 415 416 static int 417 fuse_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred) 418 { 419 struct fuse_mount *fmp = VFSTOFUSE(mp); 420 struct fuse_ipc *fip; 421 struct fuse_statfs_out *fso; 422 int error; 423 424 fip = fuse_ipc_get(fmp, 0); 425 fuse_ipc_fill(fip, FUSE_STATFS, FUSE_ROOT_ID, cred); 426 error = fuse_ipc_tx(fip); 427 if (error) 428 return error; 429 430 fso = fuse_out_data(fip); 431 432 mtx_lock(&fmp->mnt_lock); 433 sbp->f_bsize = fso->st.frsize; 434 sbp->f_frsize = FUSE_BLKSIZE; 435 sbp->f_blocks = fso->st.blocks; 436 sbp->f_bfree = fso->st.bfree; 437 sbp->f_bavail = fso->st.bavail; 438 sbp->f_files = fso->st.files; 439 sbp->f_ffree = fso->st.ffree; 440 mtx_unlock(&fmp->mnt_lock); 441 442 fuse_ipc_put(fip); 443 444 return 0; 445 } 446 447 static int 448 fuse_init(struct vfsconf *vfsp) 449 { 450 int error; 451 452 fuse_node_init(); 453 fuse_ipc_init(); 454 455 error = fuse_device_init(); 456 if (error) { 457 fuse_ipc_cleanup(); 458 fuse_node_cleanup(); 459 return error; 460 } 461 462 fuse_print("FUSE ABI %d.%d\n", FUSE_KERNEL_VERSION, 463 FUSE_KERNEL_MINOR_VERSION); 464 465 return 0; 466 } 467 468 static int 469 fuse_uninit(struct vfsconf *vfsp) 470 { 471 fuse_ipc_cleanup(); 472 fuse_node_cleanup(); 473 fuse_device_cleanup(); 474 475 return 0; 476 } 477 478 static struct vfsops fuse_vfsops = { 479 .vfs_flags = 0, 480 .vfs_init = fuse_init, 481 .vfs_uninit = fuse_uninit, 482 .vfs_mount = fuse_mount, 483 .vfs_unmount = fuse_unmount, 484 .vfs_sync = fuse_sync, 485 .vfs_root = fuse_root, 486 .vfs_statfs = fuse_statfs, 487 .vfs_statvfs = fuse_statvfs, 488 }; 489 490 VFS_SET(fuse_vfsops, fuse, VFCF_SYNTHETIC | VFCF_MPSAFE); 491 MODULE_VERSION(fuse, 1); 492