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
64struct fuse_iov {
65    void   *base;
66    size_t  len;
67    size_t  allocated_size;
68    int     credit;
69};
70
71void fiov_init(struct fuse_iov *fiov, size_t size);
72void fiov_teardown(struct fuse_iov *fiov);
73void fiov_refresh(struct fuse_iov *fiov);
74void fiov_adjust(struct fuse_iov *fiov, size_t size);
75
76#define FUSE_DIMALLOC(fiov, spc1, spc2, amnt)          \
77do {                                                   \
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
94struct fuse_ticket;
95struct fuse_data;
96
97typedef int fuse_handler_t(struct fuse_ticket *ftick, struct uio *uio);
98
99struct 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
129static __inline__
130struct fuse_iov *
131fticket_resp(struct fuse_ticket *ftick)
132{
133    return (&ftick->tk_aw_fiov);
134}
135
136static __inline__
137int
138fticket_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
145static __inline__
146void
147fticket_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
154static __inline__
155enum fuse_opcode
156fticket_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
162int fticket_pull(struct fuse_ticket *ftick, struct uio *uio);
163
164enum mountpri { FM_NOMOUNTED, FM_PRIMARY, FM_SECONDARY };
165
166/*
167 * The data representing a FUSE session.
168 */
169struct 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
215extern int fuse_data_cache_enable;
216extern int fuse_data_cache_invalidate;
217extern int fuse_mmap_enable;
218extern int fuse_sync_resize;
219extern int fuse_fix_broken_io;
220
221static __inline__
222struct fuse_data *
223fuse_get_mpdata(struct mount *mp)
224{
225    return mp->mnt_data;
226}
227
228static __inline int
229fsess_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}
236static __inline void
237fsess_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
244static __inline int
245fsess_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
253static __inline int
254fsess_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
263static __inline int
264fsess_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
271static __inline__
272void
273fuse_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
282static __inline__
283struct fuse_ticket *
284fuse_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
302static __inline__
303void
304fuse_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
313static __inline__
314void
315fuse_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
327static __inline__
328struct fuse_ticket *
329fuse_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
344struct fuse_ticket *fuse_ticket_fetch(struct fuse_data *data);
345int fuse_ticket_drop(struct fuse_ticket *ftick);
346void fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t *handler);
347void fuse_insert_message(struct fuse_ticket *ftick);
348
349static __inline__
350int
351fuse_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
357struct fuse_data *fdata_alloc(struct cdev *dev, struct ucred *cred);
358void fdata_trydestroy(struct fuse_data *data);
359void fdata_set_dead(struct fuse_data *data);
360
361static __inline__
362int
363fdata_get_dead(struct fuse_data *data)
364{
365    return (data->dataflags & FSESS_DEAD);
366}
367
368struct 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
380static __inline__
381void
382fdisp_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
389static __inline__
390void
391fdisp_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
400void 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
404void 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
408void fdisp_make_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
409                   struct vnode *vp, struct thread *td, struct ucred *cred);
410
411int  fdisp_wait_answ(struct fuse_dispatcher *fdip);
412
413static __inline__
414int
415fdisp_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