xref: /dragonfly/sys/vfs/fuse/fuse_vfsops.c (revision 1a8e5e4cf0cfbe16676810f7edca73f98bb9b8f5)
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
fuse_cmp_version(struct fuse_mount * fmp,uint32_t major,uint32_t minor)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
fuse_mount_kill(struct fuse_mount * fmp)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
fuse_mount_free(struct fuse_mount * fmp)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
fuse_mount(struct mount * mp,char * mntpt,caddr_t data,struct ucred * cred)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
fuse_unmount(struct mount * mp,int mntflags)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
fuse_sync(struct mount * mp,int waitfor)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
fuse_sync_scan1(struct mount * mp,struct vnode * vp,void * data)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
fuse_sync_scan2(struct mount * mp,struct vnode * vp,void * data)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
fuse_root(struct mount * mp,struct vnode ** vpp)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
fuse_statfs(struct mount * mp,struct statfs * sbp,struct ucred * cred)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
fuse_statvfs(struct mount * mp,struct statvfs * sbp,struct ucred * cred)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
fuse_init(struct vfsconf * vfsp)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
fuse_uninit(struct vfsconf * vfsp)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