xref: /dragonfly/sys/vfs/fuse/fuse.h (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 #ifndef FUSE_FUSE_H
29 #define FUSE_FUSE_H
30 
31 #ifndef INVARIANTS
32 #define INVARIANTS
33 #endif
34 
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/module.h>
40 #include <sys/malloc.h>
41 #include <sys/objcache.h>
42 #include <sys/proc.h>
43 #include <sys/thread.h>
44 #include <sys/mutex.h>
45 #include <sys/mutex2.h>
46 #include <sys/refcount.h>
47 #include <sys/event.h>
48 #include <sys/mount.h>
49 #include <sys/vnode.h>
50 #include <sys/file.h>
51 #include <sys/ucred.h>
52 #include <sys/unistd.h>
53 #include <sys/sysctl.h>
54 #include <sys/errno.h>
55 #include <sys/queue.h>
56 #include <sys/tree.h>
57 #include <sys/lockf.h>
58 #include <machine/atomic.h>
59 
60 #include "fuse_debug.h"
61 #include "fuse_mount.h"
62 #include "fuse_abi.h"
63 
64 #define VFSTOFUSE(mp) ((struct fuse_mount*)((mp)->mnt_data))
65 #define VTOI(vp) ((struct fuse_node*)((vp)->v_data))
66 
67 #define FUSE_MAXFILESIZE	0x7FFFFFFFFFFFFFFFLL
68 #define FUSE_BLKSIZE		PAGE_SIZE
69 #define FUSE_BLKMASK		(FUSE_BLKSIZE - 1)
70 #define FUSE_BLKMASK64		((off_t)(FUSE_BLKSIZE - 1))
71 
72 SYSCTL_DECL(_vfs_fuse);
73 
74 extern int fuse_debug;
75 extern struct vop_ops fuse_vnode_vops;
76 extern struct vop_ops fuse_spec_vops;
77 
78 struct fuse_node;
79 
80 RB_HEAD(fuse_node_tree, fuse_node);
81 
82 struct fuse_mount {
83 	struct mount *mp;
84 	struct vnode *devvp;
85 	struct ucred *cred;
86 	struct kqinfo kq;
87 	struct fuse_node *rfnp;
88 	struct mtx mnt_lock;
89 	struct mtx ipc_lock;
90 	struct mtx ino_lock;
91 	struct thread *helper_td;		// helper thread
92 	struct spinlock helper_spin;		// protect bioq
93 	TAILQ_HEAD(, bio) bioq;			// bioq for strategy I/Os
94 	TAILQ_HEAD(,fuse_ipc) request_head;
95 	TAILQ_HEAD(,fuse_ipc) reply_head;
96 	struct fuse_node_tree node_head;	// inode index
97 
98 	unsigned int refcnt;
99 	unsigned long unique;
100 	int dead;
101 	uint64_t nosys;
102 	uint32_t abi_major;
103 	uint32_t abi_minor;
104 	uint32_t max_write;
105 };
106 
107 struct fuse_node {
108 	RB_ENTRY(fuse_node) node_entry;		// inode index entry
109 	struct vnode *vp;
110 	struct vattr attr;
111 	struct fuse_mount *fmp;
112 	struct fuse_node *pfnp;
113 	struct mtx node_lock;
114 	struct lockf	advlock;
115 
116 	uint64_t ino;
117 	enum vtype type;
118 	size_t size;
119 	uint64_t nlookup;
120 	uint64_t fh;
121 	bool closed; /* XXX associated with closed fh */
122 	int modified : 1;	/* file modified */
123 	int changed : 1;	/* file inode changed */
124 	int accessed : 1;	/* file accessed */
125 	int attrgood : 1;	/* have valid attributes */
126 	int sizeoverride : 1;	/* override attr size with fnp->size */
127 };
128 
129 struct fuse_buf {
130 	void *buf;
131 	size_t len;
132 };
133 
134 struct fuse_ipc {
135 	struct fuse_mount *fmp;
136 	struct fuse_buf request;
137 	struct fuse_buf reply;
138 	TAILQ_ENTRY(fuse_ipc) request_entry;
139 	TAILQ_ENTRY(fuse_ipc) reply_entry;
140 
141 	unsigned int refcnt;
142 	uint64_t unique;
143 	int sent;
144 	int done;
145 };
146 
147 int fuse_cmp_version(struct fuse_mount*, uint32_t, uint32_t);
148 int fuse_mount_kill(struct fuse_mount*);
149 int fuse_mount_free(struct fuse_mount*);
150 
151 int fuse_device_init(void);
152 void fuse_device_cleanup(void);
153 
154 void fuse_node_new(struct fuse_mount*, uint64_t, enum vtype,
155     struct fuse_node**);
156 void fuse_node_free(struct fuse_mount *, struct fuse_node *);
157 int fuse_alloc_node(struct fuse_mount *, struct fuse_node *,
158     uint64_t, enum vtype, struct vnode **);
159 int fuse_node_vn(struct fuse_node*, struct vnode**);
160 int fuse_node_truncate(struct fuse_node*, size_t, size_t);
161 void fuse_node_init(void);
162 void fuse_node_cleanup(void);
163 
164 void fuse_buf_alloc(struct fuse_buf*, size_t);
165 void fuse_buf_free(struct fuse_buf*);
166 struct fuse_ipc *fuse_ipc_get(struct fuse_mount*, size_t);
167 void fuse_ipc_put(struct fuse_ipc*);
168 void *fuse_ipc_fill(struct fuse_ipc*, int, uint64_t, struct ucred*);
169 int fuse_ipc_tx(struct fuse_ipc*);
170 int fuse_ipc_tx_noreply(struct fuse_ipc*);
171 void fuse_ipc_init(void);
172 void fuse_ipc_cleanup(void);
173 
174 int fuse_read(struct vop_read_args*);
175 int fuse_write(struct vop_write_args*);
176 int fuse_dio_write(struct vop_write_args*);
177 
178 void fuse_hexdump(const char*, size_t);
179 void fuse_fill_in_header(struct fuse_in_header*, uint32_t, uint32_t, uint64_t,
180     uint64_t, uint32_t, uint32_t, uint32_t);
181 int fuse_forget_node(struct fuse_mount*, uint64_t, uint64_t, struct ucred*);
182 int fuse_audit_length(struct fuse_in_header*, struct fuse_out_header*);
183     const char *fuse_get_ops(int);
184 void fuse_io_thread(void *arg);
185 
186 static __inline int
187 fuse_test_dead(struct fuse_mount *fmp)
188 {
189 	return atomic_load_acq_int(&fmp->dead);
190 }
191 
192 static __inline void
193 fuse_set_dead(struct fuse_mount *fmp)
194 {
195 	atomic_store_rel_int(&fmp->dead, 1);
196 }
197 
198 static __inline int
199 fuse_test_nosys(struct fuse_mount *fmp, int op)
200 {
201 	return atomic_load_acq_64(&fmp->nosys) & (1 << op);
202 }
203 
204 static __inline void
205 fuse_set_nosys(struct fuse_mount *fmp, int op)
206 {
207 	atomic_set_64(&fmp->nosys, 1 << op);
208 }
209 
210 static __inline int
211 fuse_ipc_test_replied(struct fuse_ipc *fip)
212 {
213 	return atomic_load_acq_int(&fip->done);
214 }
215 
216 static __inline void
217 fuse_ipc_set_replied(struct fuse_ipc *fip)
218 {
219 	atomic_store_rel_int(&fip->done, 1);
220 }
221 
222 static __inline int
223 fuse_ipc_test_and_set_replied(struct fuse_ipc *fip)
224 {
225 	return atomic_cmpset_int(&fip->done, 0, 1);
226 }
227 
228 static __inline void*
229 fuse_in(struct fuse_ipc *fip)
230 {
231 	return fip->request.buf;
232 }
233 
234 static __inline size_t
235 fuse_in_size(struct fuse_ipc *fip)
236 {
237 	return fip->request.len;
238 }
239 
240 static __inline void*
241 fuse_in_data(struct fuse_ipc *fip)
242 {
243 	return (struct fuse_in_header*)fuse_in(fip) + 1;
244 }
245 
246 static __inline size_t
247 fuse_in_data_size(struct fuse_ipc *fip)
248 {
249 	return fuse_in_size(fip) - sizeof(struct fuse_in_header);
250 }
251 
252 static __inline void*
253 fuse_out(struct fuse_ipc *fip)
254 {
255 	return fip->reply.buf;
256 }
257 
258 static __inline size_t
259 fuse_out_size(struct fuse_ipc *fip)
260 {
261 	return fip->reply.len;
262 }
263 
264 static __inline void*
265 fuse_out_data(struct fuse_ipc *fip)
266 {
267 	return (struct fuse_out_header*)fuse_out(fip) + 1;
268 }
269 
270 static __inline size_t
271 fuse_out_data_size(struct fuse_ipc *fip)
272 {
273 	return fuse_out_size(fip) - sizeof(struct fuse_out_header);
274 }
275 
276 static __inline void
277 fuse_knote(struct vnode *vp, int flags)
278 {
279 	if (flags)
280 		KNOTE(&vp->v_pollinfo.vpi_kqinfo.ki_note, flags);
281 }
282 
283 #endif /* FUSE_FUSE_H */
284