Browse Source

Remove "channels" and embed into session

pull/1619/head
Antonio SJ Musumeci 4 weeks ago
parent
commit
550abed5ee
  1. 10
      libfuse/include/fuse.h
  2. 15
      libfuse/include/fuse_common.h
  3. 72
      libfuse/include/fuse_lowlevel.h
  4. 14
      libfuse/include/fuse_msgbuf.hpp
  5. 4
      libfuse/include/fuse_pollhandle.h
  6. 4
      libfuse/include/fuse_req.hpp
  7. 15
      libfuse/lib/fuse.cpp
  8. 27
      libfuse/lib/fuse_i.h
  9. 102
      libfuse/lib/fuse_lowlevel.cpp
  10. 47
      libfuse/lib/fuse_msgbuf.cpp
  11. 104
      libfuse/lib/fuse_session.c
  12. 50
      libfuse/lib/helper.c

10
libfuse/include/fuse.h

@ -273,14 +273,16 @@ struct fuse_operations
* Create a new FUSE filesystem. * Create a new FUSE filesystem.
* *
* @param ch the communication channel * @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 args argument vector
* @param op the filesystem operations * @param op the filesystem operations
* @param op_size the size of the fuse_operations structure
* @return the created FUSE handle * @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. * Destroy the FUSE handle.

15
libfuse/include/fuse_common.h

@ -135,25 +135,24 @@ struct fuse_pollhandle_t;
typedef struct fuse_pollhandle_t 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 mountpoint the mount point path
* @param args argument vector * @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 * Umount a FUSE mountpoint
* *
* @param mountpoint the mount point path * @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 * Parse common options

72
libfuse/include/fuse_lowlevel.h

