Remove write_buf, simplify FUSE msg dispatching

This commit is contained in:
Antonio SJ Musumeci 2022-11-08 23:43:59 -05:00
parent fea499e220
commit dba9c4451a
4 changed files with 75 additions and 280 deletions

View File

@ -234,8 +234,7 @@ struct fuse_lowlevel_ops
* @param ino the inode number
* @param fi for future use, currently always NULL
*/
void (*getattr)(fuse_req_t req, uint64_t ino,
fuse_file_info_t *fi);
void (*getattr)(fuse_req_t req, uint64_t ino, fuse_file_info_t *fi);
/**
* Set file attributes
@ -957,8 +956,10 @@ struct fuse_lowlevel_ops
* @param offset the offset supplied to fuse_lowlevel_notify_retrieve()
* @param bufv the buffer containing the returned data
*/
void (*retrieve_reply)(fuse_req_t req, void *cookie, uint64_t ino,
off_t offset, struct fuse_bufvec *bufv);
void (*retrieve_reply)(fuse_req_t req,
void *cookie,
uint64_t ino,
off_t offset);
/**
* Forget about multiple inodes

View File

@ -182,8 +182,7 @@ static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
}
while (len) {
res = splice(src->fd, srcpos, dst->fd, dstpos, len,
splice_flags);
res = splice(src->fd, srcpos, dst->fd, dstpos, len, splice_flags);
if (res == -1) {
if (copied)
break;

View File

@ -46,8 +46,7 @@ struct fuse_notify_req
void (*reply)(struct fuse_notify_req *,
fuse_req_t,
uint64_t,
const void *,
const struct fuse_buf *);
const void *);
struct fuse_notify_req *next;
struct fuse_notify_req *prev;
};

View File

@ -1296,58 +1296,6 @@ do_write(fuse_req_t req,
req->f->op.write(req,nodeid,param,arg->size,arg->offset,&fi);
}
static
void
do_write_buf(fuse_req_t req,
uint64_t nodeid,
const void *inarg,
const struct fuse_buf *ibuf)
{
struct fuse_ll *f = req->f;
struct fuse_bufvec bufv = {
.buf[0] = *ibuf,
.count = 1,
};
fuse_file_info_t fi = {0};
struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
fi.fh = arg->fh;
fi.writepage = arg->write_flags & 1;
if (req->f->conn.proto_minor < 9)
{
bufv.buf[0].mem = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
bufv.buf[0].size -= sizeof(struct fuse_in_header) +
FUSE_COMPAT_WRITE_IN_SIZE;
assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
}
else
{
fi.lock_owner = arg->lock_owner;
fi.flags = arg->flags;
if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
bufv.buf[0].mem = PARAM(arg);
bufv.buf[0].size -= sizeof(struct fuse_in_header) +
sizeof(struct fuse_write_in);
}
if (bufv.buf[0].size < arg->size)
{
fprintf(stderr, "fuse: do_write_buf: buffer size too small\n");
fuse_reply_err(req, EIO);
goto out;
}
bufv.buf[0].size = arg->size;
req->f->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
out:
/* Need to reset the pipe if ->write_buf() didn't consume all data */
if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
fuse_ll_clear_pipe(f);
}
static
void
do_flush(fuse_req_t req,
@ -1973,8 +1921,7 @@ static
void
do_notify_reply(fuse_req_t req,
uint64_t nodeid,
const void *inarg,
const struct fuse_buf *buf)
const void *inarg)
{
struct fuse_ll *f = req->f;
struct fuse_notify_req *nreq;
@ -1993,7 +1940,7 @@ do_notify_reply(fuse_req_t req,
pthread_mutex_unlock(&f->lock);
if(nreq != head)
nreq->reply(nreq, req, nodeid, inarg, buf);
nreq->reply(nreq, req, nodeid, inarg);
}
static
@ -2208,46 +2155,14 @@ void
fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
fuse_req_t req,
uint64_t ino,
const void *inarg,
const struct fuse_buf *ibuf)
const void *inarg)
{
struct fuse_ll *f = req->f;
struct fuse_retrieve_req *rreq =
container_of(nreq, struct fuse_retrieve_req, nreq);
const struct fuse_notify_retrieve_in *arg = inarg;
struct fuse_bufvec bufv = {
.buf[0] = *ibuf,
.count = 1,
};
if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
bufv.buf[0].mem = PARAM(arg);
bufv.buf[0].size -= sizeof(struct fuse_in_header) +
sizeof(struct fuse_notify_retrieve_in);
if (bufv.buf[0].size < arg->size)
{
fprintf(stderr, "fuse: retrieve reply: buffer size too small\n");
fuse_reply_none(req);
goto out;
}
bufv.buf[0].size = arg->size;
if (req->f->op.retrieve_reply)
{
req->f->op.retrieve_reply(req, rreq->cookie, ino,
arg->offset, &bufv);
}
else
{
fuse_reply_none(req);
}
out:
free(rreq);
if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
fuse_ll_clear_pipe(f);
}
int
@ -2362,34 +2277,13 @@ static struct {
[FUSE_POLL] = { do_poll, "POLL" },
[FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
[FUSE_DESTROY] = { do_destroy, "DESTROY" },
[FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" },
[FUSE_NOTIFY_REPLY] = { do_notify_reply, "NOTIFY_REPLY" },
[FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
[FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
};
#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
static
int
fuse_ll_copy_from_pipe(struct fuse_bufvec *dst,
struct fuse_bufvec *src)
{
int res = fuse_buf_copy(dst, src, 0);
if (res < 0)
{
fprintf(stderr, "fuse: copy from pipe: %s\n", strerror(-res));
return res;
}
if (res < fuse_buf_size(dst))
{
fprintf(stderr, "fuse: copy from pipe: short read\n");
return -1;
}
return 0;
}
static
void
fuse_ll_process_buf(void *data,
@ -2397,40 +2291,12 @@ fuse_ll_process_buf(void *data,
struct fuse_chan *ch)
{
struct fuse_ll *f = (struct fuse_ll*)data;
const size_t write_header_size = sizeof(struct fuse_in_header) +
sizeof(struct fuse_write_in);
struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size);
struct fuse_in_header *in;
const void *inarg;
struct fuse_req *req;
void *mbuf = NULL;
int err;
int res;
if (buf->flags & FUSE_BUF_IS_FD)
{
if (buf->size < tmpbuf.buf[0].size)
tmpbuf.buf[0].size = buf->size;
mbuf = malloc(tmpbuf.buf[0].size);
if (mbuf == NULL)
{
fprintf(stderr, "fuse: failed to allocate header\n");
goto clear_pipe;
}
tmpbuf.buf[0].mem = mbuf;
res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
if (res < 0)
goto clear_pipe;
in = mbuf;
}
else
{
in = buf->mem;
}
req = fuse_ll_alloc_req(f);
if(req == NULL)
@ -2445,7 +2311,7 @@ fuse_ll_process_buf(void *data,
};
fuse_send_msg(f, ch, &iov, 1);
goto clear_pipe;
return;
}
req->unique = in->unique;
@ -2469,50 +2335,17 @@ fuse_ll_process_buf(void *data,
}
err = ENOSYS;
if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
if(in->opcode >= FUSE_MAXOP)
goto reply_err;
if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size &&
(in->opcode != FUSE_WRITE || !f->op.write_buf) &&
in->opcode != FUSE_NOTIFY_REPLY)
{
void *newmbuf;
err = ENOMEM;
newmbuf = realloc(mbuf, buf->size);
if (newmbuf == NULL)
goto reply_err;
mbuf = newmbuf;
tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size);
tmpbuf.buf[0].mem = mbuf + write_header_size;
res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
err = -res;
if (res < 0)
goto reply_err;
in = mbuf;
}
inarg = (void*)&in[1];
if (in->opcode == FUSE_WRITE)
do_write_buf(req, in->nodeid, inarg, buf);
else if (in->opcode == FUSE_NOTIFY_REPLY)
do_notify_reply(req, in->nodeid, inarg, buf);
else
fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
out_free:
free(mbuf);
return;
reply_err:
fuse_reply_err(req, err);
clear_pipe:
if (buf->flags & FUSE_BUF_IS_FD)
fuse_ll_clear_pipe(f);
goto out_free;
return;
}
enum {
@ -2643,7 +2476,6 @@ fuse_ll_receive_buf(struct fuse_session *se,
struct fuse_ll *f = fuse_session_data(se);
size_t bufsize = buf->size;
struct fuse_ll_pipe *llp;
struct fuse_buf tmpbuf;
int err;
int res;
@ -2670,7 +2502,7 @@ fuse_ll_receive_buf(struct fuse_session *se,
goto fallback;
}
res = splice(fuse_chan_fd(se->ch), NULL, llp->pipe[1], NULL, bufsize, 0);
res = splice(fuse_chan_fd(se->ch), NULL, llp->pipe[1], NULL, bufsize, SPLICE_F_MOVE);
err = errno;
if(fuse_session_exited(se))
@ -2696,49 +2528,13 @@ fuse_ll_receive_buf(struct fuse_session *se,
return -EIO;
}
tmpbuf = (struct fuse_buf) {
.size = res,
.flags = FUSE_BUF_IS_FD,
.fd = llp->pipe[0],
};
/*
* Don't bother with zero copy for small requests.
* fuse_loop_mt() needs to check for FORGET so this more than
* just an optimization.
*/
if (res < sizeof(struct fuse_in_header) +
sizeof(struct fuse_write_in) + pagesize)
{
struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 };
struct fuse_bufvec dst = { .buf[0] = *buf, .count = 1 };
res = fuse_buf_copy(&dst, &src, 0);
if (res < 0) {
fprintf(stderr, "fuse: copy from pipe: %s\n",
strerror(-res));
fuse_ll_clear_pipe(f);
return res;
}
if (res < tmpbuf.size)
{
fprintf(stderr, "fuse: copy from pipe: short read\n");
fuse_ll_clear_pipe(f);
return -EIO;
}
buf->size = tmpbuf.size;
return buf->size;
}
*buf = tmpbuf;
struct iovec iov = { buf->mem, res };
res = vmsplice(llp->pipe[0], &iov, 1, 0);
return res;
fallback:
res = fuse_chan_recv(se->ch, buf->mem, bufsize);
res = fuse_chan_recv(se->ch, buf->mem, buf->size);
if(res <= 0)
return res;
@ -2752,9 +2548,9 @@ int
fuse_ll_receive_buf(struct fuse_session *se,
struct fuse_buf *buf)
{
(void) se;
int res;
int res = fuse_chan_recv(se->ch, buf->mem, buf->size);
res = fuse_chan_recv(se->ch, buf->mem, buf->size);
if(res <= 0)
return res;