15812c3ccSTomohiro Kusumi /*-
25812c3ccSTomohiro Kusumi * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
35812c3ccSTomohiro Kusumi * Copyright (c) 2019 The DragonFly Project
45812c3ccSTomohiro Kusumi * All rights reserved.
55812c3ccSTomohiro Kusumi *
65812c3ccSTomohiro Kusumi * Redistribution and use in source and binary forms, with or without
75812c3ccSTomohiro Kusumi * modification, are permitted provided that the following conditions
85812c3ccSTomohiro Kusumi * are met:
95812c3ccSTomohiro Kusumi * 1. Redistributions of source code must retain the above copyright
105812c3ccSTomohiro Kusumi * notice, this list of conditions and the following disclaimer.
115812c3ccSTomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright
125812c3ccSTomohiro Kusumi * notice, this list of conditions and the following disclaimer in the
135812c3ccSTomohiro Kusumi * documentation and/or other materials provided with the distribution.
145812c3ccSTomohiro Kusumi *
155812c3ccSTomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
165812c3ccSTomohiro Kusumi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175812c3ccSTomohiro Kusumi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185812c3ccSTomohiro Kusumi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
195812c3ccSTomohiro Kusumi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205812c3ccSTomohiro Kusumi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215812c3ccSTomohiro Kusumi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225812c3ccSTomohiro Kusumi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235812c3ccSTomohiro Kusumi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245812c3ccSTomohiro Kusumi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255812c3ccSTomohiro Kusumi * SUCH DAMAGE.
265812c3ccSTomohiro Kusumi */
275812c3ccSTomohiro Kusumi
285812c3ccSTomohiro Kusumi #ifndef FUSE_FUSE_H
295812c3ccSTomohiro Kusumi #define FUSE_FUSE_H
305812c3ccSTomohiro Kusumi
315812c3ccSTomohiro Kusumi #ifndef INVARIANTS
325812c3ccSTomohiro Kusumi #define INVARIANTS
335812c3ccSTomohiro Kusumi #endif
345812c3ccSTomohiro Kusumi
355812c3ccSTomohiro Kusumi #include <sys/types.h>
365812c3ccSTomohiro Kusumi #include <sys/stat.h>
375812c3ccSTomohiro Kusumi #include <sys/systm.h>
385812c3ccSTomohiro Kusumi #include <sys/kernel.h>
395812c3ccSTomohiro Kusumi #include <sys/module.h>
405812c3ccSTomohiro Kusumi #include <sys/malloc.h>
415812c3ccSTomohiro Kusumi #include <sys/objcache.h>
425812c3ccSTomohiro Kusumi #include <sys/proc.h>
435812c3ccSTomohiro Kusumi #include <sys/thread.h>
445812c3ccSTomohiro Kusumi #include <sys/mutex.h>
455812c3ccSTomohiro Kusumi #include <sys/mutex2.h>
465812c3ccSTomohiro Kusumi #include <sys/refcount.h>
475812c3ccSTomohiro Kusumi #include <sys/event.h>
485812c3ccSTomohiro Kusumi #include <sys/mount.h>
495812c3ccSTomohiro Kusumi #include <sys/vnode.h>
505812c3ccSTomohiro Kusumi #include <sys/file.h>
515812c3ccSTomohiro Kusumi #include <sys/ucred.h>
525812c3ccSTomohiro Kusumi #include <sys/unistd.h>
535812c3ccSTomohiro Kusumi #include <sys/sysctl.h>
545812c3ccSTomohiro Kusumi #include <sys/errno.h>
555812c3ccSTomohiro Kusumi #include <sys/queue.h>
565812c3ccSTomohiro Kusumi #include <sys/tree.h>
575d0d0bafSMatthew Dillon #include <sys/lockf.h>
585812c3ccSTomohiro Kusumi #include <machine/atomic.h>
595812c3ccSTomohiro Kusumi
605812c3ccSTomohiro Kusumi #include "fuse_debug.h"
615812c3ccSTomohiro Kusumi #include "fuse_mount.h"
625812c3ccSTomohiro Kusumi #include "fuse_abi.h"
635812c3ccSTomohiro Kusumi
645812c3ccSTomohiro Kusumi #define VFSTOFUSE(mp) ((struct fuse_mount*)((mp)->mnt_data))
655812c3ccSTomohiro Kusumi #define VTOI(vp) ((struct fuse_node*)((vp)->v_data))
665812c3ccSTomohiro Kusumi
675d0d0bafSMatthew Dillon #define FUSE_MAXFILESIZE 0x7FFFFFFFFFFFFFFFLL
685812c3ccSTomohiro Kusumi #define FUSE_BLKSIZE PAGE_SIZE
695812c3ccSTomohiro Kusumi #define FUSE_BLKMASK (FUSE_BLKSIZE - 1)
705812c3ccSTomohiro Kusumi #define FUSE_BLKMASK64 ((off_t)(FUSE_BLKSIZE - 1))
715812c3ccSTomohiro Kusumi
725812c3ccSTomohiro Kusumi SYSCTL_DECL(_vfs_fuse);
735812c3ccSTomohiro Kusumi
745812c3ccSTomohiro Kusumi extern int fuse_debug;
755812c3ccSTomohiro Kusumi extern struct vop_ops fuse_vnode_vops;
765812c3ccSTomohiro Kusumi extern struct vop_ops fuse_spec_vops;
775812c3ccSTomohiro Kusumi
78*1a8e5e4cSMatthew Dillon struct fuse_node;
79*1a8e5e4cSMatthew Dillon
80*1a8e5e4cSMatthew Dillon RB_HEAD(fuse_node_tree, fuse_node);
81*1a8e5e4cSMatthew Dillon
825812c3ccSTomohiro Kusumi struct fuse_mount {
835812c3ccSTomohiro Kusumi struct mount *mp;
845812c3ccSTomohiro Kusumi struct vnode *devvp;
855812c3ccSTomohiro Kusumi struct ucred *cred;
865812c3ccSTomohiro Kusumi struct kqinfo kq;
875812c3ccSTomohiro Kusumi struct fuse_node *rfnp;
885812c3ccSTomohiro Kusumi struct mtx mnt_lock;
895812c3ccSTomohiro Kusumi struct mtx ipc_lock;
90*1a8e5e4cSMatthew Dillon struct mtx ino_lock;
915d0d0bafSMatthew Dillon struct thread *helper_td; // helper thread
925d0d0bafSMatthew Dillon struct spinlock helper_spin; // protect bioq
935d0d0bafSMatthew Dillon TAILQ_HEAD(, bio) bioq; // bioq for strategy I/Os
945812c3ccSTomohiro Kusumi TAILQ_HEAD(,fuse_ipc) request_head;
955812c3ccSTomohiro Kusumi TAILQ_HEAD(,fuse_ipc) reply_head;
96*1a8e5e4cSMatthew Dillon struct fuse_node_tree node_head; // inode index
975812c3ccSTomohiro Kusumi
985812c3ccSTomohiro Kusumi unsigned int refcnt;
995812c3ccSTomohiro Kusumi unsigned long unique;
1005812c3ccSTomohiro Kusumi int dead;
1015812c3ccSTomohiro Kusumi uint64_t nosys;
1025812c3ccSTomohiro Kusumi uint32_t abi_major;
1035812c3ccSTomohiro Kusumi uint32_t abi_minor;
1045812c3ccSTomohiro Kusumi uint32_t max_write;
1055812c3ccSTomohiro Kusumi };
1065812c3ccSTomohiro Kusumi
1075812c3ccSTomohiro Kusumi struct fuse_node {
108*1a8e5e4cSMatthew Dillon RB_ENTRY(fuse_node) node_entry; // inode index entry
1095812c3ccSTomohiro Kusumi struct vnode *vp;
1105812c3ccSTomohiro Kusumi struct vattr attr;
1115812c3ccSTomohiro Kusumi struct fuse_mount *fmp;
1125812c3ccSTomohiro Kusumi struct fuse_node *pfnp;
1135812c3ccSTomohiro Kusumi struct mtx node_lock;
1145d0d0bafSMatthew Dillon struct lockf advlock;
1155812c3ccSTomohiro Kusumi
1165812c3ccSTomohiro Kusumi uint64_t ino;
1175812c3ccSTomohiro Kusumi enum vtype type;
1185812c3ccSTomohiro Kusumi size_t size;
1195812c3ccSTomohiro Kusumi uint64_t nlookup;
1205812c3ccSTomohiro Kusumi uint64_t fh;
1215812c3ccSTomohiro Kusumi bool closed; /* XXX associated with closed fh */
1225d0d0bafSMatthew Dillon int modified : 1; /* file modified */
1235d0d0bafSMatthew Dillon int changed : 1; /* file inode changed */
1245d0d0bafSMatthew Dillon int accessed : 1; /* file accessed */
1255d0d0bafSMatthew Dillon int attrgood : 1; /* have valid attributes */
1265d0d0bafSMatthew Dillon int sizeoverride : 1; /* override attr size with fnp->size */
1275812c3ccSTomohiro Kusumi };
1285812c3ccSTomohiro Kusumi
1295812c3ccSTomohiro Kusumi struct fuse_buf {
1305812c3ccSTomohiro Kusumi void *buf;
1315812c3ccSTomohiro Kusumi size_t len;
1325812c3ccSTomohiro Kusumi };
1335812c3ccSTomohiro Kusumi
1345812c3ccSTomohiro Kusumi struct fuse_ipc {
1355812c3ccSTomohiro Kusumi struct fuse_mount *fmp;
1365812c3ccSTomohiro Kusumi struct fuse_buf request;
1375812c3ccSTomohiro Kusumi struct fuse_buf reply;
1385812c3ccSTomohiro Kusumi TAILQ_ENTRY(fuse_ipc) request_entry;
1395812c3ccSTomohiro Kusumi TAILQ_ENTRY(fuse_ipc) reply_entry;
1405812c3ccSTomohiro Kusumi
1415812c3ccSTomohiro Kusumi unsigned int refcnt;
1425812c3ccSTomohiro Kusumi uint64_t unique;
143*1a8e5e4cSMatthew Dillon int sent;
1445812c3ccSTomohiro Kusumi int done;
1455812c3ccSTomohiro Kusumi };
1465812c3ccSTomohiro Kusumi
1475812c3ccSTomohiro Kusumi int fuse_cmp_version(struct fuse_mount*, uint32_t, uint32_t);
1485812c3ccSTomohiro Kusumi int fuse_mount_kill(struct fuse_mount*);
1495812c3ccSTomohiro Kusumi int fuse_mount_free(struct fuse_mount*);
1505812c3ccSTomohiro Kusumi
1515812c3ccSTomohiro Kusumi int fuse_device_init(void);
1525812c3ccSTomohiro Kusumi void fuse_device_cleanup(void);
1535812c3ccSTomohiro Kusumi
1545812c3ccSTomohiro Kusumi void fuse_node_new(struct fuse_mount*, uint64_t, enum vtype,
1555812c3ccSTomohiro Kusumi struct fuse_node**);
156*1a8e5e4cSMatthew Dillon void fuse_node_free(struct fuse_mount *, struct fuse_node *);
157*1a8e5e4cSMatthew Dillon int fuse_alloc_node(struct fuse_mount *, struct fuse_node *,
158*1a8e5e4cSMatthew Dillon uint64_t, enum vtype, struct vnode **);
1595d0d0bafSMatthew Dillon int fuse_node_vn(struct fuse_node*, struct vnode**);
1605812c3ccSTomohiro Kusumi int fuse_node_truncate(struct fuse_node*, size_t, size_t);
1615812c3ccSTomohiro Kusumi void fuse_node_init(void);
1625812c3ccSTomohiro Kusumi void fuse_node_cleanup(void);
1635812c3ccSTomohiro Kusumi
1645812c3ccSTomohiro Kusumi void fuse_buf_alloc(struct fuse_buf*, size_t);
1655812c3ccSTomohiro Kusumi void fuse_buf_free(struct fuse_buf*);
1665812c3ccSTomohiro Kusumi struct fuse_ipc *fuse_ipc_get(struct fuse_mount*, size_t);
1675812c3ccSTomohiro Kusumi void fuse_ipc_put(struct fuse_ipc*);
1685812c3ccSTomohiro Kusumi void *fuse_ipc_fill(struct fuse_ipc*, int, uint64_t, struct ucred*);
1695812c3ccSTomohiro Kusumi int fuse_ipc_tx(struct fuse_ipc*);
170*1a8e5e4cSMatthew Dillon int fuse_ipc_tx_noreply(struct fuse_ipc*);
1715812c3ccSTomohiro Kusumi void fuse_ipc_init(void);
1725812c3ccSTomohiro Kusumi void fuse_ipc_cleanup(void);
1735812c3ccSTomohiro Kusumi
1745812c3ccSTomohiro Kusumi int fuse_read(struct vop_read_args*);
1755812c3ccSTomohiro Kusumi int fuse_write(struct vop_write_args*);
1765812c3ccSTomohiro Kusumi int fuse_dio_write(struct vop_write_args*);
1775812c3ccSTomohiro Kusumi
1785812c3ccSTomohiro Kusumi void fuse_hexdump(const char*, size_t);
1795812c3ccSTomohiro Kusumi void fuse_fill_in_header(struct fuse_in_header*, uint32_t, uint32_t, uint64_t,
1805812c3ccSTomohiro Kusumi uint64_t, uint32_t, uint32_t, uint32_t);
1815812c3ccSTomohiro Kusumi int fuse_forget_node(struct fuse_mount*, uint64_t, uint64_t, struct ucred*);
1825812c3ccSTomohiro Kusumi int fuse_audit_length(struct fuse_in_header*, struct fuse_out_header*);
1835812c3ccSTomohiro Kusumi const char *fuse_get_ops(int);
1845d0d0bafSMatthew Dillon void fuse_io_thread(void *arg);
1855812c3ccSTomohiro Kusumi
1865812c3ccSTomohiro Kusumi static __inline int
fuse_test_dead(struct fuse_mount * fmp)1875812c3ccSTomohiro Kusumi fuse_test_dead(struct fuse_mount *fmp)
1885812c3ccSTomohiro Kusumi {
1895812c3ccSTomohiro Kusumi return atomic_load_acq_int(&fmp->dead);
1905812c3ccSTomohiro Kusumi }
1915812c3ccSTomohiro Kusumi
1925812c3ccSTomohiro Kusumi static __inline void
fuse_set_dead(struct fuse_mount * fmp)1935812c3ccSTomohiro Kusumi fuse_set_dead(struct fuse_mount *fmp)
1945812c3ccSTomohiro Kusumi {
1955812c3ccSTomohiro Kusumi atomic_store_rel_int(&fmp->dead, 1);
1965812c3ccSTomohiro Kusumi }
1975812c3ccSTomohiro Kusumi
1985812c3ccSTomohiro Kusumi static __inline int
fuse_test_nosys(struct fuse_mount * fmp,int op)1995812c3ccSTomohiro Kusumi fuse_test_nosys(struct fuse_mount *fmp, int op)
2005812c3ccSTomohiro Kusumi {
2015812c3ccSTomohiro Kusumi return atomic_load_acq_64(&fmp->nosys) & (1 << op);
2025812c3ccSTomohiro Kusumi }
2035812c3ccSTomohiro Kusumi
2045812c3ccSTomohiro Kusumi static __inline void
fuse_set_nosys(struct fuse_mount * fmp,int op)2055812c3ccSTomohiro Kusumi fuse_set_nosys(struct fuse_mount *fmp, int op)
2065812c3ccSTomohiro Kusumi {
2075812c3ccSTomohiro Kusumi atomic_set_64(&fmp->nosys, 1 << op);
2085812c3ccSTomohiro Kusumi }
2095812c3ccSTomohiro Kusumi
2105812c3ccSTomohiro Kusumi static __inline int
fuse_ipc_test_replied(struct fuse_ipc * fip)2115812c3ccSTomohiro Kusumi fuse_ipc_test_replied(struct fuse_ipc *fip)
2125812c3ccSTomohiro Kusumi {
2135812c3ccSTomohiro Kusumi return atomic_load_acq_int(&fip->done);
2145812c3ccSTomohiro Kusumi }
2155812c3ccSTomohiro Kusumi
2165812c3ccSTomohiro Kusumi static __inline void
fuse_ipc_set_replied(struct fuse_ipc * fip)2175812c3ccSTomohiro Kusumi fuse_ipc_set_replied(struct fuse_ipc *fip)
2185812c3ccSTomohiro Kusumi {
2195812c3ccSTomohiro Kusumi atomic_store_rel_int(&fip->done, 1);
2205812c3ccSTomohiro Kusumi }
2215812c3ccSTomohiro Kusumi
2225812c3ccSTomohiro Kusumi static __inline int
fuse_ipc_test_and_set_replied(struct fuse_ipc * fip)2235812c3ccSTomohiro Kusumi fuse_ipc_test_and_set_replied(struct fuse_ipc *fip)
2245812c3ccSTomohiro Kusumi {
2255812c3ccSTomohiro Kusumi return atomic_cmpset_int(&fip->done, 0, 1);
2265812c3ccSTomohiro Kusumi }
2275812c3ccSTomohiro Kusumi
2285812c3ccSTomohiro Kusumi static __inline void*
fuse_in(struct fuse_ipc * fip)2295812c3ccSTomohiro Kusumi fuse_in(struct fuse_ipc *fip)
2305812c3ccSTomohiro Kusumi {
2315812c3ccSTomohiro Kusumi return fip->request.buf;
2325812c3ccSTomohiro Kusumi }
2335812c3ccSTomohiro Kusumi
2345812c3ccSTomohiro Kusumi static __inline size_t
fuse_in_size(struct fuse_ipc * fip)2355812c3ccSTomohiro Kusumi fuse_in_size(struct fuse_ipc *fip)
2365812c3ccSTomohiro Kusumi {
2375812c3ccSTomohiro Kusumi return fip->request.len;
2385812c3ccSTomohiro Kusumi }
2395812c3ccSTomohiro Kusumi
2405812c3ccSTomohiro Kusumi static __inline void*
fuse_in_data(struct fuse_ipc * fip)2415812c3ccSTomohiro Kusumi fuse_in_data(struct fuse_ipc *fip)
2425812c3ccSTomohiro Kusumi {
2435812c3ccSTomohiro Kusumi return (struct fuse_in_header*)fuse_in(fip) + 1;
2445812c3ccSTomohiro Kusumi }
2455812c3ccSTomohiro Kusumi
2465812c3ccSTomohiro Kusumi static __inline size_t
fuse_in_data_size(struct fuse_ipc * fip)2475812c3ccSTomohiro Kusumi fuse_in_data_size(struct fuse_ipc *fip)
2485812c3ccSTomohiro Kusumi {
2495812c3ccSTomohiro Kusumi return fuse_in_size(fip) - sizeof(struct fuse_in_header);
2505812c3ccSTomohiro Kusumi }
2515812c3ccSTomohiro Kusumi
2525812c3ccSTomohiro Kusumi static __inline void*
fuse_out(struct fuse_ipc * fip)2535812c3ccSTomohiro Kusumi fuse_out(struct fuse_ipc *fip)
2545812c3ccSTomohiro Kusumi {
2555812c3ccSTomohiro Kusumi return fip->reply.buf;
2565812c3ccSTomohiro Kusumi }
2575812c3ccSTomohiro Kusumi
2585812c3ccSTomohiro Kusumi static __inline size_t
fuse_out_size(struct fuse_ipc * fip)2595812c3ccSTomohiro Kusumi fuse_out_size(struct fuse_ipc *fip)
2605812c3ccSTomohiro Kusumi {
2615812c3ccSTomohiro Kusumi return fip->reply.len;
2625812c3ccSTomohiro Kusumi }
2635812c3ccSTomohiro Kusumi
2645812c3ccSTomohiro Kusumi static __inline void*
fuse_out_data(struct fuse_ipc * fip)2655812c3ccSTomohiro Kusumi fuse_out_data(struct fuse_ipc *fip)
2665812c3ccSTomohiro Kusumi {
2675812c3ccSTomohiro Kusumi return (struct fuse_out_header*)fuse_out(fip) + 1;
2685812c3ccSTomohiro Kusumi }
2695812c3ccSTomohiro Kusumi
2705812c3ccSTomohiro Kusumi static __inline size_t
fuse_out_data_size(struct fuse_ipc * fip)2715812c3ccSTomohiro Kusumi fuse_out_data_size(struct fuse_ipc *fip)
2725812c3ccSTomohiro Kusumi {
2735812c3ccSTomohiro Kusumi return fuse_out_size(fip) - sizeof(struct fuse_out_header);
2745812c3ccSTomohiro Kusumi }
2755812c3ccSTomohiro Kusumi
2765812c3ccSTomohiro Kusumi static __inline void
fuse_knote(struct vnode * vp,int flags)2775812c3ccSTomohiro Kusumi fuse_knote(struct vnode *vp, int flags)
2785812c3ccSTomohiro Kusumi {
2795812c3ccSTomohiro Kusumi if (flags)
2805812c3ccSTomohiro Kusumi KNOTE(&vp->v_pollinfo.vpi_kqinfo.ki_note, flags);
2815812c3ccSTomohiro Kusumi }
2825812c3ccSTomohiro Kusumi
2835812c3ccSTomohiro Kusumi #endif /* FUSE_FUSE_H */
284