summaryrefslogtreecommitdiffstats
path: root/sys/fs/fuse/fuse_ipc.h
blob: cd08969c61b7254ae5043fc66e9e7da0128d06e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
/*
 * Copyright (c) 2007-2009 Google Inc. and Amit Singh
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following disclaimer
 *   in the documentation and/or other materials provided with the
 *   distribution.
 * * Neither the name of Google Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * Copyright (C) 2005 Csaba Henk.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */

#ifndef _FUSE_IPC_H_
#define _FUSE_IPC_H_

#include <sys/param.h>
#include <sys/refcount.h>

struct fuse_iov {
    void   *base;
    size_t  len;
    size_t  allocated_size;
    int     credit;
};

void fiov_init(struct fuse_iov *fiov, size_t size);
void fiov_teardown(struct fuse_iov *fiov);
void fiov_refresh(struct fuse_iov *fiov);
void fiov_adjust(struct fuse_iov *fiov, size_t size);

#define FUSE_DIMALLOC(fiov, spc1, spc2, amnt)          \
do {                                                   \
    fiov_adjust(fiov, (sizeof(*(spc1)) + (amnt)));     \
    (spc1) = (fiov)->base;                             \
    (spc2) = (char *)(fiov)->base + (sizeof(*(spc1))); \
} while (0)

#define FU_AT_LEAST(siz) max((siz), 160)

#define FUSE_ASSERT_AW_DONE(ftick)                                      \
    KASSERT((ftick)->tk_aw_link.tqe_next == NULL &&                     \
        (ftick)->tk_aw_link.tqe_prev == NULL,                           \
        ("FUSE: ticket still on answer delivery list %p", (ftick)))     \

#define FUSE_ASSERT_MS_DONE(ftick)                                      \
    KASSERT((ftick)->tk_ms_link.stqe_next == NULL,                      \
        ("FUSE: ticket still on message list %p", (ftick)))

struct fuse_ticket;
struct fuse_data;

typedef int fuse_handler_t(struct fuse_ticket *ftick, struct uio *uio);

struct fuse_ticket {
    /* fields giving the identity of the ticket */
    uint64_t                     tk_unique;
    struct fuse_data            *tk_data;
    int                          tk_flag;
    u_int                        tk_refcount;

    /* fields for initiating an upgoing message */
    struct fuse_iov              tk_ms_fiov;
    void                        *tk_ms_bufdata;
    size_t                       tk_ms_bufsize;
    enum { FT_M_FIOV, FT_M_BUF } tk_ms_type;
    STAILQ_ENTRY(fuse_ticket)    tk_ms_link;

    /* fields for handling answers coming from userspace */
    struct fuse_iov              tk_aw_fiov;
    void                        *tk_aw_bufdata;
    size_t                       tk_aw_bufsize;
    enum { FT_A_FIOV, FT_A_BUF } tk_aw_type;

    struct fuse_out_header       tk_aw_ohead;
    int                          tk_aw_errno;
    struct mtx                   tk_aw_mtx;
    fuse_handler_t              *tk_aw_handler;
    TAILQ_ENTRY(fuse_ticket)     tk_aw_link;
};

#define FT_ANSW  0x01  /* request of ticket has already been answered */
#define FT_DIRTY 0x04  /* ticket has been used */

static __inline__
struct fuse_iov *
fticket_resp(struct fuse_ticket *ftick)
{
    return (&ftick->tk_aw_fiov);
}

static __inline__
int
fticket_answered(struct fuse_ticket *ftick)
{
    DEBUGX(FUSE_DEBUG_IPC, "-> ftick=%p\n", ftick);
    mtx_assert(&ftick->tk_aw_mtx, MA_OWNED);
    return (ftick->tk_flag & FT_ANSW);
}

static __inline__
void
fticket_set_answered(struct fuse_ticket *ftick)
{
    DEBUGX(FUSE_DEBUG_IPC, "-> ftick=%p\n", ftick);
    mtx_assert(&ftick->tk_aw_mtx, MA_OWNED);
    ftick->tk_flag |= FT_ANSW;
}

static __inline__
enum fuse_opcode
fticket_opcode(struct fuse_ticket *ftick)
{
    DEBUGX(FUSE_DEBUG_IPC, "-> ftick=%p\n", ftick);
    return (((struct fuse_in_header *)(ftick->tk_ms_fiov.base))->opcode);
}

