xref: /dragonfly/sys/vfs/fuse/fuse_vfsops.c (revision f9993810)
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 
38 int fuse_debug = 0;
39 
40 SYSCTL_NODE(_vfs, OID_AUTO, fuse, CTLFLAG_RD, 0, "FUSE");
41 
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)");
46 
47 SYSCTL_INT(_vfs_fuse, OID_AUTO, debug, CTLFLAG_RW, &fuse_debug, 1, "");
48 
49 int
50 fuse_cmp_version(struct fuse_mount *fmp, uint32_t major, uint32_t minor)
51 {
52 	if (fmp->abi_major == major && fmp->abi_minor == minor)
53 		return 0;
54 
55 	if (fmp->abi_major > major ||
56 	    (fmp->abi_major == major && fmp->abi_minor > minor))
57 		return 1;
58 
59 	return -1;
60 }
61 
62 int
63 fuse_mount_kill(struct fuse_mount *fmp)
64 {
65 	if (!fuse_test_dead(fmp)) {
66 		fuse_set_dead(fmp);
67 		wakeup(fmp);
68 		KNOTE(&fmp->kq.ki_note, 0);
69 		return 0;
70 	}
71 
72 	return -1;
73 }
74 
75 int
76 fuse_mount_free(struct fuse_mount *fmp)
77 {
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);
82 		crfree(fmp->cred);
83 		kfree(fmp, M_TEMP);
84 		return 0;
85 	}
86 	fuse_dbg("fmp=%p %u refcnt left\n", fmp, fmp->refcnt);
87 
88 	return -1;
89 }
90 
91 static int
92 fuse_mount(struct mount *mp, char *mntpt, caddr_t data, struct ucred *cred)
93 {
94 	struct statfs *sbp = &mp->mnt_stat;
95 	struct vnode *devvp;
96 	struct file *file;
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;
103 	char subtype[512];
104 	int error;
105 
106 	if (mp->mnt_flag & MNT_UPDATE)
107 		return EOPNOTSUPP;
108 
109 	error = copyin(data, &args, sizeof(args));
110 	if (error)
111 		return error;
112 	memcpy(sbp->f_mntfromname, args.from, sizeof(sbp->f_mntfromname));
113 
114 	memset(sbp->f_mntfromname, 0, sizeof(sbp->f_mntfromname));
115 	error = copyinstr(args.from, sbp->f_mntfromname,
116 	    sizeof(sbp->f_mntfromname), NULL);
117 	if (error)
118 		return error;
119 
120 	memset(sbp->f_mntonname, 0, sizeof(sbp->f_mntonname));
121 	error = copyinstr(mntpt, sbp->f_mntonname, sizeof(sbp->f_mntonname),
122 	    NULL);
123 	if (error)
124 		return error;
125 
126 	memset(subtype, 0, sizeof(subtype));
127 	error = copyinstr(args.subtype, subtype, sizeof(subtype), NULL);
128 	if (error)
129 		return error;
130 	if (strlen(subtype)) {
131 		strlcat(sbp->f_fstypename, ".", sizeof(sbp->f_fstypename));
132 		strlcat(sbp->f_fstypename, subtype, sizeof(sbp->f_fstypename));
133 	}
134 
135 	error = nlookup_init(&nd, sbp->f_mntfromname, UIO_SYSSPACE, NLC_FOLLOW);
136 	if (!error) {
137 		error = nlookup(&nd);
138 		if (!error)
139 			error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
140 		nlookup_done(&nd);
141 	}
142 	if (error)
143 		return error;
144 	if (!devvp)
145 		return ENODEV;
146 
147 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
148 	error = VOP_ACCESS(devvp, VREAD | VWRITE, cred);
149 	if (error == 0)
150 		error = caps_priv_check(cred, SYSCAP_NOMOUNT_FUSE);
151 	if (error) {
152 		vput(devvp);
153 		return error;
154 	}
155 	vn_unlock(devvp);
156 
157 	fuse_dbg("fd=%d\n", args.fd);
158 	file = holdfp_fdp(curthread->td_proc->p_fd, args.fd, FREAD | FWRITE);
159 	if (!file) {
160 		vrele(devvp);
161 		return EBADF;
162 	}
163 	error = devfs_get_cdevpriv(file, (void**)&fmp);
164 	dropfp(curthread, args.fd, file);
165 	if (error) {
166 		vrele(devvp);
167 		return error;
168 	}
169 	KKASSERT(fmp);
170 
171 	fmp->mp = mp;
172 	fmp->dead = false;
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);
177 	fmp->devvp = devvp;
178 	fmp->cred = crhold(cred);
179 	KKASSERT(fmp->refcnt > 0);
180 	refcount_acquire(&fmp->refcnt);
181 
182 	mp->mnt_flag |= MNT_LOCAL;
183 	mp->mnt_kern_flag |= MNTK_ALL_MPSAFE;
184 	mp->mnt_data = (qaddr_t)fmp;
185 
186 	fuse_node_new(fmp, FUSE_ROOT_ID, VDIR, &fmp->rfnp);
187 	KKASSERT(fmp->rfnp->ino == FUSE_ROOT_ID);
188 
189 	vfs_getnewfsid(mp);
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);
192 
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;
198 	/* unused */
199 	//fii->flags = ...;
200 
201 	error = fuse_ipc_tx(fip);
202 	if (error) {
203 		vrele(devvp);
204 		return error;
205 	}
206 
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;
211 
212 	if (fuse_cmp_version(fmp, 7, 0) < 0) {
213 		fuse_ipc_put(fip);
214 		vrele(devvp);
215 		return EPROTONOSUPPORT;
216 	}
217 
218 	/* unused */
219 	//fio->max_readahead
220 	//fio->flags
221 	//fio->max_background
222 	//fio->congestion_threshold
223 	//fio->time_gran
224 	//fio->max_pages
225 	fuse_print("FUSE UABI %d.%d\n", fmp->abi_major, fmp->abi_minor);
226 
227 	fuse_ipc_put(fip);
228 
229 	VFS_STATFS(mp, &mp->mnt_stat, cred);
230 
231 	return 0;
232 }
233 
234 static int
235 fuse_unmount(struct mount *mp, int mntflags)
236 {
237 	struct fuse_mount *fmp = VFSTOFUSE(mp);
238 	struct fuse_ipc *fip;
239 	int error, flags = 0;
240 
241 	mtx_lock(&fmp->mnt_lock);
242 	if (mntflags & MNT_FORCE)
243 		flags |= FORCECLOSE;
244 
245 	error = vflush(mp, 0, flags);
246 	if (error) {
247 		mtx_unlock(&fmp->mnt_lock);
248 		fuse_dbg("vflush error=%d\n", error);
249 		return error;
250 	}
251 
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))
257 			fuse_ipc_put(fip);
258 		fuse_mount_kill(fmp);
259 	}
260 
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);
265 
266 	vrele(fmp->devvp);
267 	mtx_unlock(&fmp->mnt_lock);
268 
269 	fuse_mount_free(fmp);
270 	mp->mnt_data = NULL;
271 	mp->mnt_flag &= ~MNT_LOCAL;
272 
273 	fuse_dbg("unmount done\n");
274 
275 	return 0;
276 }
277 
278 static int
279 fuse_root(struct mount *mp, struct vnode **vpp)
280 {
281 	struct fuse_mount *fmp = VFSTOFUSE(mp);
282 	int error;
283 
284 	KASSERT(fmp->rfnp, ("no root node"));
285 	KKASSERT(fmp->rfnp->fmp);
286 
287 	error = fuse_node_vn(fmp->rfnp, LK_EXCLUSIVE, vpp);
288 	if (!error) {
289 		struct vnode *vp = *vpp;
290 		vp->v_flag |= VROOT;
291 		KKASSERT(vp->v_type == VDIR);
292 	}
293 
294 	return error;
295 }
296 
297 static int
298 fuse_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
299 {
300 	struct fuse_mount *fmp = VFSTOFUSE(mp);
301 	struct fuse_ipc *fip;
302 	struct fuse_statfs_out *fso;
303 	int error;
304 
305 	fip = fuse_ipc_get(fmp, 0);
306 	fuse_ipc_fill(fip, FUSE_STATFS, FUSE_ROOT_ID, cred);
307 	error = fuse_ipc_tx(fip);
308 	if (error)
309 		return error;
310 
311 	fso = fuse_out_data(fip);
312 
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);
322 
323 	fuse_ipc_put(fip);
324 
325 	return 0;
326 }
327 
328 static int
329 fuse_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
330 {
331 	struct fuse_mount *fmp = VFSTOFUSE(mp);
332 	struct fuse_ipc *fip;
333 	struct fuse_statfs_out *fso;
334 	int error;
335 
336 	fip = fuse_ipc_get(fmp, 0);
337 	fuse_ipc_fill(fip, FUSE_STATFS, FUSE_ROOT_ID, cred);
338 	error = fuse_ipc_tx(fip);
339 	if (error)
340 		return error;
341 
342 	fso = fuse_out_data(fip);
343 
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);
353 
354 	fuse_ipc_put(fip);
355 
356 	return 0;
357 }
358 
359 static int
360 fuse_init(struct vfsconf *vfsp)
361 {
362 	int error;
363 
364 	fuse_node_init();
365 	fuse_ipc_init();
366 	fuse_file_init();
367 
368 	error = fuse_device_init();
369 	if (error) {
370 		fuse_file_cleanup();
371 		fuse_ipc_cleanup();
372 		fuse_node_cleanup();
373 		return error;
374 	}
375 
376 	fuse_print("FUSE ABI %d.%d\n", FUSE_KERNEL_VERSION,
377 	    FUSE_KERNEL_MINOR_VERSION);
378 
379 	return 0;
380 }
381 
382 static int
383 fuse_uninit(struct vfsconf *vfsp)
384 {
385 	fuse_file_cleanup();
386 	fuse_ipc_cleanup();
387 	fuse_node_cleanup();
388 	fuse_device_cleanup();
389 
390 	return 0;
391 }
392 
393 static struct vfsops fuse_vfsops = {
394 	.vfs_flags = 0,
395 	.vfs_init = fuse_init,
396 	.vfs_uninit = fuse_uninit,
397 	.vfs_mount = fuse_mount,
398 	.vfs_unmount = fuse_unmount,
399 	.vfs_root = fuse_root,
400 	.vfs_statfs = fuse_statfs,
401 	.vfs_statvfs = fuse_statvfs,
402 };
403 
404 VFS_SET(fuse_vfsops, fuse, VFCF_SYNTHETIC | VFCF_MPSAFE);
405 MODULE_VERSION(fuse, 1);
406