xref: /freebsd/sys/fs/fuse/fuse_ipc.h (revision 193d9e768ba63fcfb187cfd17f461f7d41345048)
1 /*
2  * Copyright (c) 2007-2009 Google Inc. and Amit Singh
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above
12  *   copyright notice, this list of conditions and the following disclaimer
13  *   in the documentation and/or other materials provided with the
14  *   distribution.
15  * * Neither the name of Google Inc. nor the names of its
16  *   contributors may be used to endorse or promote products derived from
17  *   this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Copyright (C) 2005 Csaba Henk.
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  * 1. Redistributions of source code must retain the above copyright
38  *    notice, this list of conditions and the following disclaimer.
39  * 2. Redistributions in binary form must reproduce the above copyright
40  *    notice, this list of conditions and the following disclaimer in the
41  *    documentation and/or other materials provided with the distribution.
42  *
43  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
44  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
47  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53  * SUCH DAMAGE.
54  *
55  * $FreeBSD$
56  */
57 
58 #ifndef _FUSE_IPC_H_
59 #define _FUSE_IPC_H_
60 
61 #include <sys/param.h>
62 #include <sys/refcount.h>
63 
64 struct fuse_iov {
65     void   *base;
66     size_t  len;
67     size_t  allocated_size;
68     int     credit;
69 };
70 
71 void fiov_init(struct fuse_iov *fiov, size_t size);
72 void fiov_teardown(struct fuse_iov *fiov);
73 void fiov_refresh(struct fuse_iov *fiov);
74 void fiov_adjust(struct fuse_iov *fiov, size_t size);
75 
76 #define FUSE_DIMALLOC(fiov, spc1, spc2, amnt)          \
77 do {                                                   \
78     fiov_adjust(fiov, (sizeof(*(spc1)) + (amnt)));     \
79     (spc1) = (fiov)->base;                             \
80     (spc2) = (char *)(fiov)->base + (sizeof(*(spc1))); \
81 } while (0)
82 
83 #define FU_AT_LEAST(siz) max((siz), 160)
84 
85 #define FUSE_ASSERT_AW_DONE(ftick)                                      \
86     KASSERT((ftick)->tk_aw_link.tqe_next == NULL &&                     \
87         (ftick)->tk_aw_link.tqe_prev == NULL,                           \
88         ("FUSE: ticket still on answer delivery list %p", (ftick)))     \
89 
90 #define FUSE_ASSERT_MS_DONE(ftick)                                      \
91     KASSERT((ftick)->tk_ms_link.stqe_next == NULL,                      \
92         ("FUSE: ticket still on message list %p", (ftick)))
93 
94 struct fuse_ticket;
95 struct fuse_data;
96 
97 typedef int fuse_handler_t(struct fuse_ticket *ftick, struct uio *uio);
98 
99 struct fuse_ticket {
100     /* fields giving the identity of the ticket */
101     uint64_t                     tk_unique;
102     struct fuse_data            *tk_data;
103     int                          tk_flag;
104     u_int                        tk_refcount;
105 
106     /* fields for initiating an upgoing message */
107     struct fuse_iov              tk_ms_fiov;
108     void                        *tk_ms_bufdata;
109     size_t                       tk_ms_bufsize;
110     enum { FT_M_FIOV, FT_M_BUF } tk_ms_type;
111     STAILQ_ENTRY(fuse_ticket)    tk_ms_link;
112 
113     /* fields for handling answers coming from userspace */
114     struct fuse_iov              tk_aw_fiov;
115     void                        *tk_aw_bufdata;
116     size_t                       tk_aw_bufsize;
117     enum { FT_A_FIOV, FT_A_BUF } tk_aw_type;
118 
119     struct fuse_out_header       tk_aw_ohead;
120     int                          tk_aw_errno;
121     struct mtx                   tk_aw_mtx;
122     fuse_handler_t              *tk_aw_handler;
123     TAILQ_ENTRY(fuse_ticket)     tk_aw_link;
124 };
125 
126 #define FT_ANSW  0x01  /* request of ticket has already been answered */
127 #define FT_DIRTY 0x04  /* ticket has been used */
128 
129 static __inline__
130 struct fuse_iov *
131 fticket_resp(struct fuse_ticket *ftick)
132 {
133     return (&ftick->tk_aw_fiov);
134 }
135 
136 static __inline__
137 int
138 fticket_answered(struct fuse_ticket *ftick)
139 {
140     DEBUGX(FUSE_DEBUG_IPC, "-> ftick=%p\n", ftick);
141     mtx_assert(&ftick->tk_aw_mtx, MA_OWNED);
142     return (ftick->tk_flag & FT_ANSW);
143 }
144 
145 static __inline__
146 void
147 fticket_set_answered(struct fuse_ticket *ftick)
148 {
149     DEBUGX(FUSE_DEBUG_IPC, "-> ftick=%p\n", ftick);
150     mtx_assert(&ftick->tk_aw_mtx, MA_OWNED);
151     ftick->tk_flag |= FT_ANSW;
152 }
153 
154 static __inline__
155 enum fuse_opcode
156 fticket_opcode(struct fuse_ticket *ftick)
157 {
158     DEBUGX(FUSE_DEBUG_IPC, "-> ftick=%p\n", ftick);
159     return (((struct fuse_in_header *)(ftick->tk_ms_fiov.base))->opcode);
160 }
161 
162 int fticket_pull(struct fuse_ticket *ftick, struct uio *uio);
163 
164 enum mountpri { FM_NOMOUNTED, FM_PRIMARY, FM_SECONDARY };
165 
166 /*
167  * The data representing a FUSE session.
168  */
169 struct fuse_data {
170     struct cdev               *fdev;
171     struct mount              *mp;
172     struct vnode              *vroot;
173     struct ucred              *daemoncred;
174     int                        dataflags;
175     int                        ref;
176 
177     struct mtx                 ms_mtx;
178     STAILQ_HEAD(, fuse_ticket) ms_head;
179 
180     struct mtx                 aw_mtx;
181     TAILQ_HEAD(, fuse_ticket)  aw_head;
182 
183     u_long                     ticketer;
184 
185     struct sx                  rename_lock;
186 
187     uint32_t                   fuse_libabi_major;
188     uint32_t                   fuse_libabi_minor;
189 
190     uint32_t                   max_write;
191     uint32_t                   max_read;
192     uint32_t                   subtype;
193     char                       volname[MAXPATHLEN];
194 
195     struct selinfo ks_rsel;
196 
197     int                        daemon_timeout;
198     uint64_t                   notimpl;
199 };
200 
201 #define FSESS_DEAD                0x0001 /* session is to be closed */
202 #define FSESS_UNUSED0             0x0002 /* unused */
203 #define FSESS_INITED              0x0004 /* session has been inited */
204 #define FSESS_DAEMON_CAN_SPY      0x0010 /* let non-owners access this fs */
205                                          /* (and being observed by the daemon) */
206 #define FSESS_PUSH_SYMLINKS_IN    0x0020 /* prefix absolute symlinks with mp */
207 #define FSESS_DEFAULT_PERMISSIONS 0x0040 /* kernel does permission checking */
208 #define FSESS_NO_ATTRCACHE        0x0080 /* no attribute caching */
209 #define FSESS_NO_READAHEAD        0x0100 /* no readaheads */
210 #define FSESS_NO_DATACACHE        0x0200 /* disable buffer cache */
211 #define FSESS_NO_NAMECACHE        0x0400 /* disable name cache */
212 #define FSESS_NO_MMAP             0x0800 /* disable mmap */
213 #define FSESS_BROKENIO            0x1000 /* fix broken io */
214 
215 extern int fuse_data_cache_enable;
216 extern int fuse_data_cache_invalidate;
217 extern int fuse_mmap_enable;
218 extern int fuse_sync_resize;
219 extern int fuse_fix_broken_io;
220 
221 static __inline__
222 struct fuse_data *
223 fuse_get_mpdata(struct mount *mp)
224 {
225     return mp->mnt_data;
226 }
227 
228 static __inline int
229 fsess_isimpl(struct mount *mp, int opcode)
230 {
231     struct fuse_data *data = fuse_get_mpdata(mp);
232 
233     return (data->notimpl & (1ULL << opcode)) == 0;
234 
235 }
236 static __inline void
237 fsess_set_notimpl(struct mount *mp, int opcode)
238 {
239     struct fuse_data *data = fuse_get_mpdata(mp);
240 
241     data->notimpl |= (1ULL << opcode);
242 }
243 
244 static __inline int
245 fsess_opt_datacache(struct mount *mp)
246 {
247     struct fuse_data *data = fuse_get_mpdata(mp);
248 
249     return (fuse_data_cache_enable ||
250         (data->dataflags & FSESS_NO_DATACACHE) == 0);
251 }
252 
253 static __inline int
254 fsess_opt_mmap(struct mount *mp)
255 {
256     struct fuse_data *data = fuse_get_mpdata(mp);
257 
258     if (!(fuse_mmap_enable && fuse_data_cache_enable))
259         return 0;
260     return ((data->dataflags & (FSESS_NO_DATACACHE | FSESS_NO_MMAP)) == 0);
261 }
262 
263 static __inline int
264 fsess_opt_brokenio(struct mount *mp)
265 {
266     struct fuse_data *data = fuse_get_mpdata(mp);
267 
268     return (fuse_fix_broken_io || (data->dataflags & FSESS_BROKENIO));
269 }
270 
271 static __inline__
272 void
273 fuse_ms_push(struct fuse_ticket *ftick)
274 {
275     DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n",
276         ftick, ftick->tk_refcount + 1);
277     mtx_assert(&ftick->tk_data->ms_mtx, MA_OWNED);
278     refcount_acquire(&ftick->tk_refcount);
279     STAILQ_INSERT_TAIL(&ftick->tk_data->ms_head, ftick, tk_ms_link);
280 }
281 
282 static __inline__
283 struct fuse_ticket *
284 fuse_ms_pop(struct fuse_data *data)
285 {
286     struct fuse_ticket *ftick = NULL;
287 
288     mtx_assert(&data->ms_mtx, MA_OWNED);
289 
290     if ((ftick = STAILQ_FIRST(&data->ms_head))) {
291         STAILQ_REMOVE_HEAD(&data->ms_head, tk_ms_link);
292 #ifdef INVARIANTS
293         ftick->tk_ms_link.stqe_next = NULL;
294 #endif
295     }
296     DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n",
297         ftick, ftick ? ftick->tk_refcount : -1);
298 
299     return ftick;
300 }
301 
302 static __inline__
303 void
304 fuse_aw_push(struct fuse_ticket *ftick)
305 {
306     DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n",
307         ftick, ftick->tk_refcount + 1);
308     mtx_assert(&ftick->tk_data->aw_mtx, MA_OWNED);
309     refcount_acquire(&ftick->tk_refcount);
310     TAILQ_INSERT_TAIL(&ftick->tk_data->aw_head, ftick, tk_aw_link);
311 }
312 
313 static __inline__
314 void
315 fuse_aw_remove(struct fuse_ticket *ftick)
316 {
317     DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n",
318         ftick, ftick->tk_refcount);
319     mtx_assert(&ftick->tk_data->aw_mtx, MA_OWNED);
320     TAILQ_REMOVE(&ftick->tk_data->aw_head, ftick, tk_aw_link);
321 #ifdef INVARIANTS
322     ftick->tk_aw_link.tqe_next = NULL;
323     ftick->tk_aw_link.tqe_prev = NULL;
324 #endif
325 }
326 
327 static __inline__
328 struct fuse_ticket *
329 fuse_aw_pop(struct fuse_data *data)
330 {
331     struct fuse_ticket *ftick = NULL;
332 
333     mtx_assert(&data->aw_mtx, MA_OWNED);
334 
335     if ((ftick = TAILQ_FIRST(&data->aw_head))) {
336         fuse_aw_remove(ftick);
337     }
338     DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n",
339         ftick, ftick ? ftick->tk_refcount : -1);
340 
341     return ftick;
342 }
343 
344 struct fuse_ticket *fuse_ticket_fetch(struct fuse_data *data);
345 int fuse_ticket_drop(struct fuse_ticket *ftick);
346 void fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t *handler);
347 void fuse_insert_message(struct fuse_ticket *ftick);
348 
349 static __inline__
350 int
351 fuse_libabi_geq(struct fuse_data *data, uint32_t abi_maj, uint32_t abi_min)
352 {
353     return (data->fuse_libabi_major > abi_maj ||
354             (data->fuse_libabi_major == abi_maj && data->fuse_libabi_minor >= abi_min));
355 }
356 
357 struct fuse_data *fdata_alloc(struct cdev *dev, struct ucred *cred);
358 void fdata_trydestroy(struct fuse_data *data);
359 void fdata_set_dead(struct fuse_data *data);
360 
361 static __inline__
362 int
363 fdata_get_dead(struct fuse_data *data)
364 {
365     return (data->dataflags & FSESS_DEAD);
366 }
367 
368 struct fuse_dispatcher {
369 
370     struct fuse_ticket    *tick;
371     struct fuse_in_header *finh;
372 
373     void    *indata;
374     size_t   iosize;
375     uint64_t nodeid;
376     int      answ_stat;
377     void    *answ;
378 };
379 
380 static __inline__
381 void
382 fdisp_init(struct fuse_dispatcher *fdisp, size_t iosize)
383 {
384     DEBUGX(FUSE_DEBUG_IPC, "-> fdisp=%p, iosize=%zx\n", fdisp, iosize);
385     fdisp->iosize = iosize;
386     fdisp->tick = NULL;
387 }
388 
389 static __inline__
390 void
391 fdisp_destroy(struct fuse_dispatcher *fdisp)
392 {
393     DEBUGX(FUSE_DEBUG_IPC, "-> fdisp=%p, ftick=%p\n", fdisp, fdisp->tick);
394     fuse_ticket_drop(fdisp->tick);
395 #ifdef INVARIANTS
396     fdisp->tick = NULL;
397 #endif
398 }
399 
400 void fdisp_make(struct fuse_dispatcher *fdip, enum fuse_opcode op,
401                 struct mount *mp, uint64_t nid, struct thread *td,
402                 struct ucred *cred);
403 
404 void fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op,
405                     struct mount *mp, uint64_t nid, pid_t pid,
406                     struct ucred *cred);
407 
408 void fdisp_make_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
409                    struct vnode *vp, struct thread *td, struct ucred *cred);
410 
411 int  fdisp_wait_answ(struct fuse_dispatcher *fdip);
412 
413 static __inline__
414 int
415 fdisp_simple_putget_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
416                     struct vnode *vp, struct thread *td, struct ucred *cred)
417 {
418     DEBUGX(FUSE_DEBUG_IPC, "-> fdip=%p, opcode=%d, vp=%p\n", fdip, op, vp);
419     fdisp_make_vp(fdip, op, vp, td, cred);
420     return fdisp_wait_answ(fdip);
421 }
422 
423 #endif /* _FUSE_IPC_H_ */
424