@ -29,13 +29,7 @@ EXTERN_C_BEGIN
*/ */
struct fuse_session; 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() */ /** Directory entry parameters supplied to fuse_reply_entry() */
struct fuse_entry_param struct fuse_entry_param
@ -425,14 +419,14 @@ int fuse_lowlevel_notify_poll(fuse_pollhandle_t *ph);
/** /**
* Notify to invalidate cache for an inode * 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 ino the inode number
* @param off the offset in the inode where to start invalidating * @param off the offset in the inode where to start invalidating
* or negative to invalidate attributes only * or negative to invalidate attributes only
* @param len the amount of cache to invalidate or 0 for all * @param len the amount of cache to invalidate or 0 for all
* @return zero for success, -errno for failure * @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); 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 * don't call it with a lock held that can also be held by a filesystem
* operation. * 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 parent inode number
* @param name file name * @param name file name
* @param namelen strlen() of file name * @param namelen strlen() of file name
* @return zero for success, -errno for failure * @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); 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 * don't call it with a lock held that can also be held by a filesystem
* operation. * 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 parent inode number
* @param child inode number * @param child inode number
* @param name file name * @param name file name
* @param namelen strlen() of file name * @param namelen strlen() of file name
* @return zero for success, -errno for failure * @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, uint64_t parent, uint64_t child,
const char *name, size_t namelen); 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 * buffer. For dirty pages the write() method will be called
* regardless of having been retrieved previously. * 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 ino the inode number
* @param size the number of bytes to retrieve * @param size the number of bytes to retrieve
* @param offset the starting offset into the file to retrieve from * @param offset the starting offset into the file to retrieve from
* @param cookie user data to supply to the reply callback * @param cookie user data to supply to the reply callback
* @return zero for success, -errno for failure * @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); size_t size, off_t offset, void *cookie);
@ -554,8 +548,6 @@ struct fuse_session *fuse_session_new(void *data,
void *receive_buf, void *receive_buf,
void *process_buf, void *process_buf,
void *destroy); 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_destroy(struct fuse_session *se);
void fuse_session_exit(struct fuse_session *se); void fuse_session_exit(struct fuse_session *se);
int fuse_session_exited(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 int process_thread_queue_depth,
const char *pin_threads_type); 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 EXTERN_C_END

14
libfuse/include/fuse_msgbuf.hpp

@ -21,16 +21,16 @@
#include "base_types.h" #include "base_types.h"
#include "fuse_msgbuf_t.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();
fuse_msgbuf_t *msgbuf_alloc_page_aligned(); fuse_msgbuf_t *msgbuf_alloc_page_aligned();
void msgbuf_free(fuse_msgbuf_t *msgbuf); 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();

4
libfuse/include/fuse_pollhandle.h

@ -2,11 +2,11 @@
#include <stdint.h> #include <stdint.h>
struct fuse_chan;
struct fuse_session;
typedef struct fuse_pollhandle_t fuse_pollhandle_t; typedef struct fuse_pollhandle_t fuse_pollhandle_t;
struct fuse_pollhandle_t struct fuse_pollhandle_t
{ {
uint64_t kh; uint64_t kh;
struct fuse_chan *ch;
struct fuse_session *se;
}; };

4
libfuse/include/fuse_req.hpp

@ -3,13 +3,13 @@
#include "fuse_req_ctx.h" #include "fuse_req_ctx.h"
#include "fuse_conn_info.hpp" #include "fuse_conn_info.hpp"
struct fuse_chan;
struct fuse_session;
typedef struct fuse_req_t fuse_req_t; typedef struct fuse_req_t fuse_req_t;
struct fuse_req_t struct fuse_req_t
{ {
fuse_req_ctx_t ctx; fuse_req_ctx_t ctx;
struct fuse_chan *ch;
struct fuse_session *se;
fuse_conn_info_t conn; fuse_conn_info_t conn;
unsigned int ioctl_64bit : 1; unsigned int ioctl_64bit : 1;
}; };

15
libfuse/lib/fuse.cpp

@ -3313,7 +3313,7 @@ fuse_lib_poll(fuse_req_t *req_,
} }
ph->kh = arg->kh; ph->kh = arg->kh;
ph->ch = req_->ch;
ph->se = req_->se;
} }
err = f.ops.poll(&req_->ctx, err = f.ops.poll(&req_->ctx,
@ -3708,7 +3708,7 @@ fuse_invalidate_all_nodes()
names.size()); names.size());
for(auto &name : names) for(auto &name : names)
{ {
fuse_lowlevel_notify_inval_entry(f.se->ch,
fuse_lowlevel_notify_inval_entry(f.se,
FUSE_ROOT_ID, FUSE_ROOT_ID,
name.c_str(), name.c_str(),
name.size()); name.size());
@ -3756,7 +3756,8 @@ fuse_populate_maintenance_thread(struct fuse *f_)
} }
struct fuse* struct fuse*
fuse_new(struct fuse_chan *ch,
fuse_new(int fd_,
size_t bufsize_,
struct fuse_args *args, struct fuse_args *args,
const struct fuse_operations *ops_) const struct fuse_operations *ops_)
{ {
@ -3779,7 +3780,9 @@ fuse_new(struct fuse_chan *ch,
if(f.se == NULL) if(f.se == NULL)
goto out_free_fs; 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 */ /* Trace topmost layer by default */
srand(time(NULL)); srand(time(NULL));
@ -3857,7 +3860,7 @@ fuse_passthrough_open(const int fd_)
int dev_fuse_fd; int dev_fuse_fd;
struct fuse_backing_map bm = {}; struct fuse_backing_map bm = {};
dev_fuse_fd = fuse_chan_fd(f.se->ch);
dev_fuse_fd = f.se->fd;
bm.fd = fd_; bm.fd = fd_;
rv = ::ioctl(dev_fuse_fd,FUSE_DEV_IOC_BACKING_OPEN,&bm); 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; 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_); return ::ioctl(dev_fuse_fd,FUSE_DEV_IOC_BACKING_CLOSE,&backing_id_);
} }

27
libfuse/lib/fuse_i.h

@ -14,9 +14,13 @@
#include "extern_c.h" #include "extern_c.h"
struct fuse_chan;
struct fuse_ll; 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 struct fuse_session
{ {
int (*receive_buf)(struct fuse_session *se, int (*receive_buf)(struct fuse_session *se,
@ -29,7 +33,10 @@ struct fuse_session
struct fuse_ll *f; struct fuse_ll *f;
volatile int exited; 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 struct fuse_notify_req
@ -43,26 +50,22 @@ struct fuse_notify_req
struct fuse_notify_req *prev; struct fuse_notify_req *prev;
}; };
struct fuse_cmd
{
char *buf;
size_t buflen;
struct fuse_chan *ch;
};
EXTERN_C_BEGIN 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); 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, struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
const struct fuse_lowlevel_ops *op, const struct fuse_lowlevel_ops *op,
size_t op_size, void *userdata); size_t op_size, void *userdata);
int fuse_chan_clearfd(struct fuse_chan *ch);
void fuse_kern_unmount(const char *mountpoint, int fd); void fuse_kern_unmount(const char *mountpoint, int fd);
int fuse_kern_mount(const char *mountpoint, struct fuse_args *args); int fuse_kern_mount(const char *mountpoint, struct fuse_args *args);

102
libfuse/lib/fuse_lowlevel.cpp

