aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/fuse_lowlevel.c70
-rw-r--r--lib/fuse_uring.c150
-rw-r--r--lib/fuse_uring_i.h29
3 files changed, 222 insertions, 27 deletions
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index d6b254e..03aeca7 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -227,21 +227,22 @@ static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
/*
* Send data to fuse-kernel using an fd of the fuse device.
*/
-static int _fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
- struct iovec *iov, int count)
+static int fuse_write_msg_dev(struct fuse_session *se, struct fuse_chan *ch,
+ struct iovec *iov, int count)
{
ssize_t res;
int err;
- if (se->io != NULL) {
+ if (se->io != NULL)
+
/* se->io->writev is never NULL if se->io is not NULL as
* specified by fuse_session_custom_io()
*/
res = se->io->writev(ch ? ch->fd : se->fd, iov, count,
se->userdata);
- } else {
+ else
res = writev(ch ? ch->fd : se->fd, iov, count);
- }
+
if (res == -1) {
/* ENOENT means the operation was interrupted */
err = errno;
@@ -253,15 +254,17 @@ static int _fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
return 0;
}
-/* Send data. If *ch* is NULL, send via session master fd */
static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
- struct iovec *iov, int count)
+ struct iovec *iov, int count, fuse_req_t req)
{
struct fuse_out_header *out = iov[0].iov_base;
int err;
+ bool is_uring = req && req->is_uring ? true : false;
- assert(se != NULL);
+ if (!is_uring)
+ assert(se != NULL);
out->len = iov_length(iov, count);
+
if (se->debug) {
if (out->unique == 0) {
fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n",
@@ -278,12 +281,15 @@ static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
}
}
- err = _fuse_send_msg(se, ch, iov, count);
+ if (is_uring)
+ err = fuse_send_msg_uring(req, iov, count);
+ else
+ err = fuse_write_msg_dev(se, ch, iov, count);
+
trace_request_reply(out->unique, out->len, out->error, err);
return err;
}
-
int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
int count)
{
@@ -305,7 +311,7 @@ int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
iov[0].iov_base = &out;
iov[0].iov_len = sizeof(struct fuse_out_header);
- return fuse_send_msg(req->se, req->ch, iov, count);
+ return fuse_send_msg(req->se, req->ch, iov, count, req);
}
static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
@@ -321,6 +327,9 @@ static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
static int send_reply(fuse_req_t req, int error, const void *arg,
size_t argsize)
{
+ if (req->is_uring)
+ return send_reply_uring(req, error, arg, argsize);
+
struct iovec iov[2];
int count = 1;
if (argsize) {
@@ -599,7 +608,7 @@ static int fuse_send_data_iov_fallback(struct fuse_session *se,
struct fuse_chan *ch,
struct iovec *iov, int iov_count,
struct fuse_bufvec *buf,
- size_t len)
+ size_t len, fuse_req_t req)
{
struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
void *mbuf;
@@ -614,7 +623,7 @@ static int fuse_send_data_iov_fallback(struct fuse_session *se,
iov[iov_count].iov_base = buf->buf[0].mem;
iov[iov_count].iov_len = len;
iov_count++;
- return fuse_send_msg(se, ch, iov, iov_count);
+ return fuse_send_msg(se, ch, iov, iov_count, req);
}
res = posix_memalign(&mbuf, pagesize, len);
@@ -632,7 +641,7 @@ static int fuse_send_data_iov_fallback(struct fuse_session *se,
iov[iov_count].iov_base = mbuf;
iov[iov_count].iov_len = len;
iov_count++;
- res = fuse_send_msg(se, ch, iov, iov_count);
+ res = fuse_send_msg(se, ch, iov, iov_count, req);
free(mbuf);
return res;
@@ -764,8 +773,9 @@ static int grow_pipe_to_max(int pipefd)
}
static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
- struct iovec *iov, int iov_count,
- struct fuse_bufvec *buf, unsigned int flags)
+ struct iovec *iov, int iov_count,
+ struct fuse_bufvec *buf, unsigned int flags,
+ fuse_req_t req)
{
int res;
size_t len = fuse_buf_size(buf);
@@ -917,7 +927,7 @@ static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
iov[iov_count].iov_base = mbuf;
iov[iov_count].iov_len = len;
iov_count++;
- res = fuse_send_msg(se, ch, iov, iov_count);
+ res = fuse_send_msg(se, ch, iov, iov_count, req);
free(mbuf);
return res;
}
@@ -964,17 +974,17 @@ clear_pipe:
return res;
fallback:
- return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
+ return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len, req);
}
#else
static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
struct iovec *iov, int iov_count,
- struct fuse_bufvec *buf, unsigned int flags)
+ struct fuse_bufvec *req_data, unsigned int flags)
{
- size_t len = fuse_buf_size(buf);
+ size_t len = fuse_buf_size(req_data);
(void) flags;
- return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
+ return fuse_send_data_iov_fallback(se, ch, iov, iov_count, req_data, len);
}
#endif
@@ -985,13 +995,16 @@ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
struct fuse_out_header out;
int res;
+ if (req->is_uring)
+ return fuse_reply_data_uring(req, bufv, flags);
+
iov[0].iov_base = &out;
iov[0].iov_len = sizeof(struct fuse_out_header);
out.unique = req->unique;
out.error = 0;
- res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
+ res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags, req);
if (res <= 0) {
fuse_free_req(req);
return res;
@@ -1743,8 +1756,8 @@ static void do_write_buf(fuse_req_t req, const fuse_ino_t nodeid,
sizeof(struct fuse_write_in);
}
if (bufv.buf[0].size < arg->size) {
- fuse_log(FUSE_LOG_ERR, "fuse: %s: buffer size too small\n",
- __func__);
+ fuse_log(FUSE_LOG_ERR,
+ "fuse: %s: buffer size too small\n", __func__);
fuse_reply_err(req, EIO);
goto out;
}
@@ -2576,6 +2589,7 @@ _do_init(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
FUSE_CAP_READDIRPLUS_AUTO);
+ LL_SET_DEFAULT(1, FUSE_CAP_OVER_IO_URING);
/* This could safely become default, but libfuse needs an API extension
* to support it
@@ -2840,6 +2854,7 @@ static int send_notify_iov(struct fuse_session *se, int notify_code,
struct iovec *iov, int count)
{
struct fuse_out_header out;
+ struct fuse_req *req = NULL;
if (!se->got_init)
return -ENOTCONN;
@@ -2849,7 +2864,7 @@ static int send_notify_iov(struct fuse_session *se, int notify_code,
iov[0].iov_base = &out;
iov[0].iov_len = sizeof(struct fuse_out_header);
- return fuse_send_msg(se, NULL, iov, count);
+ return fuse_send_msg(se, NULL, iov, count, req);
}
int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
@@ -2991,6 +3006,7 @@ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
struct iovec iov[3];
size_t size = fuse_buf_size(bufv);
int res;
+ struct fuse_req *req = NULL;
if (!se)
return -EINVAL;
@@ -3011,7 +3027,7 @@ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
iov[1].iov_base = &outarg;
iov[1].iov_len = sizeof(outarg);
- res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
+ res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags, req);
if (res > 0)
res = -res;
@@ -3392,7 +3408,7 @@ void fuse_session_process_buf_internal(struct fuse_session *se,
.iov_len = sizeof(struct fuse_out_header),
};
- fuse_send_msg(se, ch, &iov, 1);
+ fuse_send_msg(se, ch, &iov, 1, NULL);
goto clear_pipe;
}
diff --git a/lib/fuse_uring.c b/lib/fuse_uring.c
index 65ee987..55d68fa 100644
--- a/lib/fuse_uring.c
+++ b/lib/fuse_uring.c
@@ -141,6 +141,156 @@ fuse_uring_sqe_prepare(struct io_uring_sqe *sqe, struct fuse_ring_ent *req,
sqe->__pad1 = 0;
}
+static int fuse_uring_commit_sqe(struct fuse_ring_pool *ring_pool,
+ struct fuse_ring_queue *queue,
+ struct fuse_ring_ent *ring_ent)
+{
+ struct fuse_session *se = ring_pool->se;
+ struct fuse_uring_req_header *rrh = ring_ent->req_header;
+ struct fuse_out_header *out = (struct fuse_out_header *)&rrh->in_out;
+ struct fuse_uring_ent_in_out *ent_in_out =
+ (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out;
+ struct io_uring_sqe *sqe = io_uring_get_sqe(&queue->ring);
+
+ if (sqe == NULL) {
+ /* This is an impossible condition, unless there is a bug.
+ * The kernel sent back an SQEs, which is assigned to a request.
+ * There is no way to get out of SQEs, as the number of
+ * SQEs matches the number tof requests.
+ */
+
+ se->error = -EIO;
+ fuse_log(FUSE_LOG_ERR, "Failed to get a ring SQEs\n");
+
+ return -EIO;
+ }
+
+ fuse_uring_sqe_prepare(sqe, ring_ent,
+ FUSE_IO_URING_CMD_COMMIT_AND_FETCH);
+
+ fuse_uring_sqe_set_req_data(fuse_uring_get_sqe_cmd(sqe), queue->qid,
+ ring_ent->req_commit_id);
+
+ if (se->debug) {
+ fuse_log(FUSE_LOG_DEBUG, " unique: %llu, result=%d\n",
+ out->unique, ent_in_out->payload_sz);
+ }
+
+ /* XXX: This needs to be a ring config option */
+ io_uring_submit(&queue->ring);
+
+ return 0;
+}
+
+int send_reply_uring(fuse_req_t req, int error, const void *arg, size_t argsize)
+{
+ int res;
+ struct fuse_ring_ent *ring_ent =
+ container_of(req, struct fuse_ring_ent, req);
+ struct fuse_uring_req_header *rrh = ring_ent->req_header;
+ struct fuse_out_header *out = (struct fuse_out_header *)&rrh->in_out;
+ struct fuse_uring_ent_in_out *ent_in_out =
+ (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out;
+
+ struct fuse_ring_queue *queue = ring_ent->ring_queue;
+ struct fuse_ring_pool *ring_pool = queue->ring_pool;
+ size_t max_payload_sz = ring_pool->max_req_payload_sz;
+
+ if (argsize > max_payload_sz) {
+ fuse_log(FUSE_LOG_ERR, "argsize %zu exceeds buffer size %zu",
+ argsize, max_payload_sz);
+ error = -EINVAL;
+ } else if (argsize) {
+ memcpy(ring_ent->op_payload, arg, argsize);
+ }
+ ent_in_out->payload_sz = argsize;
+
+ out->error = error;
+ out->unique = req->unique;
+
+ res = fuse_uring_commit_sqe(ring_pool, queue, ring_ent);
+
+ fuse_free_req(req);
+
+ return res;
+}
+
+int fuse_reply_data_uring(fuse_req_t req, struct fuse_bufvec *bufv,
+ enum fuse_buf_copy_flags flags)
+{
+ struct fuse_ring_ent *ring_ent =
+ container_of(req, struct fuse_ring_ent, req);
+
+ struct fuse_ring_queue *queue = ring_ent->ring_queue;
+ struct fuse_ring_pool *ring_pool = queue->ring_pool;
+ struct fuse_uring_req_header *rrh = ring_ent->req_header;
+ struct fuse_out_header *out = (struct fuse_out_header *)&rrh->in_out;
+ struct fuse_uring_ent_in_out *ent_in_out =
+ (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out;
+ size_t max_payload_sz = ring_ent->req_payload_sz;
+ struct fuse_bufvec dest_vec = FUSE_BUFVEC_INIT(max_payload_sz);
+ int res;
+
+ dest_vec.buf[0].mem = ring_ent->op_payload;
+ dest_vec.buf[0].size = max_payload_sz;
+
+ res = fuse_buf_copy(&dest_vec, bufv, flags);
+
+ out->error = res < 0 ? res : 0;
+ out->unique = req->unique;
+
+ ent_in_out->payload_sz = res > 0 ? res : 0;
+
+ res = fuse_uring_commit_sqe(ring_pool, queue, ring_ent);
+
+ fuse_free_req(req);
+
+ return res;
+}
+
+/**
+ * Copy the iov into the ring buffer and submit and commit/fetch sqe
+ */
+int fuse_send_msg_uring(fuse_req_t req, struct iovec *iov, int count)
+{
+ struct fuse_ring_ent *ring_ent =
+ container_of(req, struct fuse_ring_ent, req);
+
+ struct fuse_ring_queue *queue = ring_ent->ring_queue;
+ struct fuse_ring_pool *ring_pool = queue->ring_pool;
+ struct fuse_uring_req_header *rrh = ring_ent->req_header;
+ struct fuse_out_header *out = (struct fuse_out_header *)&rrh->in_out;
+ struct fuse_uring_ent_in_out *ent_in_out =
+ (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out;
+ size_t max_buf = ring_pool->max_req_payload_sz;
+ size_t len = 0;
+ int res = 0;
+
+ /* copy iov into the payload, idx=0 is the header section */
+ for (int idx = 1; idx < count; idx++) {
+ struct iovec *cur = &iov[idx];
+
+ if (len + cur->iov_len > max_buf) {
+ fuse_log(FUSE_LOG_ERR,
+ "iov[%d] exceeds buffer size %zu",
+ idx, max_buf);
+ res = -EINVAL; /* Gracefully handle this? */
+ break;
+ }
+
+ memcpy(ring_ent->op_payload + len, cur->iov_base, cur->iov_len);
+ len += cur->iov_len;
+ }
+
+ ent_in_out->payload_sz = len;
+
+ out->error = res;
+ out->unique = req->unique;
+ out->len = len;
+
+ return fuse_uring_commit_sqe(ring_pool, queue, ring_ent);
+}
+
static int fuse_queue_setup_io_uring(struct io_uring *ring, size_t qid,
size_t depth, int fd, int evfd)
{
diff --git a/lib/fuse_uring_i.h b/lib/fuse_uring_i.h
index e9f2989..40cda5b 100644
--- a/lib/fuse_uring_i.h
+++ b/lib/fuse_uring_i.h
@@ -27,6 +27,12 @@ struct fuse_in_header;
int fuse_uring_start(struct fuse_session *se);
int fuse_uring_stop(struct fuse_session *se);
+int send_reply_uring(fuse_req_t req, int error, const void *arg,
+ size_t argsize);
+
+int fuse_reply_data_uring(fuse_req_t req, struct fuse_bufvec *bufv,
+ enum fuse_buf_copy_flags flags);
+int fuse_send_msg_uring(fuse_req_t req, struct iovec *iov, int count);
#else // HAVE_URING
@@ -40,6 +46,29 @@ static inline int fuse_uring_stop(struct fuse_session *se FUSE_VAR_UNUSED)
return -ENOTSUP;
}
+static inline int send_reply_uring(fuse_req_t req FUSE_VAR_UNUSED,
+ int error FUSE_VAR_UNUSED,
+ const void *arg FUSE_VAR_UNUSED,
+ size_t argsize FUSE_VAR_UNUSED)
+{
+ return -ENOTSUP;
+}
+
+static inline int
+fuse_reply_data_uring(fuse_req_t req FUSE_VAR_UNUSED,
+ struct fuse_bufvec *bufv FUSE_VAR_UNUSED,
+ enum fuse_buf_copy_flags flags FUSE_VAR_UNUSED)
+{
+ return -ENOTSUP;
+}
+
+static inline int fuse_send_msg_uring(fuse_req_t req FUSE_VAR_UNUSED,
+ struct iovec *iov FUSE_VAR_UNUSED,
+ int count FUSE_VAR_UNUSED)
+{
+ return -ENOTSUP;
+}
+
#endif // HAVE_URING
#endif // FUSE_URING_I_H_