xref: /dragonfly/sys/vfs/fuse/fuse_vfsops.c (revision 7485684f)
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