block/export/fuse.c | 118 ++++++++++++-------------------------------- 1 file changed, 32 insertions(+), 86 deletions(-)
Handle the memory layout differences for op_in in
fuse_co_process_request_common()'s callers. This way it's not necessary
to check whether uring is started.
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
block/export/fuse.c | 118 ++++++++++++--------------------------------
1 file changed, 32 insertions(+), 86 deletions(-)
Hi Brian,
You mentioned that FUSE_IN_OP_STRUCT_LEGACY() is harder to eliminate so
I took a look at it this morning. This patch compiles but I have not
tested it.
If you like this approach, please include it in your series and write a
similar patch for FUSE_OUT_OP_STRUCT_LEGACY().
diff --git a/block/export/fuse.c b/block/export/fuse.c
index e5b753e717..d4f393c2eb 100644
--- a/block/export/fuse.c
+++ b/block/export/fuse.c
@@ -137,8 +137,7 @@ struct FuseQueue {
* The request buffer must be able to hold a full write, and/or at least
* FUSE_MIN_READ_BUFFER (from linux/fuse.h) bytes.
* This however is just the first part of the buffer; every read is given
- * a vector of this buffer (which should be enough for all normal requests,
- * which we check via the static assertion in FUSE_IN_OP_STRUCT_LEGACY())
+ * a vector of this buffer (which should be enough for all normal requests)
* and the spill-over buffer below.
* Therefore, the size of this buffer plus FUSE_SPILLOVER_BUF_SIZE must be
* FUSE_MIN_READ_BUFFER or more (checked via static assertion below).
@@ -1765,33 +1764,24 @@ static int fuse_write_buf_response(int fd, uint32_t req_id,
/*
* For use in fuse_co_process_request_common():
- * Returns a pointer to the parameter object for the given operation (inside of
- * in_buf, which is assumed to hold a fuse_in_header first).
- * Verifies that the object is complete (in_buf is large enough to hold it in
- * one piece, and the request length includes the whole object).
- * Only performs verification for legacy FUSE.
+ * Returns a pointer to the parameter object for the given operation.
+ * Verifies that the object is complete (the request length includes the whole
+ * object).
*
* Note that queue->request_buf may be overwritten after yielding, so the
* returned pointer must not be used across a function that may yield!
*/
-#define FUSE_IN_OP_STRUCT_LEGACY(op_name, queue) \
+#define FUSE_IN_OP_STRUCT(op_name) \
({ \
- const struct fuse_in_header *__in_hdr = \
- (const struct fuse_in_header *)(queue)->request_buf; \
- const struct fuse_##op_name##_in *__in = \
- (const struct fuse_##op_name##_in *)(__in_hdr + 1); \
- const size_t __param_len = sizeof(*__in_hdr) + sizeof(*__in); \
- \
- QEMU_BUILD_BUG_ON(sizeof((queue)->request_buf) < \
- (sizeof(struct fuse_in_header) + \
- sizeof(struct fuse_##op_name##_in))); \
- \
- uint32_t __req_len = __in_hdr->len; \
- if (__req_len < __param_len) { \
- warn_report("FUSE request truncated (%" PRIu32 " < %zu)", \
- __req_len, __param_len); \
+ const struct fuse_##op_name##_in *__in = op_in; \
+ const size_t __needed = sizeof(struct fuse_in_header) + \
+ sizeof(*__in); \
+ QEMU_BUILD_BUG_ON(sizeof(((FuseQueue *)0)->request_buf) < __needed); \
+ if (req_len < __needed) { \
+ warn_report("FUSE request with opcode %u truncated (%u < %zu)", \
+ opcode, req_len, __needed); \
ret = -EINVAL; \
- __in = NULL; \
+ break; \
} \
__in; \
})
@@ -1822,9 +1812,10 @@ static int fuse_write_buf_response(int fd, uint32_t req_id,
*/
static void coroutine_fn fuse_co_process_request_common(
FuseExport *exp,
+ uint32_t req_len,
uint32_t opcode,
uint64_t req_id,
- void *in_buf,
+ const void *op_in,
void *spillover_buf,
void *out_buf,
void (*send_response)(void *opaque, uint32_t req_id, int ret,
@@ -1849,13 +1840,7 @@ static void coroutine_fn fuse_co_process_request_common(
switch (opcode) {
case FUSE_INIT: {
- FuseQueue *q = opaque;
- const struct fuse_init_in *in =
- FUSE_IN_OP_STRUCT_LEGACY(init, q);
- if (!in) {
- break;
- }
-
+ const struct fuse_init_in *in = FUSE_IN_OP_STRUCT(init);
struct fuse_init_out *out =
FUSE_OUT_OP_STRUCT_LEGACY(init, out_buf);
@@ -1898,19 +1883,12 @@ static void coroutine_fn fuse_co_process_request_common(
}
case FUSE_SETATTR: {
- const struct fuse_setattr_in *in;
+ const struct fuse_setattr_in *in = FUSE_IN_OP_STRUCT(setattr);
struct fuse_attr_out *out;
if (exp->uring_started) {
- in = in_buf;
out = out_buf;
} else {
- FuseQueue *q = opaque;
- in = FUSE_IN_OP_STRUCT_LEGACY(setattr, q);
- if (!in) {
- break;
- }
-
out = FUSE_OUT_OP_STRUCT_LEGACY(attr, out_buf);
}
@@ -1920,24 +1898,13 @@ static void coroutine_fn fuse_co_process_request_common(
}
case FUSE_READ: {
- const struct fuse_read_in *in;
-
- if (exp->uring_started) {
- in = in_buf;
- } else {
- FuseQueue *q = opaque;
- in = FUSE_IN_OP_STRUCT_LEGACY(read, q);
- if (!in) {
- break;
- }
- }
-
+ const struct fuse_read_in *in = FUSE_IN_OP_STRUCT(read);
ret = fuse_co_read(exp, &out_data_buffer, in->offset, in->size);
break;
}
case FUSE_WRITE: {
- const struct fuse_write_in *in;
+ const struct fuse_write_in *in = FUSE_IN_OP_STRUCT(write);
struct fuse_write_out *out;
const void *in_place_buf;
const void *spill_buf;
@@ -1945,7 +1912,6 @@ static void coroutine_fn fuse_co_process_request_common(
if (exp->uring_started) {
FuseUringEnt *ent = opaque;
- in = in_buf;
out = out_buf;
assert(in->size <= ent->req_header.ring_ent_in_out.payload_sz);
@@ -1957,17 +1923,8 @@ static void coroutine_fn fuse_co_process_request_common(
in_place_buf = NULL;
spill_buf = out_buf;
} else {
- FuseQueue *q = opaque;
- in = FUSE_IN_OP_STRUCT_LEGACY(write, q);
- if (!in) {
- break;
- }
-
- out = FUSE_OUT_OP_STRUCT_LEGACY(write, out_buf);
-
/* Additional check for WRITE: verify the request includes data */
- uint32_t req_len =
- ((const struct fuse_in_header *)(q->request_buf))->len;
+ out = FUSE_OUT_OP_STRUCT_LEGACY(write, out_buf);
if (unlikely(req_len < sizeof(struct fuse_in_header) + sizeof(*in) +
in->size)) {
@@ -2002,18 +1959,7 @@ static void coroutine_fn fuse_co_process_request_common(
}
case FUSE_FALLOCATE: {
- const struct fuse_fallocate_in *in;
-
- if (exp->uring_started) {
- in = in_buf;
- } else {
- FuseQueue *q = opaque;
- in = FUSE_IN_OP_STRUCT_LEGACY(fallocate, q);
- if (!in) {
- break;
- }
- }
-
+ const struct fuse_fallocate_in *in = FUSE_IN_OP_STRUCT(fallocate);
ret = fuse_co_fallocate(exp, in->offset, in->length, in->mode);
break;
}
@@ -2028,19 +1974,12 @@ static void coroutine_fn fuse_co_process_request_common(
#ifdef CONFIG_FUSE_LSEEK
case FUSE_LSEEK: {
- const struct fuse_lseek_in *in;
+ const struct fuse_lseek_in *in = FUSE_IN_OP_STRUCT(lseek);
struct fuse_lseek_out *out;
if (exp->uring_started) {
- in = in_buf;
out = out_buf;
} else {
- FuseQueue *q = opaque;
- in = FUSE_IN_OP_STRUCT_LEGACY(lseek, q);
- if (!in) {
- break;
- }
-
out = FUSE_OUT_OP_STRUCT_LEGACY(lseek, out_buf);
}
@@ -2081,6 +2020,7 @@ static void coroutine_fn fuse_co_process_request_common(
}
#endif
}
+
/* Helper to send response for legacy */
static void send_response_legacy(void *opaque, uint32_t req_id, int ret,
const void *buf, void *out_buf)
@@ -2101,8 +2041,10 @@ static void coroutine_fn
fuse_co_process_request(FuseQueue *q, void *spillover_buf)
{
FuseExport *exp = q->exp;
+ uint32_t req_len;
uint32_t opcode;
uint64_t req_id;
+ const void *op_in;
/*
* Return buffer. Must be large enough to hold all return headers, but does
@@ -2134,12 +2076,15 @@ fuse_co_process_request(FuseQueue *q, void *spillover_buf)
const struct fuse_in_header *in_hdr =
(const struct fuse_in_header *)q->request_buf;
+ req_len = in_hdr->len;
opcode = in_hdr->opcode;
req_id = in_hdr->unique;
+ op_in = in_hdr + 1;
}
- fuse_co_process_request_common(exp, opcode, req_id, NULL, spillover_buf,
- out_buf, send_response_legacy, q);
+ fuse_co_process_request_common(exp, req_len, opcode, req_id, op_in,
+ spillover_buf, out_buf,
+ send_response_legacy, q);
}
#ifdef CONFIG_LINUX_IO_URING
@@ -2196,6 +2141,7 @@ static void coroutine_fn fuse_uring_co_process_request(FuseUringEnt *ent)
(struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out;
struct fuse_in_header *in_hdr =
(struct fuse_in_header *)&rrh->in_out;
+ uint32_t req_len = in_hdr->len;
uint32_t opcode = in_hdr->opcode;
uint64_t req_id = in_hdr->unique;
@@ -2208,7 +2154,7 @@ static void coroutine_fn fuse_uring_co_process_request(FuseUringEnt *ent)
return;
}
- fuse_co_process_request_common(exp, opcode, req_id, &rrh->op_in,
+ fuse_co_process_request_common(exp, req_len, opcode, req_id, &rrh->op_in,
NULL, ent->req_payload, send_response_uring, ent);
}
#endif /* CONFIG_LINUX_IO_URING */
--
2.53.0
© 2016 - 2026 Red Hat, Inc.