Add support for FUSE passthrough
Some checks are pending
CodeQL / Analyze (push) Waiting to run
mkdocs / deploy (push) Waiting to run

This commit is contained in:
trapexit 2025-06-05 23:47:42 -05:00 • committed by GitHub
parent 92312c8507
commit e310d24615
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
412 changed files with 43707 additions and 17432 deletions

View file

@ -37,7 +37,6 @@
#include <inttypes.h>
#include <limits.h>
#include <poll.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@ -45,6 +44,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/time.h>
@ -364,9 +364,6 @@ free_node(struct fuse *f_,
{
filename_free(f_,node_->name);
if(node_->hidden_fh)
f_->fs->op.free_hide(node_->hidden_fh);
node_free(node_);
}
@ -938,8 +935,8 @@ try_get_path2(struct fuse *f,
const char *name2,
char **path1,
char **path2,
node_t **wnode1,
node_t **wnode2)
node_t **wnode1,
node_t **wnode2)
{
int err;
@ -1160,7 +1157,7 @@ static
void
free_path_wrlock(struct fuse *f,
uint64_t nodeid,
node_t *wnode,
node_t *wnode,
char *path)
{
mutex_lock(&f->lock);
@ -1408,7 +1405,7 @@ lookup_path(struct fuse *f,
rv = ((fi == NULL) ?
f->fs->op.getattr(path,&e->attr,&e->timeout) :
f->fs->op.fgetattr(fi,&e->attr,&e->timeout));
f->fs->op.fgetattr(fi->fh,&e->attr,&e->timeout));
if(rv)
return rv;
@ -1487,14 +1484,19 @@ static
struct fuse*
req_fuse_prepare(fuse_req_t req)
{
struct fuse_context_i *c = fuse_get_context_internal();
struct fuse_context_i *c = fuse_get_context_internal();
const struct fuse_ctx *ctx = fuse_req_ctx(req);
c->req = req;
c->ctx.fuse = req_fuse(req);
c->ctx.uid = ctx->uid;
c->ctx.gid = ctx->gid;
c->ctx.pid = ctx->pid;
c->ctx.umask = ctx->umask;
c->req = req;
c->ctx.fuse = req_fuse(req);
c->ctx.opcode = ctx->opcode;
c->ctx.unique = ctx->unique;
c->ctx.nodeid = ctx->nodeid;
c->ctx.uid = ctx->uid;
c->ctx.gid = ctx->gid;
c->ctx.pid = ctx->pid;
c->ctx.umask = ctx->umask;
return c->ctx.fuse;
}
@ -1672,41 +1674,36 @@ fuse_lib_getattr(fuse_req_t req,
{
int err;
char *path;
uint64_t fh;
struct fuse *f;
struct stat buf;
node_t *node;
fuse_timeouts_t timeout;
fuse_file_info_t ffi = {0};
const struct fuse_getattr_in *arg;
arg = (fuse_getattr_in*)fuse_hdr_arg(hdr_);
f = req_fuse_prepare(req);
fh = 0;
if(arg->getattr_flags & FUSE_GETATTR_FH)
{
ffi.fh = arg->fh;
}
else
{
mutex_lock(&f->lock);
node = get_node(f,hdr_->nodeid);
if(node->hidden_fh)
ffi.fh = node->hidden_fh;
mutex_unlock(&f->lock);
}
fh = arg->fh;
memset(&buf,0,sizeof(buf));
err = 0;
path = NULL;
if(ffi.fh == 0)
err = get_path(f,hdr_->nodeid,&path);
if(fh == 0)
{
err = get_path(f,hdr_->nodeid,&path);
if(err == -ESTALE) // unlinked but open
err = 0;
}
if(!err)
{
err = ((ffi.fh == 0) ?
err = ((path != NULL) ?
f->fs->op.getattr(path,&buf,&timeout) :
f->fs->op.fgetattr(&ffi,&buf,&timeout));
f->fs->op.fgetattr(fh,&buf,&timeout));
free_path(f,hdr_->nodeid,path);
}
@ -1738,6 +1735,7 @@ fuse_lib_statx_path(fuse_req_t req_,
struct fuse_statx st{};
fuse_timeouts_t timeouts{};
// TODO: if node unlinked... but FUSE may not send it
err = get_path(f_,hdr_->nodeid,&fusepath);
if(err)
{
@ -1803,63 +1801,51 @@ void
fuse_lib_setattr(fuse_req_t req,
struct fuse_in_header *hdr_)
{
uint64_t fh;
struct fuse *f = req_fuse_prepare(req);
struct stat stbuf = {0};
char *path;
int err;
node_t *node;
fuse_timeouts_t timeout;
fuse_file_info_t *fi;
fuse_file_info_t ffi = {0};
struct fuse_setattr_in *arg;
arg = (fuse_setattr_in*)fuse_hdr_arg(hdr_);
fi = NULL;
fh = 0;
if(arg->valid & FATTR_FH)
{
fi = &ffi;
fi->fh = arg->fh;
}
else
{
mutex_lock(&f->lock);
node = get_node(f,hdr_->nodeid);
if(node->hidden_fh)
{
fi = &ffi;
fi->fh = node->hidden_fh;
}
mutex_unlock(&f->lock);
}
fh = arg->fh;
err = 0;
path = NULL;
if(fi == NULL)
err = get_path(f,hdr_->nodeid,&path);
if(fh == 0)
{
err = get_path(f,hdr_->nodeid,&path);
if(err == -ESTALE)
err = 0;
}
if(!err)
{
err = 0;
if(!err && (arg->valid & FATTR_MODE))
err = ((fi == NULL) ?
err = ((path != NULL) ?
f->fs->op.chmod(path,arg->mode) :
f->fs->op.fchmod(fi,arg->mode));
f->fs->op.fchmod(fh,arg->mode));
if(!err && (arg->valid & (FATTR_UID | FATTR_GID)))
{
uid_t uid = ((arg->valid & FATTR_UID) ? arg->uid : (uid_t)-1);
gid_t gid = ((arg->valid & FATTR_GID) ? arg->gid : (gid_t)-1);
err = ((fi == NULL) ?
err = ((path != NULL) ?
f->fs->op.chown(path,uid,gid) :
f->fs->op.fchown(fi,uid,gid));
f->fs->op.fchown(fh,uid,gid));
}
if(!err && (arg->valid & FATTR_SIZE))
err = ((fi == NULL) ?
err = ((path != NULL) ?
f->fs->op.truncate(path,arg->size) :
f->fs->op.ftruncate(fi,arg->size));
f->fs->op.ftruncate(fh,arg->size));
#ifdef HAVE_UTIMENSAT
if(!err && (arg->valid & (FATTR_ATIME | FATTR_MTIME)))
@ -1881,9 +1867,9 @@ fuse_lib_setattr(fuse_req_t req,
else if(arg->valid & FATTR_MTIME)
tv[1] = (struct timespec){ static_cast<time_t>(arg->mtime), arg->mtimensec };
err = ((fi == NULL) ?
err = ((path != NULL) ?
f->fs->op.utimens(path,tv) :
f->fs->op.futimens(fi,tv));
f->fs->op.futimens(fh,tv));
}
else
#endif
@ -1894,15 +1880,15 @@ fuse_lib_setattr(fuse_req_t req,
tv[0].tv_nsec = arg->atimensec;
tv[1].tv_sec = arg->mtime;
tv[1].tv_nsec = arg->mtimensec;
err = ((fi == NULL) ?
err = ((path != NULL) ?
f->fs->op.utimens(path,tv) :
f->fs->op.futimens(fi,tv));
f->fs->op.futimens(fh,tv));
}
if(!err)
err = ((fi == NULL) ?
err = ((path != NULL) ?
f->fs->op.getattr(path,&stbuf,&timeout) :
f->fs->op.fgetattr(fi,&stbuf,&timeout));
f->fs->op.fgetattr(fh,&stbuf,&timeout));
free_path(f,hdr_->nodeid,path);
}
@ -2076,10 +2062,8 @@ fuse_lib_unlink(fuse_req_t req,
if(!err)
{
mutex_lock(&f->lock);
if(node_open(wnode))
err = f->fs->op.prepare_hide(path,&wnode->hidden_fh);
mutex_unlock(&f->lock);
fuse_get_context()->nodeid = wnode->nodeid;
err = f->fs->op.unlink(path);
if(!err)
@ -2172,11 +2156,6 @@ fuse_lib_rename(fuse_req_t req,
if(!err)
{
mutex_lock(&f->lock);
if(node_open(wnode2))
err = f->fs->op.prepare_hide(newpath,&wnode2->hidden_fh);
mutex_unlock(&f->lock);
err = f->fs->op.rename(oldpath,newpath);
if(!err)
err = rename_node(f,hdr_->nodeid,oldname,arg->newdir,newname);
@ -2244,11 +2223,8 @@ fuse_do_release(struct fuse *f,
uint64_t ino,
fuse_file_info_t *fi)
{
uint64_t fh;
node_t *node;
fh = 0;
f->fs->op.release(fi);
mutex_lock(&f->lock);
@ -2256,17 +2232,8 @@ fuse_do_release(struct fuse *f,
node = get_node(f,ino);
assert(node->open_count > 0);
node->open_count--;
if(node->hidden_fh && (node->open_count == 0))
{
fh = node->hidden_fh;
node->hidden_fh = 0;
}
}
mutex_unlock(&f->lock);
if(fh)
f->fs->op.free_hide(fh);
}
static
@ -2278,6 +2245,7 @@ fuse_lib_create(fuse_req_t req,
char *path;
struct fuse *f;
const char *name;
uint64_t new_nodeid;
fuse_file_info_t ffi = {0};
struct fuse_entry_param e;
struct fuse_create_in *arg;
@ -2294,6 +2262,14 @@ fuse_lib_create(fuse_req_t req,
f = req_fuse_prepare(req);
// opportunistically allocate a node so we have a new nodeid for
// later in the actual create. Added for use with passthrough.
{
node_t *node = find_node(f,hdr_->nodeid,name);
new_nodeid = node->nodeid;
fuse_get_context()->nodeid = new_nodeid;
}
err = get_path_name(f,hdr_->nodeid,name,&path);
if(!err)
{
@ -2330,6 +2306,7 @@ fuse_lib_create(fuse_req_t req,
}
else
{
forget_node(f,new_nodeid,1);
fuse_reply_err(req,err);
}
@ -2355,7 +2332,7 @@ open_auto_cache(struct fuse *f,
struct stat stbuf;
mutex_unlock(&f->lock);
err = f->fs->op.fgetattr(fi,&stbuf,&timeout);
err = f->fs->op.fgetattr(fi->fh,&stbuf,&timeout);
mutex_lock(&f->lock);
if(!err)
@ -2494,14 +2471,12 @@ fuse_lib_fsync(fuse_req_t req,
int err;
struct fuse *f;
struct fuse_fsync_in *arg;
fuse_file_info_t ffi = {0};
arg = (fuse_fsync_in*)fuse_hdr_arg(hdr_);
ffi.fh = arg->fh;
f = req_fuse_prepare(req);
err = f->fs->op.fsync(&ffi,
err = f->fs->op.fsync(arg->fh,
!!(arg->fsync_flags & 1));
fuse_reply_err(req,err);
@ -3569,15 +3544,13 @@ fuse_lib_fallocate(fuse_req_t req,
{
int err;
struct fuse *f;
fuse_file_info_t ffi = {0};
const struct fuse_fallocate_in *arg;
arg = (fuse_fallocate_in*)fuse_hdr_arg(hdr_);
ffi.fh = arg->fh;
f = req_fuse_prepare(req);
err = f->fs->op.fallocate(&ffi,
err = f->fs->op.fallocate(arg->fh,
arg->mode,
arg->offset,
arg->length);
@ -4218,20 +4191,6 @@ fuse_destroy(struct fuse *f)
memset(c,0,sizeof(*c));
c->ctx.fuse = f;
for(i = 0; i < f->id_table.size; i++)
{
node_t *node;
for(node = f->id_table.array[i]; node != NULL; node = node->id_next)
{
if(!node->hidden_fh)
continue;
f->fs->op.free_hide(node->hidden_fh);
node->hidden_fh = 0;
}
}
}
for(i = 0; i < f->id_table.size; i++)
@ -4266,3 +4225,36 @@ fuse_log_metrics_get(void)
{
return g_LOG_METRICS;
}
int
fuse_get_dev_fuse_fd(const struct fuse_context *fc_)
{
return fuse_chan_fd(fc_->fuse->se->ch);
}
int
fuse_passthrough_open(const struct fuse_context *fc_,
const int fd_)
{
int rv;
int dev_fuse_fd;
struct fuse_backing_map bm = {0};
dev_fuse_fd = fuse_get_dev_fuse_fd(fc_);
bm.fd = fd_;
rv = ::ioctl(dev_fuse_fd,FUSE_DEV_IOC_BACKING_OPEN,&bm);
return rv;
}
int
fuse_passthrough_close(const struct fuse_context *fc_,
const int backing_id_)
{
int dev_fuse_fd;
dev_fuse_fd = fuse_get_dev_fuse_fd(fc_);
return ::ioctl(dev_fuse_fd,FUSE_DEV_IOC_BACKING_CLOSE,&backing_id_);
}