Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/fuse/fuse_ipc.h
Show All 26 Lines | |||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
* | * | ||||
* Copyright (C) 2005 Csaba Henk. | * Copyright (C) 2005 Csaba Henk. | ||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Copyright (c) 2019 The FreeBSD Foundation | |||||
* | |||||
* Portions of this software were developed by BFF Storage Systems, LLC under | |||||
* sponsorship from the FreeBSD Foundation. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
* notice, this list of conditions and the following disclaimer in the | * notice, this list of conditions and the following disclaimer in the | ||||
* documentation and/or other materials provided with the distribution. | * documentation and/or other materials provided with the distribution. | ||||
Show All 14 Lines | |||||
*/ | */ | ||||
#ifndef _FUSE_IPC_H_ | #ifndef _FUSE_IPC_H_ | ||||
#define _FUSE_IPC_H_ | #define _FUSE_IPC_H_ | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/refcount.h> | #include <sys/refcount.h> | ||||
enum fuse_data_cache_mode { | |||||
FUSE_CACHE_UC, | |||||
FUSE_CACHE_WT, | |||||
FUSE_CACHE_WB, | |||||
}; | |||||
struct fuse_iov { | struct fuse_iov { | ||||
void *base; | void *base; | ||||
size_t len; | size_t len; | ||||
size_t allocated_size; | size_t allocated_size; | ||||
int credit; | int credit; | ||||
}; | }; | ||||
void fiov_init(struct fuse_iov *fiov, size_t size); | void fiov_init(struct fuse_iov *fiov, size_t size); | ||||
Show All 24 Lines | |||||
typedef int fuse_handler_t(struct fuse_ticket *ftick, struct uio *uio); | typedef int fuse_handler_t(struct fuse_ticket *ftick, struct uio *uio); | ||||
struct fuse_ticket { | struct fuse_ticket { | ||||
/* fields giving the identity of the ticket */ | /* fields giving the identity of the ticket */ | ||||
uint64_t tk_unique; | uint64_t tk_unique; | ||||
struct fuse_data *tk_data; | struct fuse_data *tk_data; | ||||
int tk_flag; | int tk_flag; | ||||
u_int tk_refcount; | u_int tk_refcount; | ||||
/* | |||||
* If this ticket's operation has been interrupted, this will hold the | |||||
* unique value of the FUSE_INTERRUPT operation. Otherwise, it will be | |||||
* 0. | |||||
*/ | |||||
uint64_t irq_unique; | |||||
/* fields for initiating an upgoing message */ | /* fields for initiating an upgoing message */ | ||||
struct fuse_iov tk_ms_fiov; | struct fuse_iov tk_ms_fiov; | ||||
void *tk_ms_bufdata; | void *tk_ms_bufdata; | ||||
size_t tk_ms_bufsize; | size_t tk_ms_bufsize; | ||||
enum { FT_M_FIOV, FT_M_BUF } tk_ms_type; | enum { FT_M_FIOV, FT_M_BUF } tk_ms_type; | ||||
STAILQ_ENTRY(fuse_ticket) tk_ms_link; | STAILQ_ENTRY(fuse_ticket) tk_ms_link; | ||||
Show All 28 Lines | |||||
static inline void | static inline void | ||||
fticket_set_answered(struct fuse_ticket *ftick) | fticket_set_answered(struct fuse_ticket *ftick) | ||||
{ | { | ||||
mtx_assert(&ftick->tk_aw_mtx, MA_OWNED); | mtx_assert(&ftick->tk_aw_mtx, MA_OWNED); | ||||
ftick->tk_flag |= FT_ANSW; | ftick->tk_flag |= FT_ANSW; | ||||
} | } | ||||
static inline struct fuse_in_header* | |||||
fticket_in_header(struct fuse_ticket *ftick) | |||||
{ | |||||
return (struct fuse_in_header *)(ftick->tk_ms_fiov.base); | |||||
} | |||||
static inline enum fuse_opcode | static inline enum fuse_opcode | ||||
fticket_opcode(struct fuse_ticket *ftick) | fticket_opcode(struct fuse_ticket *ftick) | ||||
{ | { | ||||
return (((struct fuse_in_header *)(ftick->tk_ms_fiov.base))->opcode); | return fticket_in_header(ftick)->opcode; | ||||
} | } | ||||
int fticket_pull(struct fuse_ticket *ftick, struct uio *uio); | int fticket_pull(struct fuse_ticket *ftick, struct uio *uio); | ||||
enum mountpri { FM_NOMOUNTED, FM_PRIMARY, FM_SECONDARY }; | |||||
/* | /* | ||||
* The data representing a FUSE session. | * The data representing a FUSE session. | ||||
*/ | */ | ||||
struct fuse_data { | struct fuse_data { | ||||
struct cdev *fdev; | struct cdev *fdev; | ||||
struct mount *mp; | struct mount *mp; | ||||
struct vnode *vroot; | struct vnode *vroot; | ||||
struct ucred *daemoncred; | struct ucred *daemoncred; | ||||
int dataflags; | int dataflags; | ||||
int ref; | int ref; | ||||
struct mtx ms_mtx; | struct mtx ms_mtx; | ||||
STAILQ_HEAD(, fuse_ticket) ms_head; | STAILQ_HEAD(, fuse_ticket) ms_head; | ||||
int ms_count; | |||||
struct mtx aw_mtx; | struct mtx aw_mtx; | ||||
TAILQ_HEAD(, fuse_ticket) aw_head; | TAILQ_HEAD(, fuse_ticket) aw_head; | ||||
/* | |||||
* Holds the next value of the FUSE operation unique value. | |||||
* Also, serves as a wakeup channel to prevent any operations from | |||||
* being created before INIT completes. | |||||
*/ | |||||
u_long ticketer; | u_long ticketer; | ||||
struct sx rename_lock; | struct sx rename_lock; | ||||
uint32_t fuse_libabi_major; | uint32_t fuse_libabi_major; | ||||
uint32_t fuse_libabi_minor; | uint32_t fuse_libabi_minor; | ||||
uint32_t max_readahead_blocks; | |||||
uint32_t max_write; | uint32_t max_write; | ||||
uint32_t max_read; | uint32_t max_read; | ||||
uint32_t subtype; | uint32_t subtype; | ||||
char volname[MAXPATHLEN]; | char volname[MAXPATHLEN]; | ||||
struct selinfo ks_rsel; | struct selinfo ks_rsel; | ||||
int daemon_timeout; | int daemon_timeout; | ||||
unsigned time_gran; | |||||
uint64_t notimpl; | uint64_t notimpl; | ||||
uint64_t mnt_flag; | |||||
enum fuse_data_cache_mode cache_mode; | |||||
}; | }; | ||||
#define FSESS_DEAD 0x0001 /* session is to be closed */ | #define FSESS_DEAD 0x0001 /* session is to be closed */ | ||||
#define FSESS_UNUSED0 0x0002 /* unused */ | |||||
#define FSESS_INITED 0x0004 /* session has been inited */ | #define FSESS_INITED 0x0004 /* session has been inited */ | ||||
#define FSESS_DAEMON_CAN_SPY 0x0010 /* let non-owners access this fs */ | #define FSESS_DAEMON_CAN_SPY 0x0010 /* let non-owners access this fs */ | ||||
/* (and being observed by the daemon) */ | /* (and being observed by the daemon) */ | ||||
#define FSESS_PUSH_SYMLINKS_IN 0x0020 /* prefix absolute symlinks with mp */ | #define FSESS_PUSH_SYMLINKS_IN 0x0020 /* prefix absolute symlinks with mp */ | ||||
#define FSESS_DEFAULT_PERMISSIONS 0x0040 /* kernel does permission checking */ | #define FSESS_DEFAULT_PERMISSIONS 0x0040 /* kernel does permission checking */ | ||||
#define FSESS_NO_ATTRCACHE 0x0080 /* no attribute caching */ | #define FSESS_ASYNC_READ 0x1000 /* allow multiple reads of some file */ | ||||
#define FSESS_NO_READAHEAD 0x0100 /* no readaheads */ | #define FSESS_POSIX_LOCKS 0x2000 /* daemon supports POSIX locks */ | ||||
#define FSESS_NO_DATACACHE 0x0200 /* disable buffer cache */ | #define FSESS_EXPORT_SUPPORT 0x10000 /* daemon supports NFS-style lookups */ | ||||
#define FSESS_NO_NAMECACHE 0x0400 /* disable name cache */ | #define FSESS_INTR 0x20000 /* interruptible mounts */ | ||||
#define FSESS_NO_MMAP 0x0800 /* disable mmap */ | #define FSESS_MNTOPTS_MASK ( \ | ||||
#define FSESS_BROKENIO 0x1000 /* fix broken io */ | FSESS_DAEMON_CAN_SPY | FSESS_PUSH_SYMLINKS_IN | \ | ||||
FSESS_DEFAULT_PERMISSIONS | FSESS_INTR) | |||||
enum fuse_data_cache_mode { | |||||
FUSE_CACHE_UC, | |||||
FUSE_CACHE_WT, | |||||
FUSE_CACHE_WB, | |||||
}; | |||||
extern int fuse_data_cache_mode; | extern int fuse_data_cache_mode; | ||||
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 * | static inline struct fuse_data * | ||||
fuse_get_mpdata(struct mount *mp) | fuse_get_mpdata(struct mount *mp) | ||||
{ | { | ||||
return mp->mnt_data; | return mp->mnt_data; | ||||
} | } | ||||
static inline bool | static inline bool | ||||
Show All 12 Lines | fsess_set_notimpl(struct mount *mp, int opcode) | ||||
data->notimpl |= (1ULL << opcode); | data->notimpl |= (1ULL << opcode); | ||||
} | } | ||||
static inline bool | static inline bool | ||||
fsess_opt_datacache(struct mount *mp) | fsess_opt_datacache(struct mount *mp) | ||||
{ | { | ||||
struct fuse_data *data = fuse_get_mpdata(mp); | struct fuse_data *data = fuse_get_mpdata(mp); | ||||
return (fuse_data_cache_mode != FUSE_CACHE_UC && | return (data->cache_mode != FUSE_CACHE_UC); | ||||
(data->dataflags & FSESS_NO_DATACACHE) == 0); | |||||
} | } | ||||
static inline bool | static inline bool | ||||
fsess_opt_mmap(struct mount *mp) | fsess_opt_mmap(struct mount *mp) | ||||
{ | { | ||||
struct fuse_data *data = fuse_get_mpdata(mp); | return (fsess_opt_datacache(mp)); | ||||
if (!fuse_mmap_enable || fuse_data_cache_mode == FUSE_CACHE_UC) | |||||
return (false); | |||||
return ((data->dataflags & (FSESS_NO_DATACACHE | FSESS_NO_MMAP)) == 0); | |||||
} | } | ||||
static inline bool | static inline bool | ||||
fsess_opt_brokenio(struct mount *mp) | fsess_opt_writeback(struct mount *mp) | ||||
{ | { | ||||
struct fuse_data *data = fuse_get_mpdata(mp); | struct fuse_data *data = fuse_get_mpdata(mp); | ||||
return (fuse_fix_broken_io || (data->dataflags & FSESS_BROKENIO)); | return (data->cache_mode == FUSE_CACHE_WB); | ||||
} | } | ||||
/* Insert a new upgoing message */ | |||||
static inline void | static inline void | ||||
fuse_ms_push(struct fuse_ticket *ftick) | fuse_ms_push(struct fuse_ticket *ftick) | ||||
{ | { | ||||
mtx_assert(&ftick->tk_data->ms_mtx, MA_OWNED); | mtx_assert(&ftick->tk_data->ms_mtx, MA_OWNED); | ||||
refcount_acquire(&ftick->tk_refcount); | refcount_acquire(&ftick->tk_refcount); | ||||
STAILQ_INSERT_TAIL(&ftick->tk_data->ms_head, ftick, tk_ms_link); | STAILQ_INSERT_TAIL(&ftick->tk_data->ms_head, ftick, tk_ms_link); | ||||
ftick->tk_data->ms_count++; | |||||
} | } | ||||
/* Insert a new upgoing message to the front of the queue */ | |||||
static inline void | |||||
fuse_ms_push_head(struct fuse_ticket *ftick) | |||||
{ | |||||
mtx_assert(&ftick->tk_data->ms_mtx, MA_OWNED); | |||||
refcount_acquire(&ftick->tk_refcount); | |||||
STAILQ_INSERT_HEAD(&ftick->tk_data->ms_head, ftick, tk_ms_link); | |||||
ftick->tk_data->ms_count++; | |||||
} | |||||
static inline struct fuse_ticket * | static inline struct fuse_ticket * | ||||
fuse_ms_pop(struct fuse_data *data) | fuse_ms_pop(struct fuse_data *data) | ||||
{ | { | ||||
struct fuse_ticket *ftick = NULL; | struct fuse_ticket *ftick = NULL; | ||||
mtx_assert(&data->ms_mtx, MA_OWNED); | mtx_assert(&data->ms_mtx, MA_OWNED); | ||||
if ((ftick = STAILQ_FIRST(&data->ms_head))) { | if ((ftick = STAILQ_FIRST(&data->ms_head))) { | ||||
STAILQ_REMOVE_HEAD(&data->ms_head, tk_ms_link); | STAILQ_REMOVE_HEAD(&data->ms_head, tk_ms_link); | ||||
data->ms_count--; | |||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
MPASS(data->ms_count >= 0); | |||||
ftick->tk_ms_link.stqe_next = NULL; | ftick->tk_ms_link.stqe_next = NULL; | ||||
#endif | #endif | ||||
} | } | ||||
return (ftick); | return (ftick); | ||||
} | } | ||||
static inline void | static inline void | ||||
Show All 26 Lines | if ((ftick = TAILQ_FIRST(&data->aw_head)) != NULL) | ||||
fuse_aw_remove(ftick); | fuse_aw_remove(ftick); | ||||
return (ftick); | return (ftick); | ||||
} | } | ||||
struct fuse_ticket *fuse_ticket_fetch(struct fuse_data *data); | struct fuse_ticket *fuse_ticket_fetch(struct fuse_data *data); | ||||
int fuse_ticket_drop(struct fuse_ticket *ftick); | int fuse_ticket_drop(struct fuse_ticket *ftick); | ||||
void fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t *handler); | void fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t *handler); | ||||
void fuse_insert_message(struct fuse_ticket *ftick); | void fuse_insert_message(struct fuse_ticket *ftick, bool irq); | ||||
static inline bool | static inline bool | ||||
fuse_libabi_geq(struct fuse_data *data, uint32_t abi_maj, uint32_t abi_min) | fuse_libabi_geq(struct fuse_data *data, uint32_t abi_maj, uint32_t abi_min) | ||||
{ | { | ||||
return (data->fuse_libabi_major > abi_maj || | return (data->fuse_libabi_major > abi_maj || | ||||
(data->fuse_libabi_major == abi_maj && | (data->fuse_libabi_major == abi_maj && | ||||
data->fuse_libabi_minor >= abi_min)); | data->fuse_libabi_minor >= abi_min)); | ||||
} | } | ||||
Show All 30 Lines | |||||
fdisp_destroy(struct fuse_dispatcher *fdisp) | fdisp_destroy(struct fuse_dispatcher *fdisp) | ||||
{ | { | ||||
fuse_ticket_drop(fdisp->tick); | fuse_ticket_drop(fdisp->tick); | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
fdisp->tick = NULL; | fdisp->tick = NULL; | ||||
#endif | #endif | ||||
} | } | ||||
void fdisp_refresh(struct fuse_dispatcher *fdip); | |||||
void fdisp_make(struct fuse_dispatcher *fdip, enum fuse_opcode op, | void fdisp_make(struct fuse_dispatcher *fdip, enum fuse_opcode op, | ||||
struct mount *mp, uint64_t nid, struct thread *td, struct ucred *cred); | 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, | void fdisp_make_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op, | ||||
struct vnode *vp, struct thread *td, struct ucred *cred); | |||||
void fdisp_refresh_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op, | |||||
struct vnode *vp, struct thread *td, struct ucred *cred); | struct vnode *vp, struct thread *td, struct ucred *cred); | ||||
int fdisp_wait_answ(struct fuse_dispatcher *fdip); | int fdisp_wait_answ(struct fuse_dispatcher *fdip); | ||||
static inline int | static inline int | ||||
fdisp_simple_putget_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op, | fdisp_simple_putget_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op, | ||||
struct vnode *vp, struct thread *td, struct ucred *cred) | struct vnode *vp, struct thread *td, struct ucred *cred) | ||||
{ | { | ||||
fdisp_make_vp(fdip, op, vp, td, cred); | fdisp_make_vp(fdip, op, vp, td, cred); | ||||
return (fdisp_wait_answ(fdip)); | return (fdisp_wait_answ(fdip)); | ||||
} | } | ||||
#endif /* _FUSE_IPC_H_ */ | #endif /* _FUSE_IPC_H_ */ |