From 15bcc47d6ae157e79abaa78fde0bf34ee74ca0e8 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Mon, 16 Feb 2026 20:55:18 -0600 Subject: [PATCH] Remove "channels" and embed into session --- libfuse/include/fuse.h | 10 +-- libfuse/include/fuse_common.h | 15 ++--- libfuse/include/fuse_lowlevel.h | 72 +++++---------------- libfuse/include/fuse_msgbuf.hpp | 14 ++-- libfuse/include/fuse_pollhandle.h | 4 +- libfuse/include/fuse_req.hpp | 4 +- libfuse/lib/fuse.cpp | 15 +++-- libfuse/lib/fuse_i.h | 27 ++++---- libfuse/lib/fuse_lowlevel.cpp | 102 ++++++++++++++--------------- libfuse/lib/fuse_msgbuf.cpp | 47 ++++++++------ libfuse/lib/fuse_session.c | 104 ++++++++++-------------------- libfuse/lib/helper.c | 50 +++++++------- 12 files changed, 203 insertions(+), 261 deletions(-) diff --git a/libfuse/include/fuse.h b/libfuse/include/fuse.h index f44b4009..1c788f43 100644 --- a/libfuse/include/fuse.h +++ b/libfuse/include/fuse.h @@ -273,14 +273,16 @@ struct fuse_operations * Create a new FUSE filesystem. * * @param ch the communication channel + * @param fd the /dev/fuse file descriptor + * @param bufsize the buffer size for FUSE communication * @param args argument vector * @param op the filesystem operations - * @param op_size the size of the fuse_operations structure * @return the created FUSE handle */ -struct fuse *fuse_new(struct fuse_chan *ch, - struct fuse_args *args, - const struct fuse_operations *op); +struct fuse *fuse_new(int fd, + size_t bufsize, + struct fuse_args *args, + const struct fuse_operations *op); /** * Destroy the FUSE handle. diff --git a/libfuse/include/fuse_common.h b/libfuse/include/fuse_common.h index 992c3ce0..cb89ee19 100644 --- a/libfuse/include/fuse_common.h +++ b/libfuse/include/fuse_common.h @@ -135,25 +135,24 @@ struct fuse_pollhandle_t; typedef struct fuse_pollhandle_t fuse_pollhandle_t; /** - * Create a FUSE mountpoint + * Mount a FUSE filesystem. * - * Returns a control file descriptor suitable for passing to - * fuse_new() + * This function creates a FUSE mount and returns the /dev/fuse file descriptor. + * The file descriptor is stored in the session for internal use. * * @param mountpoint the mount point path * @param args argument vector - * @return the communication channel on success, NULL on failure + * @return the /dev/fuse file descriptor on success, -1 on failure */ -struct fuse_chan *fuse_mount(const char *mountpoint, - struct fuse_args *args); +int fuse_mount(const char *mountpoint, struct fuse_args *args); /** * Umount a FUSE mountpoint * * @param mountpoint the mount point path - * @param ch the communication channel + * @param fd the /dev/fuse file descriptor (or -1 if already closed) */ -void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); +void fuse_unmount(const char *mountpoint, int fd); /** * Parse common options diff --git a/libfuse/include/fuse_lowlevel.h b/libfuse/include/fuse_lowlevel.h index 53949774..3fe95f4f 100644 --- a/libfuse/include/fuse_lowlevel.h +++ b/libfuse/include/fuse_lowlevel.h @@ -29,13 +29,7 @@ EXTERN_C_BEGIN */ struct fuse_session; -/** - * Channel - * - * A communication channel, providing hooks for sending and receiving - * messages - */ -struct fuse_chan; + /** Directory entry parameters supplied to fuse_reply_entry() */ struct fuse_entry_param @@ -425,14 +419,14 @@ int fuse_lowlevel_notify_poll(fuse_pollhandle_t *ph); /** * Notify to invalidate cache for an inode * - * @param ch the channel through which to send the invalidation + * @param se the session through which to send the invalidation * @param ino the inode number * @param off the offset in the inode where to start invalidating * or negative to invalidate attributes only * @param len the amount of cache to invalidate or 0 for all * @return zero for success, -errno for failure */ -int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, uint64_t ino, +int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, uint64_t ino, off_t off, off_t len); /** @@ -443,13 +437,13 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, uint64_t ino, * don't call it with a lock held that can also be held by a filesystem * operation. * - * @param ch the channel through which to send the invalidation + * @param se the session through which to send the invalidation * @param parent inode number * @param name file name * @param namelen strlen() of file name * @return zero for success, -errno for failure */ -int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, uint64_t parent, +int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, uint64_t parent, const char *name, size_t namelen); /** @@ -461,14 +455,14 @@ int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, uint64_t parent, * don't call it with a lock held that can also be held by a filesystem * operation. * - * @param ch the channel through which to send the notification + * @param se the session through which to send the notification * @param parent inode number * @param child inode number * @param name file name * @param namelen strlen() of file name * @return zero for success, -errno for failure */ -int fuse_lowlevel_notify_delete(struct fuse_chan *ch, +int fuse_lowlevel_notify_delete(struct fuse_session *se, uint64_t parent, uint64_t child, const char *name, size_t namelen); @@ -490,14 +484,14 @@ int fuse_lowlevel_notify_delete(struct fuse_chan *ch, * buffer. For dirty pages the write() method will be called * regardless of having been retrieved previously. * - * @param ch the channel through which to send the invalidation + * @param se the session through which to send the invalidation * @param ino the inode number * @param size the number of bytes to retrieve * @param offset the starting offset into the file to retrieve from * @param cookie user data to supply to the reply callback * @return zero for success, -errno for failure */ -int fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, uint64_t ino, +int fuse_lowlevel_notify_retrieve(struct fuse_session *se, uint64_t ino, size_t size, off_t offset, void *cookie); @@ -554,8 +548,6 @@ struct fuse_session *fuse_session_new(void *data, void *receive_buf, void *process_buf, void *destroy); -void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); -void fuse_session_remove_chan(struct fuse_chan *ch); void fuse_session_destroy(struct fuse_session *se); void fuse_session_exit(struct fuse_session *se); int fuse_session_exited(struct fuse_session *se); @@ -573,44 +565,12 @@ int fuse_session_loop_mt(struct fuse_session *se, const int process_thread_queue_depth, const char *pin_threads_type); -/* ----------------------------------------------------------- * - * Channel interface * - * ----------------------------------------------------------- */ - -struct fuse_chan *fuse_chan_new(int fd, size_t bufsize); - -/** - * Query the file descriptor of the channel - * - * @param ch the channel - * @return the file descriptor passed to fuse_chan_new() - */ -int fuse_chan_fd(struct fuse_chan *ch); - -/** - * Query the minimal receive buffer size - * - * @param ch the channel - * @return the buffer size passed to fuse_chan_new() - */ -size_t fuse_chan_bufsize(struct fuse_chan *ch); - -/** - * Query the user data - * - * @param ch the channel - * @return the user data passed to fuse_chan_new() - */ -void *fuse_chan_data(struct fuse_chan *ch); - -/** - * Query the session to which this channel is assigned - * - * @param ch the channel - * @return the session, or NULL if the channel is not assigned - */ -struct fuse_session *fuse_chan_session(struct fuse_chan *ch); - -void fuse_chan_destroy(struct fuse_chan *ch); +/* Direct file descriptor and buffer size accessors + * (channel fields inlined into session for single-mount simplicity) */ +int fuse_session_fd(struct fuse_session *se); +size_t fuse_session_bufsize(struct fuse_session *se); +int fuse_session_clearfd(struct fuse_session *se); +void fuse_session_setfd(struct fuse_session *se, int fd); +void fuse_session_setbufsize(struct fuse_session *se, size_t bufsize); EXTERN_C_END diff --git a/libfuse/include/fuse_msgbuf.hpp b/libfuse/include/fuse_msgbuf.hpp index 345df805..1e791f10 100644 --- a/libfuse/include/fuse_msgbuf.hpp +++ b/libfuse/include/fuse_msgbuf.hpp @@ -21,16 +21,16 @@ #include "base_types.h" #include "fuse_msgbuf_t.h" -u32 msgbuf_get_pagesize(); -void msgbuf_set_bufsize(const uint32_t size); -uint64_t msgbuf_get_bufsize(); +u32 msgbuf_get_pagesize(); +void msgbuf_set_bufsize(const u64 size); +u64 msgbuf_get_bufsize(); fuse_msgbuf_t *msgbuf_alloc(); fuse_msgbuf_t *msgbuf_alloc_page_aligned(); void msgbuf_free(fuse_msgbuf_t *msgbuf); -void msgbuf_gc(); -void msgbuf_gc_10percent(); +void msgbuf_gc(); +void msgbuf_gc_10percent(); -uint64_t msgbuf_alloc_count(); -uint64_t msgbuf_avail_count(); +u64 msgbuf_alloc_count(); +u64 msgbuf_avail_count(); diff --git a/libfuse/include/fuse_pollhandle.h b/libfuse/include/fuse_pollhandle.h index 8cc2dd84..779c1bbf 100644 --- a/libfuse/include/fuse_pollhandle.h +++ b/libfuse/include/fuse_pollhandle.h @@ -2,11 +2,11 @@ #include -struct fuse_chan; +struct fuse_session; typedef struct fuse_pollhandle_t fuse_pollhandle_t; struct fuse_pollhandle_t { uint64_t kh; - struct fuse_chan *ch; + struct fuse_session *se; }; diff --git a/libfuse/include/fuse_req.hpp b/libfuse/include/fuse_req.hpp index 2c82ee53..7ba7df4c 100644 --- a/libfuse/include/fuse_req.hpp +++ b/libfuse/include/fuse_req.hpp @@ -3,13 +3,13 @@ #include "fuse_req_ctx.h" #include "fuse_conn_info.hpp" -struct fuse_chan; +struct fuse_session; typedef struct fuse_req_t fuse_req_t; struct fuse_req_t { fuse_req_ctx_t ctx; - struct fuse_chan *ch; + struct fuse_session *se; fuse_conn_info_t conn; unsigned int ioctl_64bit : 1; }; diff --git a/libfuse/lib/fuse.cpp b/libfuse/lib/fuse.cpp index 8d1d733f..7cc9d8e7 100644 --- a/libfuse/lib/fuse.cpp +++ b/libfuse/lib/fuse.cpp @@ -3313,7 +3313,7 @@ fuse_lib_poll(fuse_req_t *req_, } ph->kh = arg->kh; - ph->ch = req_->ch; + ph->se = req_->se; } err = f.ops.poll(&req_->ctx, @@ -3708,7 +3708,7 @@ fuse_invalidate_all_nodes() names.size()); for(auto &name : names) { - fuse_lowlevel_notify_inval_entry(f.se->ch, + fuse_lowlevel_notify_inval_entry(f.se, FUSE_ROOT_ID, name.c_str(), name.size()); @@ -3756,7 +3756,8 @@ fuse_populate_maintenance_thread(struct fuse *f_) } struct fuse* -fuse_new(struct fuse_chan *ch, +fuse_new(int fd_, + size_t bufsize_, struct fuse_args *args, const struct fuse_operations *ops_) { @@ -3779,7 +3780,9 @@ fuse_new(struct fuse_chan *ch, if(f.se == NULL) goto out_free_fs; - fuse_session_add_chan(f.se,ch); + /* Inlined channel fields - direct assignment */ + f.se->fd = fd_; + f.se->bufsize = bufsize_; /* Trace topmost layer by default */ srand(time(NULL)); @@ -3857,7 +3860,7 @@ fuse_passthrough_open(const int fd_) int dev_fuse_fd; struct fuse_backing_map bm = {}; - dev_fuse_fd = fuse_chan_fd(f.se->ch); + dev_fuse_fd = f.se->fd; bm.fd = fd_; rv = ::ioctl(dev_fuse_fd,FUSE_DEV_IOC_BACKING_OPEN,&bm); @@ -3870,7 +3873,7 @@ fuse_passthrough_close(const int backing_id_) { int dev_fuse_fd; - dev_fuse_fd = fuse_chan_fd(f.se->ch); + dev_fuse_fd = f.se->fd; return ::ioctl(dev_fuse_fd,FUSE_DEV_IOC_BACKING_CLOSE,&backing_id_); } diff --git a/libfuse/lib/fuse_i.h b/libfuse/lib/fuse_i.h index 0300d7b2..b144a94d 100644 --- a/libfuse/lib/fuse_i.h +++ b/libfuse/lib/fuse_i.h @@ -14,9 +14,13 @@ #include "extern_c.h" -struct fuse_chan; struct fuse_ll; +/* Simplified fuse_session - fields inlined from former fuse_chan + * Since mergerfs only supports one mount, we collapse the hierarchy: + * fuse_session -> fuse_chan -> fd + * into a single structure with direct fields. + */ struct fuse_session { int (*receive_buf)(struct fuse_session *se, @@ -29,7 +33,10 @@ struct fuse_session struct fuse_ll *f; volatile int exited; - struct fuse_chan *ch; + + /* Formerly in fuse_chan - inlined for single-mount simplicity */ + int fd; /* /dev/fuse file descriptor */ + size_t bufsize; /* Buffer size for I/O operations */ }; struct fuse_notify_req @@ -43,26 +50,22 @@ struct fuse_notify_req struct fuse_notify_req *prev; }; -struct fuse_cmd -{ - char *buf; - size_t buflen; - struct fuse_chan *ch; -}; + EXTERN_C_BEGIN -struct fuse *fuse_new_common(struct fuse_chan *ch, - struct fuse_args *args, +struct fuse *fuse_new_common(int fd, + size_t bufsize, + struct fuse_args *args, const struct fuse_operations *op); -struct fuse_chan *fuse_kern_chan_new(int fd); + struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata); -int fuse_chan_clearfd(struct fuse_chan *ch); + void fuse_kern_unmount(const char *mountpoint, int fd); int fuse_kern_mount(const char *mountpoint, struct fuse_args *args); diff --git a/libfuse/lib/fuse_lowlevel.cpp b/libfuse/lib/fuse_lowlevel.cpp index 8318a451..f5d6d6cd 100644 --- a/libfuse/lib/fuse_lowlevel.cpp +++ b/libfuse/lib/fuse_lowlevel.cpp @@ -102,16 +102,16 @@ iov_length(const struct iovec *iov, static int -fuse_send_msg(struct fuse_chan *ch, - struct iovec *iov, - int count) +fuse_send_msg(struct fuse_session *se, + struct iovec *iov, + int count) { int rv; struct fuse_out_header *out = (fuse_out_header*)iov[0].iov_base; out->len = iov_length(iov, count); - rv = writev(fuse_chan_fd(ch),iov,count); + rv = writev(se->fd,iov,count); if(rv == -1) return -errno; @@ -143,7 +143,7 @@ fuse_send_reply_iov_nofree(fuse_req_t *req, iov[0].iov_base = &out; iov[0].iov_len = sizeof(struct fuse_out_header); - return fuse_send_msg(req->ch, iov, count); + return fuse_send_msg(req->se, iov, count); } static @@ -424,7 +424,7 @@ fuse_reply_data(fuse_req_t *req, if(fuse_cfg.debug) fuse_debug_data_out(req->ctx.unique,bufsize_); - res = fuse_send_msg(req->ch,iov,2); + res = fuse_send_msg(req->se,iov,2); if(res <= 0) { fuse_req_free(req); @@ -1077,7 +1077,7 @@ do_init(fuse_req_t *req, max_write = UINT_MAX; max_readahead = UINT_MAX; - bufsize = fuse_chan_bufsize(req->ch); + bufsize = req->se->bufsize; inargflags = 0; outargflags = 0; @@ -1421,10 +1421,10 @@ do_lseek(fuse_req_t *req_, static int -send_notify_iov(struct fuse_chan *ch, - int notify_code, - struct iovec *iov, - int count) +send_notify_iov(struct fuse_session *se, + int notify_code, + struct iovec *iov, + int count) { struct fuse_out_header out; @@ -1436,7 +1436,7 @@ send_notify_iov(struct fuse_chan *ch, iov[0].iov_base = &out; iov[0].iov_len = sizeof(struct fuse_out_header); - return fuse_send_msg(ch, iov, count); + return fuse_send_msg(se, iov, count); } int @@ -1452,7 +1452,7 @@ fuse_lowlevel_notify_poll(fuse_pollhandle_t *ph) iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); - return send_notify_iov(ph->ch, FUSE_NOTIFY_POLL, iov, 2); + return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2); } else { @@ -1461,15 +1461,15 @@ fuse_lowlevel_notify_poll(fuse_pollhandle_t *ph) } int -fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, - uint64_t ino, - off_t off, - off_t len) +fuse_lowlevel_notify_inval_inode(struct fuse_session *se, + uint64_t ino, + off_t off, + off_t len) { struct fuse_notify_inval_inode_out outarg; struct iovec iov[2]; - if(!ch) + if(!se) return -EINVAL; outarg.ino = ino; @@ -1479,19 +1479,19 @@ fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); - return send_notify_iov(ch, FUSE_NOTIFY_INVAL_INODE, iov, 2); + return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2); } int -fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, - uint64_t parent, - const char *name, - size_t namelen) +fuse_lowlevel_notify_inval_entry(struct fuse_session *se, + uint64_t parent, + const char *name, + size_t namelen) { struct fuse_notify_inval_entry_out outarg; struct iovec iov[3]; - if(!ch) + if(!se) return -EINVAL; outarg.parent = parent; @@ -1504,20 +1504,20 @@ fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, iov[2].iov_base = (void *)name; iov[2].iov_len = namelen + 1; - return send_notify_iov(ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3); + return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3); } int -fuse_lowlevel_notify_delete(struct fuse_chan *ch, - uint64_t parent, - uint64_t child, - const char *name, - size_t namelen) +fuse_lowlevel_notify_delete(struct fuse_session *se, + uint64_t parent, + uint64_t child, + const char *name, + size_t namelen) { struct fuse_notify_delete_out outarg; struct iovec iov[3]; - if(!ch) + if(!se) return -EINVAL; if(f.conn.proto_minor < 18) @@ -1533,7 +1533,7 @@ fuse_lowlevel_notify_delete(struct fuse_chan *ch, iov[2].iov_base = (void *)name; iov[2].iov_len = namelen + 1; - return send_notify_iov(ch, FUSE_NOTIFY_DELETE, iov, 3); + return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3); } struct fuse_retrieve_req @@ -1558,18 +1558,18 @@ fuse_ll_retrieve_reply(struct fuse_notify_req *nreq, } int -fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, - uint64_t ino, - size_t size, - off_t offset, - void *cookie) +fuse_lowlevel_notify_retrieve(struct fuse_session *se, + uint64_t ino, + size_t size, + off_t offset, + void *cookie) { struct fuse_notify_retrieve_out outarg; struct iovec iov[2]; struct fuse_retrieve_req *rreq; int err; - if(!ch) + if(!se) return -EINVAL; if(f.conn.proto_minor < 15) @@ -1594,7 +1594,7 @@ fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); - err = send_notify_iov(ch, FUSE_NOTIFY_RETRIEVE, iov, 2); + err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2); if(err) { mutex_lock(&f.lock); @@ -1685,9 +1685,9 @@ fuse_ll_destroy(void *data) static void -fuse_send_errno(struct fuse_chan *ch_, - const int errno_, - const uint64_t unique_id_) +fuse_send_errno(struct fuse_session *se_, + const int errno_, + const uint64_t unique_id_) { struct fuse_out_header out = {}; struct iovec iov = {}; @@ -1701,15 +1701,15 @@ fuse_send_errno(struct fuse_chan *ch_, if(fuse_cfg.debug) fuse_debug_out_header(&out); - fuse_send_msg(ch_,&iov,1); + fuse_send_msg(se_,&iov,1); } static void -fuse_send_enomem(struct fuse_chan *ch_, - const uint64_t unique_id_) +fuse_send_enomem(struct fuse_session *se_, + const uint64_t unique_id_) { - fuse_send_errno(ch_,ENOMEM,unique_id_); + fuse_send_errno(se_,ENOMEM,unique_id_); } // static @@ -1728,7 +1728,7 @@ fuse_ll_buf_receive_read(struct fuse_session *se_, { int rv; - rv = read(fuse_chan_fd(se_->ch),msgbuf_->mem,msgbuf_->size); + rv = read(se_->fd,msgbuf_->mem,msgbuf_->size); if(rv == -1) return -errno; @@ -1757,7 +1757,7 @@ fuse_ll_buf_process_read(struct fuse_session *se_, req = fuse_req_alloc(); if(req == NULL) - return fuse_send_enomem(se_->ch,in->unique); + return fuse_send_enomem(se_,in->unique); req->ctx.len = in->len; req->ctx.opcode = in->opcode; @@ -1768,7 +1768,7 @@ fuse_ll_buf_process_read(struct fuse_session *se_, req->ctx.pid = in->pid; req->ctx.umask = 0; req->conn = f.conn; - req->ch = se_->ch; + req->se = se_; err = ENOSYS; if(in->opcode >= FUSE_MAXOPS) @@ -1801,7 +1801,7 @@ fuse_ll_buf_process_read_init(struct fuse_session *se_, req = fuse_req_alloc(); if(req == NULL) - return fuse_send_enomem(se_->ch,in->unique); + return fuse_send_enomem(se_,in->unique); req->ctx.len = in->len; req->ctx.opcode = in->opcode; @@ -1811,7 +1811,7 @@ fuse_ll_buf_process_read_init(struct fuse_session *se_, req->ctx.gid = in->gid; req->ctx.pid = in->pid; req->ctx.umask = 0; - req->ch = se_->ch; + req->se = se_; err = EIO; if(in->opcode != FUSE_INIT) diff --git a/libfuse/lib/fuse_msgbuf.cpp b/libfuse/lib/fuse_msgbuf.cpp index be35ab98..a3986a13 100644 --- a/libfuse/lib/fuse_msgbuf.cpp +++ b/libfuse/lib/fuse_msgbuf.cpp @@ -22,22 +22,22 @@ #include +#include #include -#include #include #include #include -static std::uint32_t g_PAGESIZE = 0; -static std::uint32_t g_BUFSIZE = 0; +static u32 g_PAGESIZE = 0; +static u64 g_BUFSIZE = 0; -static std::atomic g_MSGBUF_ALLOC_COUNT; +static std::atomic g_MSGBUF_ALLOC_COUNT = 0; static std::mutex g_MUTEX; static std::vector g_MSGBUF_STACK; -uint64_t +u64 msgbuf_get_bufsize() { return g_BUFSIZE; @@ -54,7 +54,7 @@ msgbuf_get_pagesize() // aligned. +1 again for fuse header as the max_pages value is for the // body. void -msgbuf_set_bufsize(const uint32_t size_in_pages_) +msgbuf_set_bufsize(const u64 size_in_pages_) { g_BUFSIZE = ((size_in_pages_ + 2) * g_PAGESIZE); } @@ -84,7 +84,14 @@ __attribute__((constructor)) void _msgbuf_constructor() { - g_PAGESIZE = sysconf(_SC_PAGESIZE); + long pagesize = sysconf(_SC_PAGESIZE); + + assert(pagesize > 0); + g_PAGESIZE = pagesize; + + // Ensure fuse headers fit within a single page for O_DIRECT alignment + assert((sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in)) + < g_PAGESIZE); msgbuf_set_bufsize(FUSE_DEFAULT_MAX_MAX_PAGES); } @@ -94,17 +101,17 @@ __attribute__((destructor)) void _msgbuf_destructor() { - + msgbuf_gc(); } static void* -_page_aligned_malloc(const uint64_t size_) +_page_aligned_malloc(const u64 size_in_bytes_) { int rv; void *buf = NULL; - rv = posix_memalign(&buf,g_PAGESIZE,size_); + rv = posix_memalign(&buf,g_PAGESIZE,size_in_bytes_); if(rv != 0) return NULL; @@ -167,26 +174,30 @@ msgbuf_destroy(fuse_msgbuf_t *msgbuf_) void msgbuf_free(fuse_msgbuf_t *msgbuf_) { - std::lock_guard lck(g_MUTEX); + bool destroy; - if(msgbuf_->size != (g_BUFSIZE - g_PAGESIZE)) + { + std::lock_guard lck(g_MUTEX); + + destroy = (msgbuf_->size != (g_BUFSIZE - g_PAGESIZE)); + if(!destroy) + g_MSGBUF_STACK.emplace_back(msgbuf_); + } + + if(destroy) { msgbuf_destroy(msgbuf_); g_MSGBUF_ALLOC_COUNT.fetch_sub(1,std::memory_order_relaxed); - return; } - - g_MSGBUF_STACK.emplace_back(msgbuf_); - } -uint64_t +u64 msgbuf_alloc_count() { return g_MSGBUF_ALLOC_COUNT; } -uint64_t +u64 msgbuf_avail_count() { std::lock_guard lck(g_MUTEX); diff --git a/libfuse/lib/fuse_session.c b/libfuse/lib/fuse_session.c index 32d357d6..5b3d99ac 100644 --- a/libfuse/lib/fuse_session.c +++ b/libfuse/lib/fuse_session.c @@ -4,7 +4,7 @@ This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB -*/ + */ #include "fuse_i.h" #include "fuse_kernel.h" @@ -17,15 +17,14 @@ #include #include +/* + * Simplified session management for single-mount filesystems. + * The fuse_chan structure has been removed and its fields inlined + * into fuse_session (fd, bufsize) since mergerfs only supports + * one mount point per process. + */ -struct fuse_chan -{ - struct fuse_session *se; - int fd; - size_t bufsize; -}; - -struct fuse_session * +struct fuse_session* fuse_session_new(void *data, void *receive_buf, void *process_buf, @@ -42,38 +41,25 @@ fuse_session_new(void *data, se->receive_buf = receive_buf; se->process_buf = process_buf; se->destroy = destroy; + se->fd = -1; /* Not yet mounted */ + se->bufsize = 0; return se; } -void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch) -{ - assert(se->ch == NULL); - assert(ch->se == NULL); - se->ch = ch; - ch->se = se; -} - -void fuse_session_remove_chan(struct fuse_chan *ch) -{ - struct fuse_session *se = ch->se; - if (se) { - assert(se->ch == ch); - se->ch = NULL; - ch->se = NULL; - } -} - void fuse_session_destroy(struct fuse_session *se) { se->destroy(se->f); - if(se->ch != NULL) - fuse_chan_destroy(se->ch); + if(se->fd != -1) { + close(se->fd); + se->fd = -1; + } free(se); } -void fuse_session_reset(struct fuse_session *se) +void +fuse_session_reset(struct fuse_session *se) { se->exited = 0; } @@ -96,59 +82,37 @@ fuse_session_data(struct fuse_session *se) return se->f; } -struct fuse_chan * -fuse_chan_new(int fd, - size_t bufsize) +/* Direct accessors for inlined channel fields */ +int +fuse_session_fd(struct fuse_session *se) { - struct fuse_chan *ch; - - ch = (struct fuse_chan*)malloc(sizeof(*ch)); - if(ch == NULL) - { - fprintf(stderr, "fuse: failed to allocate channel\n"); - return NULL; - } - - memset(ch, 0, sizeof(*ch)); - - ch->fd = fd; - ch->bufsize = bufsize; - - return ch; + return se->fd; } -int fuse_chan_fd(struct fuse_chan *ch) +size_t +fuse_session_bufsize(struct fuse_session *se) { - return ch->fd; + return se->bufsize; } -int fuse_chan_clearfd(struct fuse_chan *ch) +int +fuse_session_clearfd(struct fuse_session *se) { - int fd = ch->fd; - ch->fd = -1; + int fd = se->fd; + se->fd = -1; return fd; } -size_t fuse_chan_bufsize(struct fuse_chan *ch) -{ - return ch->bufsize; -} - -struct fuse_session *fuse_chan_session(struct fuse_chan *ch) +void +fuse_session_setfd(struct fuse_session *se, + int fd) { - return ch->se; + se->fd = fd; } void -fuse_chan_destroy(struct fuse_chan *ch) +fuse_session_setbufsize(struct fuse_session *se, + size_t bufsize) { - int fd; - - fuse_session_remove_chan(ch); - - fd = fuse_chan_fd(ch); - if(fd != -1) - close(fd); - - free(ch); + se->bufsize = bufsize; } diff --git a/libfuse/lib/helper.c b/libfuse/lib/helper.c index 6f19a48a..725fbd3f 100644 --- a/libfuse/lib/helper.c +++ b/libfuse/lib/helper.c @@ -194,14 +194,14 @@ int fuse_daemonize(int foreground) } static -struct fuse_chan * +int fuse_mount_common(const char *mountpoint_, - struct fuse_args *args_) + struct fuse_args *args_, + size_t *bufsize_) { int fd; long bufsize; long pagesize; - struct fuse_chan *ch; /* * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos @@ -216,38 +216,34 @@ fuse_mount_common(const char *mountpoint_, fd = fuse_kern_mount(mountpoint_,args_); if(fd == -1) - return NULL; + return -1; pagesize = sysconf(_SC_PAGESIZE); bufsize = ((FUSE_DEFAULT_MAX_MAX_PAGES + 1) * pagesize); - ch = fuse_chan_new(fd,bufsize); - if(!ch) - fuse_kern_unmount(mountpoint_, fd); + if (bufsize_) + *bufsize_ = bufsize; - return ch; + return fd; } -struct fuse_chan * +int fuse_mount(const char *mountpoint_, struct fuse_args *args_) { - return fuse_mount_common(mountpoint_,args_); + return fuse_mount_common(mountpoint_,args_,NULL); } -static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch) +static void fuse_unmount_common(const char *mountpoint, int fd) { - if (mountpoint) { - int fd = ch ? fuse_chan_clearfd(ch) : -1; + if (mountpoint && fd != -1) { fuse_kern_unmount(mountpoint, fd); - if (ch) - fuse_chan_destroy(ch); } } -void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) +void fuse_unmount(const char *mountpoint, int fd) { - fuse_unmount_common(mountpoint, ch); + fuse_unmount_common(mountpoint, fd); } struct fuse* @@ -258,7 +254,8 @@ fuse_setup_common(int argc, int *fd) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_chan *ch; + int fuse_fd; + size_t bufsize; struct fuse *fuse; int foreground; int res; @@ -267,13 +264,13 @@ fuse_setup_common(int argc, if (res == -1) return NULL; - ch = fuse_mount_common(*mountpoint, &args); - if (!ch) { + fuse_fd = fuse_mount_common(*mountpoint, &args, &bufsize); + if (fuse_fd == -1) { fuse_opt_free_args(&args); goto err_free; } - fuse = fuse_new(ch, &args, op); + fuse = fuse_new(fuse_fd, bufsize, &args, op); fuse_opt_free_args(&args); if (fuse == NULL) goto err_unmount; @@ -287,12 +284,12 @@ fuse_setup_common(int argc, goto err_unmount; if (fd) - *fd = fuse_chan_fd(ch); + *fd = fuse_fd; return fuse; err_unmount: - fuse_unmount_common(*mountpoint, ch); + fuse_unmount_common(*mountpoint, fuse_fd); err_free: free(*mountpoint); return NULL; @@ -313,9 +310,12 @@ struct fuse *fuse_setup(int argc, static void fuse_teardown_common(char *mountpoint) { struct fuse_session *se = fuse_get_session(); - struct fuse_chan *ch = se->ch; + int fd = se ? se->fd : -1; fuse_remove_signal_handlers(se); - fuse_unmount_common(mountpoint, ch); + if (mountpoint && fd != -1) { + se->fd = -1; + fuse_kern_unmount(mountpoint, fd); + } free(mountpoint); }