int fticket_pull(struct fuse_ticket *ftick, struct uio *uio);

enum mountpri { FM_NOMOUNTED, FM_PRIMARY, FM_SECONDARY };

/*
 * The data representing a FUSE session.
 */
struct fuse_data {
    struct cdev               *fdev;
    struct mount              *mp;
    struct vnode              *vroot;
    struct ucred              *daemoncred;
    int                        dataflags;
    int                        ref; 

    struct mtx                 ms_mtx;
    STAILQ_HEAD(, fuse_ticket) ms_head;

    struct mtx                 aw_mtx;
    TAILQ_HEAD(, fuse_ticket)  aw_head;

    u_long                     ticketer;

    struct sx                  rename_lock;

    uint32_t                   fuse_libabi_major;
    uint32_t                   fuse_libabi_minor;

    uint32_t                   max_write;
    uint32_t                   max_read;
    uint32_t                   subtype;
    char                       volname[MAXPATHLEN];

    struct selinfo ks_rsel;

    int                        daemon_timeout;
    uint64_t                   notimpl;
};

#define FSESS_DEAD                0x0001 /* session is to be closed */
#define FSESS_UNUSED0             0x0002 /* unused */
#define FSESS_INITED              0x0004 /* session has been inited */
#define FSESS_DAEMON_CAN_SPY      0x0010 /* let non-owners access this fs */
                                         /* (and being observed by the daemon) */
#define FSESS_PUSH_SYMLINKS_IN    0x0020 /* prefix absolute symlinks with mp */
#define FSESS_DEFAULT_PERMISSIONS 0x0040 /* kernel does permission checking */
#define FSESS_NO_ATTRCACHE        0x0080 /* no attribute caching */
#define FSESS_NO_READAHEAD        0x0100 /* no readaheads */
#define FSESS_NO_DATACACHE        0x0200 /* disable buffer cache */
#define FSESS_NO_NAMECACHE        0x0400 /* disable name cache */
#define FSESS_NO_MMAP             0x0800 /* disable mmap */
#define FSESS_BROKENIO            0x1000 /* fix broken io */

extern int fuse_data_cache_enable;
extern int fuse_data_cache_invalidate;
extern int fuse_mmap_enable;
extern int fuse_sync_resize;
extern int fuse_fix_broken_io;

static __inline__
struct fuse_data *
fuse_get_mpdata(struct mount *mp)
{
    return mp->mnt_data;
}

static __inline int
fsess_isimpl(struct mount *mp, int opcode)
{
    struct fuse_data *data = fuse_get_mpdata(mp);

    return (data->notimpl & (1ULL << opcode)) == 0;

}
static __inline void
fsess_set_notimpl(struct mount *mp, int opcode)
{
    struct fuse_data *data = fuse_get_mpdata(mp);

    data->notimpl |= (1ULL << opcode);
}

static __inline int
fsess_opt_datacache(struct mount *mp)
{
    struct fuse_data *data = fuse_get_mpdata(mp);

    return (fuse_data_cache_enable ||
        (data->dataflags & FSESS_NO_DATACACHE) == 0);
}

static __inline int
fsess_opt_mmap(struct mount *mp)
{
    struct fuse_data *data = fuse_get_mpdata(mp);

    if (!(fuse_mmap_enable && fuse_data_cache_enable))
        return 0;
    return ((data->dataflags & (FSESS_NO_DATACACHE | FSESS_NO_MMAP)) == 0);
}

static __inline int
fsess_opt_brokenio(struct mount *mp)
{
    struct fuse_data *data = fuse_get_mpdata(mp);

    return (fuse_fix_broken_io || (data->dataflags & FSESS_BROKENIO));
}

static __inline__
void
fuse_ms_push(struct fuse_ticket *ftick)
{
    DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n",
        ftick, ftick->tk_refcount + 1);
    mtx_assert(&ftick->tk_data->ms_mtx, MA_OWNED);
    refcount_acquire(&ftick->tk_refcount);
    STAILQ_INSERT_TAIL(&ftick->tk_data->ms_head, ftick, tk_ms_link);
}

static __inline__
struct fuse_ticket *
fuse_ms_pop(struct fuse_data *data)
{
    struct fuse_ticket *ftick = NULL;

    mtx_assert(&data->ms_mtx, MA_OWNED);

    if ((ftick = STAILQ_FIRST(&data->ms_head))) {
        STAILQ_REMOVE_HEAD(&data->ms_head, tk_ms_link);
#ifdef INVARIANTS
        ftick->tk_ms_link.stqe_next = NULL;
#endif
    }
    DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n",
        ftick, ftick ? ftick->tk_refcount : -1);

    return ftick;
}