@ -102,16 +102,16 @@ iov_length(const struct iovec *iov,
static static
int 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; int rv;
struct fuse_out_header *out = (fuse_out_header*)iov[0].iov_base; struct fuse_out_header *out = (fuse_out_header*)iov[0].iov_base;
out->len = iov_length(iov, count); out->len = iov_length(iov, count);
rv = writev(fuse_chan_fd(ch),iov,count);
rv = writev(se->fd,iov,count);
if(rv == -1) if(rv == -1)
return -errno; return -errno;
@ -143,7 +143,7 @@ fuse_send_reply_iov_nofree(fuse_req_t *req,
iov[0].iov_base = &out; iov[0].iov_base = &out;
iov[0].iov_len = sizeof(struct fuse_out_header); 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 static
@ -424,7 +424,7 @@ fuse_reply_data(fuse_req_t *req,
if(fuse_cfg.debug) if(fuse_cfg.debug)
fuse_debug_data_out(req->ctx.unique,bufsize_); 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) if(res <= 0)
{ {
fuse_req_free(req); fuse_req_free(req);
@ -1077,7 +1077,7 @@ do_init(fuse_req_t *req,
max_write = UINT_MAX; max_write = UINT_MAX;
max_readahead = UINT_MAX; max_readahead = UINT_MAX;
bufsize = fuse_chan_bufsize(req->ch);
bufsize = req->se->bufsize;
inargflags = 0; inargflags = 0;
outargflags = 0; outargflags = 0;
@ -1421,10 +1421,10 @@ do_lseek(fuse_req_t *req_,
static static
int 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; struct fuse_out_header out;
@ -1436,7 +1436,7 @@ send_notify_iov(struct fuse_chan *ch,
iov[0].iov_base = &out; iov[0].iov_base = &out;
iov[0].iov_len = sizeof(struct fuse_out_header); iov[0].iov_len = sizeof(struct fuse_out_header);
return fuse_send_msg(ch, iov, count);
return fuse_send_msg(se, iov, count);
} }
int int
@ -1452,7 +1452,7 @@ fuse_lowlevel_notify_poll(fuse_pollhandle_t *ph)
iov[1].iov_base = &outarg; iov[1].iov_base = &outarg;
iov[1].iov_len = sizeof(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 else
{ {
@ -1461,15 +1461,15 @@ fuse_lowlevel_notify_poll(fuse_pollhandle_t *ph)
} }
int 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 fuse_notify_inval_inode_out outarg;
struct iovec iov[2]; struct iovec iov[2];
if(!ch)
if(!se)
return -EINVAL; return -EINVAL;
outarg.ino = ino; outarg.ino = ino;
@ -1479,19 +1479,19 @@ fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch,
iov[1].iov_base = &outarg; iov[1].iov_base = &outarg;
iov[1].iov_len = sizeof(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 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 fuse_notify_inval_entry_out outarg;
struct iovec iov[3]; struct iovec iov[3];
if(!ch)
if(!se)
return -EINVAL; return -EINVAL;
outarg.parent = parent; 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_base = (void *)name;
iov[2].iov_len = namelen + 1; 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 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 fuse_notify_delete_out outarg;
struct iovec iov[3]; struct iovec iov[3];
if(!ch)
if(!se)
return -EINVAL; return -EINVAL;
if(f.conn.proto_minor < 18) 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_base = (void *)name;
iov[2].iov_len = namelen + 1; 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 struct fuse_retrieve_req
@ -1558,18 +1558,18 @@ fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
} }
int 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 fuse_notify_retrieve_out outarg;
struct iovec iov[2]; struct iovec iov[2];
struct fuse_retrieve_req *rreq; struct fuse_retrieve_req *rreq;
int err; int err;
if(!ch)
if(!se)
return -EINVAL; return -EINVAL;
if(f.conn.proto_minor < 15) 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_base = &outarg;
iov[1].iov_len = sizeof(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) if(err)
{ {
mutex_lock(&f.lock); mutex_lock(&f.lock);
@ -1685,9 +1685,9 @@ fuse_ll_destroy(void *data)
static static
void 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 fuse_out_header out = {};
struct iovec iov = {}; struct iovec iov = {};
@ -1701,15 +1701,15 @@ fuse_send_errno(struct fuse_chan *ch_,
if(fuse_cfg.debug) if(fuse_cfg.debug)
fuse_debug_out_header(&out); fuse_debug_out_header(&out);
fuse_send_msg(ch_,&iov,1);
fuse_send_msg(se_,&iov,1);
} }
static static
void 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 // static
@ -1728,7 +1728,7 @@ fuse_ll_buf_receive_read(struct fuse_session *se_,
{ {
int rv; int rv;
rv = read(fuse_chan_fd(se_->ch),msgbuf_->mem,msgbuf_->size);
rv = read(se_->fd,msgbuf_->mem,msgbuf_->size);
if(rv == -1) if(rv == -1)
return -errno; return -errno;
@ -1757,7 +1757,7 @@ fuse_ll_buf_process_read(struct fuse_session *se_,
req = fuse_req_alloc(); req = fuse_req_alloc();
if(req == NULL) 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.len = in->len;
req->ctx.opcode = in->opcode; 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.pid = in->pid;
req->ctx.umask = 0; req->ctx.umask = 0;
req->conn = f.conn; req->conn = f.conn;
req->ch = se_->ch;
req->se = se_;
err = ENOSYS; err = ENOSYS;
if(in->opcode >= FUSE_MAXOPS) if(in->opcode >= FUSE_MAXOPS)
@ -1801,7 +1801,7 @@ fuse_ll_buf_process_read_init(struct fuse_session *se_,
req = fuse_req_alloc(); req = fuse_req_alloc();
if(req == NULL) 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.len = in->len;
req->ctx.opcode = in->opcode; 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.gid = in->gid;
req->ctx.pid = in->pid; req->ctx.pid = in->pid;
req->ctx.umask = 0; req->ctx.umask = 0;
req->ch = se_->ch;
req->se = se_;
err = EIO; err = EIO;
if(in->opcode != FUSE_INIT) if(in->opcode != FUSE_INIT)

47
libfuse/lib/fuse_msgbuf.cpp

@ -22,22 +22,22 @@
#include <unistd.h> #include <unistd.h>
#include <cassert>
#include <atomic> #include <atomic>
#include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <mutex> #include <mutex>
#include <vector> #include <vector>
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<std::uint_fast64_t> g_MSGBUF_ALLOC_COUNT;
static std::atomic<std::uint_fast64_t> g_MSGBUF_ALLOC_COUNT = 0;
static std::mutex g_MUTEX; static std::mutex g_MUTEX;
static std::vector<fuse_msgbuf_t*> g_MSGBUF_STACK; static std::vector<fuse_msgbuf_t*> g_MSGBUF_STACK;
uint64_t
u64
msgbuf_get_bufsize() msgbuf_get_bufsize()
{ {
return g_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 // aligned. +1 again for fuse header as the max_pages value is for the
// body. // body.
void 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); g_BUFSIZE = ((size_in_pages_ + 2) * g_PAGESIZE);
} }
@ -84,7 +84,14 @@ __attribute__((constructor))
void void
_msgbuf_constructor() _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); msgbuf_set_bufsize(FUSE_DEFAULT_MAX_MAX_PAGES);
} }
@ -94,17 +101,17 @@ __attribute__((destructor))
void void
_msgbuf_destructor() _msgbuf_destructor()
{ {
msgbuf_gc();
} }
static static
void* void*
_page_aligned_malloc(const uint64_t size_)
_page_aligned_malloc(const u64 size_in_bytes_)
{ {
int rv; int rv;
void *buf = NULL; void *buf = NULL;
rv = posix_memalign(&buf,g_PAGESIZE,size_);
rv = posix_memalign(&buf,g_PAGESIZE,size_in_bytes_);
if(rv != 0) if(rv != 0)
return NULL; return NULL;
@ -167,26 +174,30 @@ msgbuf_destroy(fuse_msgbuf_t *msgbuf_)
void void
msgbuf_free(fuse_msgbuf_t *msgbuf_) msgbuf_free(fuse_msgbuf_t *msgbuf_)
{ {
std::lock_guard<std::mutex> lck(g_MUTEX);
bool destroy;
if(msgbuf_->size != (g_BUFSIZE - g_PAGESIZE))
{
std::lock_guard<std::mutex> lck(g_MUTEX);
destroy = (msgbuf_->size != (g_BUFSIZE - g_PAGESIZE));
if(!destroy)
g_MSGBUF_STACK.emplace_back(msgbuf_);
}
if(destroy)
{ {
msgbuf_destroy(msgbuf_); msgbuf_destroy(msgbuf_);
g_MSGBUF_ALLOC_COUNT.fetch_sub(1,std::memory_order_relaxed); g_MSGBUF_ALLOC_COUNT.fetch_sub(1,std::memory_order_relaxed);
return;
} }
g_MSGBUF_STACK.emplace_back(msgbuf_);
} }
uint64_t
u64
msgbuf_alloc_count() msgbuf_alloc_count()
{ {
return g_MSGBUF_ALLOC_COUNT; return g_MSGBUF_ALLOC_COUNT;
} }
uint64_t
u64
msgbuf_avail_count() msgbuf_avail_count()
{ {
std::lock_guard<std::mutex> lck(g_MUTEX); std::lock_guard<std::mutex> lck(g_MUTEX);

104
libfuse/lib/fuse_session.c

@ -4,7 +4,7 @@
This program can be distributed under the terms of the GNU LGPLv2. This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB See the file COPYING.LIB
*/
*/
#include "fuse_i.h" #include "fuse_i.h"
#include "fuse_kernel.h" #include "fuse_kernel.h"
@ -17,15 +17,14 @@
#include <unistd.h> #include <unistd.h>
#include <sys/uio.h> #include <sys/uio.h>
/*
* 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, fuse_session_new(void *data,
void *receive_buf, void *receive_buf,
void *process_buf, void *process_buf,
@ -42,38 +41,25 @@ fuse_session_new(void *data,
se->receive_buf = receive_buf; se->receive_buf = receive_buf;
se->process_buf = process_buf; se->process_buf = process_buf;
se->destroy = destroy; se->destroy = destroy;
se->fd = -1; /* Not yet mounted */
se->bufsize = 0;
return se; 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 void
fuse_session_destroy(struct fuse_session *se) fuse_session_destroy(struct fuse_session *se)
{ {
se->destroy(se->f); 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); free(se);
} }
void fuse_session_reset(struct fuse_session *se)
void
fuse_session_reset(struct fuse_session *se)
{ {
se->exited = 0; se->exited = 0;
} }
@ -96,59 +82,37 @@ fuse_session_data(struct fuse_session *se)
return se->f; 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; 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 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;
} }

50
libfuse/lib/helper.c

@ -194,14 +194,14 @@ int fuse_daemonize(int foreground)
} }
static static
struct fuse_chan *
int
fuse_mount_common(const char *mountpoint_, fuse_mount_common(const char *mountpoint_,
struct fuse_args *args_)
struct fuse_args *args_,
size_t *bufsize_)
{ {
int fd; int fd;
long bufsize; long bufsize;
long pagesize; long pagesize;
struct fuse_chan *ch;
/* /*
* Make sure file descriptors 0, 1 and 2 are open, otherwise chaos * 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_); fd = fuse_kern_mount(mountpoint_,args_);
if(fd == -1) if(fd == -1)
return NULL;
return -1;
pagesize = sysconf(_SC_PAGESIZE); pagesize = sysconf(_SC_PAGESIZE);
bufsize = ((FUSE_DEFAULT_MAX_MAX_PAGES + 1) * 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_, fuse_mount(const char *mountpoint_,
struct fuse_args *args_) 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); 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* struct fuse*
@ -258,7 +254,8 @@ fuse_setup_common(int argc,
int *fd) int *fd)
{ {
struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_chan *ch;
int fuse_fd;
size_t bufsize;
struct fuse *fuse; struct fuse *fuse;
int foreground; int foreground;
int res; int res;
@ -267,13 +264,13 @@ fuse_setup_common(int argc,
if (res == -1) if (res == -1)
return NULL; 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); fuse_opt_free_args(&args);
goto err_free; goto err_free;
} }
fuse = fuse_new(ch, &args, op);
fuse = fuse_new(fuse_fd, bufsize, &args, op);
fuse_opt_free_args(&args); fuse_opt_free_args(&args);
if (fuse == NULL) if (fuse == NULL)
goto err_unmount; goto err_unmount;
@ -287,12 +284,12 @@ fuse_setup_common(int argc,
goto err_unmount; goto err_unmount;
if (fd) if (fd)
*fd = fuse_chan_fd(ch);
*fd = fuse_fd;
return fuse; return fuse;
err_unmount: err_unmount:
fuse_unmount_common(*mountpoint, ch);
fuse_unmount_common(*mountpoint, fuse_fd);
err_free: err_free:
free(*mountpoint); free(*mountpoint);
return NULL; return NULL;
@ -313,9 +310,12 @@ struct fuse *fuse_setup(int argc,
static void fuse_teardown_common(char *mountpoint) static void fuse_teardown_common(char *mountpoint)
{ {
struct fuse_session *se = fuse_get_session(); 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_remove_signal_handlers(se);
fuse_unmount_common(mountpoint, ch);
if (mountpoint && fd != -1) {
se->fd = -1;
fuse_kern_unmount(mountpoint, fd);
}
free(mountpoint); free(mountpoint);
} }

Loading…
Cancel
Save