Merge branch 'vendor/MDOCML'
[dragonfly.git] / sys / vfs / fuse / fuse_vfsops.c
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/priv.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)
150                 error = priv_check_cred(cred, PRIV_ROOT, 0);
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_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,
401 };
402
403 VFS_SET(fuse_vfsops, fuse, VFCF_SYNTHETIC | VFCF_MPSAFE);
404 MODULE_VERSION(fuse, 1);