static __inline__
void
fuse_aw_push(struct fuse_ticket *ftick)
{
    DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n",
        ftick, ftick->tk_refcount + 1);
    mtx_assert(&ftick->tk_data->aw_mtx, MA_OWNED);
    refcount_acquire(&ftick->tk_refcount);
    TAILQ_INSERT_TAIL(&ftick->tk_data->aw_head, ftick, tk_aw_link);
}

static __inline__
void
fuse_aw_remove(struct fuse_ticket *ftick)
{
    DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n",
        ftick, ftick->tk_refcount);
    mtx_assert(&ftick->tk_data->aw_mtx, MA_OWNED);
    TAILQ_REMOVE(&ftick->tk_data->aw_head, ftick, tk_aw_link);
#ifdef INVARIANTS
    ftick->tk_aw_link.tqe_next = NULL;
    ftick->tk_aw_link.tqe_prev = NULL;
#endif
}

static __inline__
struct fuse_ticket *
fuse_aw_pop(struct fuse_data *data)
{
    struct fuse_ticket *ftick = NULL;

    mtx_assert(&data->aw_mtx, MA_OWNED);

    if ((ftick = TAILQ_FIRST(&data->aw_head))) {
        fuse_aw_remove(ftick);
    }
    DEBUGX(FUSE_DEBUG_IPC, "ftick=%p refcount=%d\n",
        ftick, ftick ? ftick->tk_refcount : -1);

    return ftick;
}

struct fuse_ticket *fuse_ticket_fetch(struct fuse_data *data);
int fuse_ticket_drop(struct fuse_ticket *ftick);
void fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t *handler);
void fuse_insert_message(struct fuse_ticket *ftick);

static __inline__
int
fuse_libabi_geq(struct fuse_data *data, uint32_t abi_maj, uint32_t abi_min)
{
    return (data->fuse_libabi_major > abi_maj ||
            (data->fuse_libabi_major == abi_maj && data->fuse_libabi_minor >= abi_min));
}

struct fuse_data *fdata_alloc(struct cdev *dev, struct ucred *cred);
void fdata_trydestroy(struct fuse_data *data);
void fdata_set_dead(struct fuse_data *data);

static __inline__
int
fdata_get_dead(struct fuse_data *data)
{
    return (data->dataflags & FSESS_DEAD);
}

struct fuse_dispatcher {

    struct fuse_ticket    *tick;
    struct fuse_in_header *finh;

    void    *indata;
    size_t   iosize;
    uint64_t nodeid;
    int      answ_stat;
    void    *answ;
};

static __inline__
void
fdisp_init(struct fuse_dispatcher *fdisp, size_t iosize)
{
    DEBUGX(FUSE_DEBUG_IPC, "-> fdisp=%p, iosize=%zx\n", fdisp, iosize);
    fdisp->iosize = iosize;
    fdisp->tick = NULL;
}

static __inline__
void
fdisp_destroy(struct fuse_dispatcher *fdisp)
{
    DEBUGX(FUSE_DEBUG_IPC, "-> fdisp=%p, ftick=%p\n", fdisp, fdisp->tick);
    fuse_ticket_drop(fdisp->tick);
#ifdef INVARIANTS
    fdisp->tick = NULL;
#endif
}

void fdisp_make(struct fuse_dispatcher *fdip, enum fuse_opcode op,
                struct mount *mp, uint64_t nid, struct thread *td,
                struct ucred *cred);

void fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op,
                    struct mount *mp, uint64_t nid, pid_t pid,
                    struct ucred *cred);

void fdisp_make_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
                   struct vnode *vp, struct thread *td, struct ucred *cred);

int  fdisp_wait_answ(struct fuse_dispatcher *fdip);

static __inline__
int
fdisp_simple_putget_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
                    struct vnode *vp, struct thread *td, struct ucred *cred)
{
    DEBUGX(FUSE_DEBUG_IPC, "-> fdip=%p, opcode=%d, vp=%p\n", fdip, op, vp);
    fdisp_make_vp(fdip, op, vp, td, cred);
    return fdisp_wait_answ(fdip);
}

#endif /* _FUSE_IPC_H_ */
OpenPOWER on IntegriCloud