Browse Source

Rework fuse read to use same buffers as messages

pull/1143/head
Antonio SJ Musumeci 1 year ago
parent
commit
373d331f39
  1. 8
      libfuse/include/fuse.h
  2. 16
      libfuse/include/fuse_lowlevel.h
  3. 111
      libfuse/lib/fuse.c
  4. 29
      libfuse/lib/fuse_lowlevel.c
  5. 38
      src/fs_pread.hpp
  6. 70
      src/fuse_read.cpp
  7. 16
      src/fuse_read.hpp
  8. 98
      src/fuse_read_buf.cpp
  9. 4
      src/mergerfs.cpp

8
libfuse/include/fuse.h

@ -482,10 +482,10 @@ struct fuse_operations
*
* Introduced in version 2.9
*/
int (*read_buf) (const fuse_file_info_t *ffi,
struct fuse_bufvec **bufp,
size_t size,
off_t off);
int (*read)(const fuse_file_info_t *ffi,
char *buf,
size_t size,
off_t off);
/**
* Perform BSD file locking operation
*

16
libfuse/include/fuse_lowlevel.h

@ -1137,19 +1137,9 @@ int fuse_reply_write(fuse_req_t req, size_t count);
*/
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size);
/**
* Reply with data copied/moved from buffer(s)
*
* Possible requests:
* read, readdir, getxattr, listxattr
*
* @param req request handle
* @param bufv buffer vector
* @param flags flags controlling the copy
* @return zero for success, -errno for failure to send reply
*/
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
enum fuse_buf_copy_flags flags);
int fuse_reply_data(fuse_req_t req,
char *buf,
size_t bufsize);
/**
* Reply with data vector

111
libfuse/lib/fuse.c

@ -23,6 +23,7 @@
#include "fuse_misc.h"
#include "fuse_opt.h"
#include "fuse_pollhandle.h"
#include "fuse_msgbuf.hpp"
#include <assert.h>
#include <dlfcn.h>
@ -1379,20 +1380,6 @@ req_fuse(fuse_req_t req)
return (struct fuse*)fuse_req_userdata(req);
}
static
void
fuse_free_buf(struct fuse_bufvec *buf)
{
if(buf != NULL)
{
size_t i;
for(i = 0; i < buf->count; i++)
free(buf->buf[i].mem);
free(buf);
}
}
static
int
node_open(const struct node *node_)
@ -1545,16 +1532,6 @@ req_fuse_prepare(fuse_req_t req)
return c->ctx.fuse;
}
static
inline
void
reply_err(fuse_req_t req,
int err)
{
/* fuse_reply_err() uses non-negated errno values */
fuse_reply_err(req,-err);
}
static
void
reply_entry(fuse_req_t req,
@ -1573,7 +1550,7 @@ reply_entry(fuse_req_t req,
}
else
{
reply_err(req,err);
fuse_reply_err(req,err);
}
}
@ -1770,7 +1747,7 @@ fuse_lib_getattr(fuse_req_t req,
}
else
{
reply_err(req,err);
fuse_reply_err(req,err);
}
}
@ -1893,7 +1870,7 @@ fuse_lib_setattr(fuse_req_t req,
}
else
{
reply_err(req,err);
fuse_reply_err(req,err);
}
}
@ -1918,7 +1895,7 @@ fuse_lib_access(fuse_req_t req,
free_path(f,hdr_->nodeid,path);
}
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -1947,7 +1924,7 @@ fuse_lib_readlink(fuse_req_t req,
}
else
{
reply_err(req,err);
fuse_reply_err(req,err);
}
}
@ -2068,7 +2045,7 @@ fuse_lib_unlink(fuse_req_t req,
free_path_wrlock(f,hdr_->nodeid,wnode,path);
}
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -2095,7 +2072,7 @@ fuse_lib_rmdir(fuse_req_t req,
free_path_wrlock(f,hdr_->nodeid,wnode,path);
}
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -2168,7 +2145,7 @@ fuse_lib_rename(fuse_req_t req,
free_path2(f,hdr_->nodeid,arg->newdir,wnode1,wnode2,oldpath,newpath);
}
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -2295,7 +2272,7 @@ fuse_lib_create(fuse_req_t req,
}
else
{
reply_err(req,err);
fuse_reply_err(req,err);
}
free_path(f,hdr_->nodeid,path);
@ -2376,7 +2353,7 @@ fuse_lib_open(fuse_req_t req,
}
else
{
reply_err(req,err);
fuse_reply_err(req,err);
}
free_path(f,hdr_->nodeid,path);
@ -2390,8 +2367,8 @@ fuse_lib_read(fuse_req_t req,
int res;
struct fuse *f;
fuse_file_info_t ffi = {0};
struct fuse_bufvec *buf = NULL;
struct fuse_read_in *arg;
fuse_msgbuf_t *msgbuf;
arg = fuse_hdr_arg(hdr_);
ffi.fh = arg->fh;
@ -2403,14 +2380,16 @@ fuse_lib_read(fuse_req_t req,
f = req_fuse_prepare(req);
res = f->fs->op.read_buf(&ffi,&buf,arg->size,arg->offset);
msgbuf = msgbuf_alloc();
res = f->fs->op.read(&ffi,msgbuf->mem,arg->size,arg->offset);
if(res >= 0)
fuse_reply_data(req,buf,FUSE_BUF_SPLICE_MOVE);
fuse_reply_data(req,msgbuf->mem,res);
else
reply_err(req,res);
fuse_reply_err(req,res);
fuse_free_buf(buf);
msgbuf_free(msgbuf);
}
static
@ -2446,7 +2425,7 @@ fuse_lib_write(fuse_req_t req,
if(res >= 0)
fuse_reply_write(req,res);
else
reply_err(req,res);
fuse_reply_err(req,res);
}
static
@ -2467,7 +2446,7 @@ fuse_lib_fsync(fuse_req_t req,
err = f->fs->op.fsync(&ffi,
!!(arg->fsync_flags & 1));
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -2502,7 +2481,7 @@ fuse_lib_opendir(fuse_req_t req,
dh = (struct fuse_dh *)calloc(1,sizeof(struct fuse_dh));
if(dh == NULL)
{
reply_err(req,-ENOMEM);
fuse_reply_err(req,ENOMEM);
return;
}
@ -2534,7 +2513,7 @@ fuse_lib_opendir(fuse_req_t req,
}
else
{
reply_err(req,err);
fuse_reply_err(req,err);
pthread_mutex_destroy(&dh->lock);
free(dh);
}
@ -2597,7 +2576,7 @@ fuse_lib_readdir(fuse_req_t req_,
if(rv)
{
reply_err(req_,rv);
fuse_reply_err(req_,rv);
goto out;
}
@ -2641,7 +2620,7 @@ fuse_lib_readdir_plus(fuse_req_t req_,
if(rv)
{
reply_err(req_,rv);
fuse_reply_err(req_,rv);
goto out;
}
@ -2681,7 +2660,7 @@ fuse_lib_releasedir(fuse_req_t req_,
pthread_mutex_destroy(&dh->lock);
fuse_dirents_free(&dh->d);
free(dh);
reply_err(req_,0);
fuse_reply_err(req_,0);
}
static
@ -2705,7 +2684,7 @@ fuse_lib_fsyncdir(fuse_req_t req,
err = f->fs->op.fsyncdir(&ffi,
!!(arg->fsync_flags & FUSE_FSYNC_FDATASYNC));
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -2732,7 +2711,7 @@ fuse_lib_statfs(fuse_req_t req,
if(!err)
fuse_reply_statfs(req,&buf);
else
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -2764,7 +2743,7 @@ fuse_lib_setxattr(fuse_req_t req,
free_path(f,hdr_->nodeid,path);
}
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -2810,7 +2789,7 @@ fuse_lib_getxattr(fuse_req_t req,
char *value = (char*)malloc(arg->size);
if(value == NULL)
{
reply_err(req,-ENOMEM);
fuse_reply_err(req,ENOMEM);
return;
}
@ -2818,7 +2797,7 @@ fuse_lib_getxattr(fuse_req_t req,
if(res > 0)
fuse_reply_buf(req,value,res);
else
reply_err(req,res);
fuse_reply_err(req,res);
free(value);
}
else
@ -2827,7 +2806,7 @@ fuse_lib_getxattr(fuse_req_t req,
if(res >= 0)
fuse_reply_xattr(req,res);
else
reply_err(req,res);
fuse_reply_err(req,res);
}
}
@ -2870,7 +2849,7 @@ fuse_lib_listxattr(fuse_req_t req,
char *list = (char*)malloc(arg->size);
if(list == NULL)
{
reply_err(req,-ENOMEM);
fuse_reply_err(req,ENOMEM);
return;
}
@ -2878,7 +2857,7 @@ fuse_lib_listxattr(fuse_req_t req,
if(res > 0)
fuse_reply_buf(req,list,res);
else
reply_err(req,res);
fuse_reply_err(req,res);
free(list);
}
else
@ -2887,7 +2866,7 @@ fuse_lib_listxattr(fuse_req_t req,
if(res >= 0)
fuse_reply_xattr(req,res);
else
reply_err(req,res);
fuse_reply_err(req,res);
}
}
@ -2912,7 +2891,7 @@ fuse_lib_removexattr(fuse_req_t req,
free_path(f,hdr_->nodeid,path);
}
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -2942,7 +2921,7 @@ fuse_lib_copy_file_range(fuse_req_t req_,
if(rv >= 0)
fuse_reply_write(req_,rv);
else
reply_err(req_,rv);
fuse_reply_err(req_,rv);
}
static
@ -3157,7 +3136,7 @@ fuse_lib_release(fuse_req_t req,
fuse_do_release(f,hdr_->nodeid,&ffi);
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -3181,7 +3160,7 @@ fuse_lib_flush(fuse_req_t req,
err = fuse_flush_common(f,req,hdr_->nodeid,&ffi);
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -3252,7 +3231,7 @@ fuse_lib_getlk(fuse_req_t req,
if(!err)
fuse_reply_lock(req,&flk);
else
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -3276,7 +3255,7 @@ fuse_lib_setlk(fuse_req_t req,
pthread_mutex_unlock(&f->lock);
}
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -3291,7 +3270,7 @@ fuse_lib_flock(fuse_req_t req,
err = f->fs->op.flock(fi,op);
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -3320,7 +3299,7 @@ fuse_lib_bmap(fuse_req_t req,
if(!err)
fuse_reply_bmap(req,block);
else
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -3388,7 +3367,7 @@ fuse_lib_ioctl(fuse_req_t req,
fuse_reply_ioctl(req,err,out_buf,out_size);
goto out;
err:
reply_err(req,err);
fuse_reply_err(req,err);
out:
free(out_buf);
}
@ -3427,7 +3406,7 @@ fuse_lib_poll(fuse_req_t req,
if(!err)
fuse_reply_poll(req,revents);
else
reply_err(req,err);
fuse_reply_err(req,err);
}
static
@ -3450,7 +3429,7 @@ fuse_lib_fallocate(fuse_req_t req,
arg->offset,
arg->length);
reply_err(req,err);
fuse_reply_err(req,err);
}
static

29
libfuse/lib/fuse_lowlevel.c

@ -146,6 +146,8 @@ fuse_send_msg(struct fuse_ll *f,
return 0;
}
#define MAX_ERRNO 4095
int
fuse_send_reply_iov_nofree(fuse_req_t req,
int error,
@ -154,17 +156,20 @@ fuse_send_reply_iov_nofree(fuse_req_t req,
{
struct fuse_out_header out;
if(error <= -1000 || error > 0)
if(error > 0)
error = -error;
if(error <= -MAX_ERRNO)
{
fprintf(stderr, "fuse: bad error value: %i\n",error);
fprintf(stderr,"fuse: bad error value: %i\n",error);
error = -ERANGE;
}
out.unique = req->unique;
out.error = error;
out.error = error;
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->f, req->ch, iov, count);
}
@ -231,7 +236,7 @@ int
fuse_reply_err(fuse_req_t req_,
int err_)
{
return send_reply(req_,-err_,NULL,0);
return send_reply(req_,err_,NULL,0);
}
void
@ -445,21 +450,23 @@ fuse_send_data_iov(struct fuse_ll *f,
}
int
fuse_reply_data(fuse_req_t req,
struct fuse_bufvec *bufv,
enum fuse_buf_copy_flags flags)
fuse_reply_data(fuse_req_t req,
char *buf_,
const size_t bufsize_)
{
int res;
struct iovec iov[2];
struct fuse_out_header out;
int res;
iov[0].iov_base = &out;
iov[0].iov_len = sizeof(struct fuse_out_header);
iov[0].iov_len = sizeof(struct fuse_out_header);
iov[1].iov_base = buf_;
iov[1].iov_len = bufsize_;
out.unique = req->unique;
out.error = 0;
res = fuse_send_data_iov(req->f, req->ch, iov, 1, bufv, flags);
res = fuse_send_msg(req->f,req->ch,iov,2);
if(res <= 0)
{
destroy_req(req);

38
src/fs_pread.hpp

@ -0,0 +1,38 @@
/*
ISC License
Copyright (c) 2023, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
#include <unistd.h>
namespace fs
{
static
int
pread(const int fd_,
void *buf_,
const size_t count_,
const off_t offset_)
{
int rv;
rv = ::pread(fd_,buf_,count_,offset_);
return ((rv == -1) ? -errno : rv);
}
}

70
src/fuse_read.cpp

@ -0,0 +1,70 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "errno.hpp"
#include "fileinfo.hpp"
#include "fs_pread.hpp"
#include "fuse.h"
#include <stdlib.h>
#include <string.h>
typedef struct fuse_bufvec fuse_bufvec;
namespace l
{
static
int
read(const int fd_,
char *buf_,
const size_t size_,
const off_t offset_)
{
int rv;
rv = fs::pread(fd_,buf_,size_,offset_);
return rv;
}
}
namespace FUSE
{
int
read(const fuse_file_info_t *ffi_,
char *buf_,
size_t size_,
off_t offset_)
{
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh);
return l::read(fi->fd,
buf_,
size_,
offset_);
}
int
read_null(const fuse_file_info_t *ffi_,
char *buf_,
size_t size_,
off_t offset_)
{
return size_;
}
}

16
src/fuse_read_buf.hpp → src/fuse_read.hpp

@ -24,14 +24,14 @@
namespace FUSE
{
int
read_buf(const fuse_file_info_t *ffi,
struct fuse_bufvec **buf,
size_t size,
off_t offset);
read(const fuse_file_info_t *ffi,
char *buf,
size_t size,
off_t offset);
int
read_buf_null(const fuse_file_info_t *ffi,
struct fuse_bufvec **buf,
size_t size,
off_t offset);
read_null(const fuse_file_info_t *ffi,
char *buf,
size_t size,
off_t offset);
}

98
src/fuse_read_buf.cpp

@ -1,98 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "errno.hpp"
#include "fileinfo.hpp"
#include "fuse.h"
#include <stdlib.h>
#include <string.h>
typedef struct fuse_bufvec fuse_bufvec;
namespace l
{
static
int
read_buf(const int fd_,
fuse_bufvec **bufp_,
const size_t size_,
const off_t offset_)
{
fuse_bufvec *src;
src = (fuse_bufvec*)malloc(sizeof(fuse_bufvec));
if(src == NULL)
return -ENOMEM;
*src = FUSE_BUFVEC_INIT(size_);
src->buf->flags = (fuse_buf_flags)(FUSE_BUF_IS_FD|FUSE_BUF_FD_SEEK|FUSE_BUF_FD_RETRY);
src->buf->fd = fd_;
src->buf->pos = offset_;
*bufp_ = src;
return 0;
}
}
namespace FUSE
{
int
read_buf(const fuse_file_info_t *ffi_,
fuse_bufvec **bufp_,
size_t size_,
off_t offset_)
{
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh);
return l::read_buf(fi->fd,
bufp_,
size_,
offset_);
}
int
read_buf_null(const fuse_file_info_t *ffi_,
fuse_bufvec **bufp_,
size_t size_,
off_t offset_)
{
void *mem;
struct fuse_bufvec *buf;
buf = (struct fuse_bufvec*)malloc(sizeof(struct fuse_bufvec));
if(buf == NULL)
return -ENOMEM;
mem = (void*)calloc(1,size_);
if(mem == NULL)
{
free(buf);
return -ENOMEM;
}
*buf = FUSE_BUFVEC_INIT(size_);
buf->buf[0].mem = mem;
*bufp_ = buf;
return 0;
}
}

4
src/mergerfs.cpp

@ -56,7 +56,7 @@
#include "fuse_opendir.hpp"
#include "fuse_poll.hpp"
#include "fuse_prepare_hide.hpp"
#include "fuse_read_buf.hpp"
#include "fuse_read.hpp"
#include "fuse_readdir.hpp"
#include "fuse_readdir_plus.hpp"
#include "fuse_readlink.hpp"
@ -119,7 +119,7 @@ namespace l
ops_.opendir = FUSE::opendir;
ops_.poll = FUSE::poll;;
ops_.prepare_hide = FUSE::prepare_hide;
ops_.read_buf = (nullrw_ ? FUSE::read_buf_null : FUSE::read_buf);
ops_.read = (nullrw_ ? FUSE::read_null : FUSE::read);
ops_.readdir = FUSE::readdir;
ops_.readdir_plus = FUSE::readdir_plus;
ops_.readlink = FUSE::readlink;

Loading…
Cancel
Save