From nobody Sun Apr 12 00:55:12 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1771535832; cv=none; d=zohomail.com; s=zohoarc; b=DD2N5Ct80WEQ5eMGTBYNIy8pUuiPCIDYFsjU/5YV92AgDnfsMANLG7zk7eMWmcfGr/k06Nli7YoVYSkuNah7o2X1LJRwpKU5DMlz4i9TVVBMaqM4zNdXmOBbjM1ZWo3QX1Iho4qlvj4T+rqW0980bj1hS+vUhVJpgWl3hnz+5pg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1771535832; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=S+5hQGGZywLI2PLtKdUE33CAXPAjE5523eM+4x4NpYA=; b=JHGKSeb2o6tUXNCY/Uog/7CkPSnQs6dvRmpNu3MMgLiEoeFaZ096Pn7kSDxrIcAnPyP383JFPu9EtEA7Kvo0ZuHl5CVjeegLwwlkYi/AuqGg692UhNE0+iCPpazioFD2YrC3rN/fL/YFfkYDIiFIlqSVzKPOLbuKn3jBeoQrCm0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1771535832176621.5649211197273; Thu, 19 Feb 2026 13:17:12 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vtBON-0005f9-0W; Thu, 19 Feb 2026 16:16:59 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vtBOJ-0005el-3o for qemu-devel@nongnu.org; Thu, 19 Feb 2026 16:16:55 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vtBOF-0005X8-1x for qemu-devel@nongnu.org; Thu, 19 Feb 2026 16:16:53 -0500 Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-523-n6m1cz2jMsaI_ciIZxuqRA-1; Thu, 19 Feb 2026 16:16:44 -0500 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6916418002DE; Thu, 19 Feb 2026 21:16:42 +0000 (UTC) Received: from localhost (unknown [10.2.16.138]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1251819560A7; Thu, 19 Feb 2026 21:16:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1771535808; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=S+5hQGGZywLI2PLtKdUE33CAXPAjE5523eM+4x4NpYA=; b=Rk59B3zttho3REOFj/XTG0cFTDsXq6wGeclWuFu+lFgyRBT+dTdUze7nKWKUWdtp+nmGzw aFeBV6+zte3erySeUvUZZHTfrfIsd2U2BGEkdC1bX7LIPlzljXkUcu8/epK5L4JMXOnh/o 2zQTZC5S6h0DrPN84m34OYodbcEPFto= X-MC-Unique: n6m1cz2jMsaI_ciIZxuqRA-1 X-Mimecast-MFC-AGG-ID: n6m1cz2jMsaI_ciIZxuqRA_1771535803 From: Stefan Hajnoczi To: Brian Song Cc: qemu-block@nongnu.org, qemu-devel@nongnu.org, hreitz@redhat.com, kwolf@redhat.com, eblake@redhat.com, armbru@redhat.com, fam@euphon.net, bernd@bsbernd.com, Stefan Hajnoczi Subject: [PATCH] fuse: unify op_in for io_uring and classic FUSE Date: Thu, 19 Feb 2026 16:14:00 -0500 Message-ID: <20260219211626.987027-1-stefanha@redhat.com> In-Reply-To: <96F8FC7D-C7B5-4346-8421-65173B0FAD1A@gmail.com> References: <96F8FC7D-C7B5-4346-8421-65173B0FAD1A@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=stefanha@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.045, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1771535833534154100 Content-Type: text/plain; charset="utf-8" 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 --- 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 lea= st * FUSE_MIN_READ_BUFFER (from linux/fuse.h) bytes. * This however is just the first part of the buffer; every read is gi= ven - * a vector of this buffer (which should be enough for all normal requ= ests, - * 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 requ= ests) * and the spill-over buffer below. * Therefore, the size of this buffer plus FUSE_SPILLOVER_BUF_SIZE mus= t 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, =20 /* * For use in fuse_co_process_request_common(): - * Returns a pointer to the parameter object for the given operation (insi= de 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 w= hole + * 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 =3D \ - (const struct fuse_in_header *)(queue)->request_buf; \ - const struct fuse_##op_name##_in *__in =3D \ - (const struct fuse_##op_name##_in *)(__in_hdr + 1); \ - const size_t __param_len =3D 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 =3D __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 =3D op_in; \ + const size_t __needed =3D 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 =3D -EINVAL; \ - __in =3D 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_com= mon( =20 switch (opcode) { case FUSE_INIT: { - FuseQueue *q =3D opaque; - const struct fuse_init_in *in =3D - FUSE_IN_OP_STRUCT_LEGACY(init, q); - if (!in) { - break; - } - + const struct fuse_init_in *in =3D FUSE_IN_OP_STRUCT(init); struct fuse_init_out *out =3D FUSE_OUT_OP_STRUCT_LEGACY(init, out_buf); =20 @@ -1898,19 +1883,12 @@ static void coroutine_fn fuse_co_process_request_co= mmon( } =20 case FUSE_SETATTR: { - const struct fuse_setattr_in *in; + const struct fuse_setattr_in *in =3D FUSE_IN_OP_STRUCT(setattr); struct fuse_attr_out *out; =20 if (exp->uring_started) { - in =3D in_buf; out =3D out_buf; } else { - FuseQueue *q =3D opaque; - in =3D FUSE_IN_OP_STRUCT_LEGACY(setattr, q); - if (!in) { - break; - } - out =3D FUSE_OUT_OP_STRUCT_LEGACY(attr, out_buf); } =20 @@ -1920,24 +1898,13 @@ static void coroutine_fn fuse_co_process_request_co= mmon( } =20 case FUSE_READ: { - const struct fuse_read_in *in; - - if (exp->uring_started) { - in =3D in_buf; - } else { - FuseQueue *q =3D opaque; - in =3D FUSE_IN_OP_STRUCT_LEGACY(read, q); - if (!in) { - break; - } - } - + const struct fuse_read_in *in =3D FUSE_IN_OP_STRUCT(read); ret =3D fuse_co_read(exp, &out_data_buffer, in->offset, in->size); break; } =20 case FUSE_WRITE: { - const struct fuse_write_in *in; + const struct fuse_write_in *in =3D 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_comm= on( if (exp->uring_started) { FuseUringEnt *ent =3D opaque; =20 - in =3D in_buf; out =3D out_buf; =20 assert(in->size <=3D ent->req_header.ring_ent_in_out.payload_s= z); @@ -1957,17 +1923,8 @@ static void coroutine_fn fuse_co_process_request_com= mon( in_place_buf =3D NULL; spill_buf =3D out_buf; } else { - FuseQueue *q =3D opaque; - in =3D FUSE_IN_OP_STRUCT_LEGACY(write, q); - if (!in) { - break; - } - - out =3D FUSE_OUT_OP_STRUCT_LEGACY(write, out_buf); - /* Additional check for WRITE: verify the request includes dat= a */ - uint32_t req_len =3D - ((const struct fuse_in_header *)(q->request_buf))->len; + out =3D FUSE_OUT_OP_STRUCT_LEGACY(write, out_buf); =20 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_com= mon( } =20 case FUSE_FALLOCATE: { - const struct fuse_fallocate_in *in; - - if (exp->uring_started) { - in =3D in_buf; - } else { - FuseQueue *q =3D opaque; - in =3D FUSE_IN_OP_STRUCT_LEGACY(fallocate, q); - if (!in) { - break; - } - } - + const struct fuse_fallocate_in *in =3D FUSE_IN_OP_STRUCT(fallocate= ); ret =3D fuse_co_fallocate(exp, in->offset, in->length, in->mode); break; } @@ -2028,19 +1974,12 @@ static void coroutine_fn fuse_co_process_request_co= mmon( =20 #ifdef CONFIG_FUSE_LSEEK case FUSE_LSEEK: { - const struct fuse_lseek_in *in; + const struct fuse_lseek_in *in =3D FUSE_IN_OP_STRUCT(lseek); struct fuse_lseek_out *out; =20 if (exp->uring_started) { - in =3D in_buf; out =3D out_buf; } else { - FuseQueue *q =3D opaque; - in =3D FUSE_IN_OP_STRUCT_LEGACY(lseek, q); - if (!in) { - break; - } - out =3D FUSE_OUT_OP_STRUCT_LEGACY(lseek, out_buf); } =20 @@ -2081,6 +2020,7 @@ static void coroutine_fn fuse_co_process_request_comm= on( } #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 =3D q->exp; + uint32_t req_len; uint32_t opcode; uint64_t req_id; + const void *op_in; =20 /* * Return buffer. Must be large enough to hold all return headers, bu= t does @@ -2134,12 +2076,15 @@ fuse_co_process_request(FuseQueue *q, void *spillov= er_buf) const struct fuse_in_header *in_hdr =3D (const struct fuse_in_header *)q->request_buf; =20 + req_len =3D in_hdr->len; opcode =3D in_hdr->opcode; req_id =3D in_hdr->unique; + op_in =3D in_hdr + 1; } =20 - fuse_co_process_request_common(exp, opcode, req_id, NULL, spillover_bu= f, - 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); } =20 #ifdef CONFIG_LINUX_IO_URING @@ -2196,6 +2141,7 @@ static void coroutine_fn fuse_uring_co_process_reques= t(FuseUringEnt *ent) (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out; struct fuse_in_header *in_hdr =3D (struct fuse_in_header *)&rrh->in_out; + uint32_t req_len =3D in_hdr->len; uint32_t opcode =3D in_hdr->opcode; uint64_t req_id =3D in_hdr->unique; =20 @@ -2208,7 +2154,7 @@ static void coroutine_fn fuse_uring_co_process_reques= t(FuseUringEnt *ent) return; } =20 - 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 */ --=20 2.53.0