From nobody Sun Feb 8 21:32:23 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=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1770466226; cv=none; d=zohomail.com; s=zohoarc; b=iWJIVDHqK2alWpxLNCoVXCbYMG05VGq9asfY4MNrYglW2yDefqpXJvhASIzjicOVn4rPMxkVhLOUFusdjI712VW0/6qp4AOLu072aCJuW8oGZbDkymfDJBzFXGqnyO73GKpjMaWzRQiHVKj+wEj6XOdp9zkc/ar0N0wZHMRTO2g= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770466226; 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=e4M2Nh1IUiw+FQ6WAOCON1M0zDU5UgL7i/MkIz5UbV4=; b=ZPhb7d/pBnqf4pF2rqeIr1OzxBfZzo3CLGdFxjj7FfJvnuoTrUixLfrAa+tfJMX19NzJZeRQOPbRYItPFdZYrjHzh5r/kjeaqOJ/HFKJ4rpTbl7RwavCj9hR8hNupwIZNbI7+d3BDvM443EYq3SlBvGqJMiK8yg0OLqH62PPqR8= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1770466226875275.1479562767853; Sat, 7 Feb 2026 04:10:26 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1voh8S-00078q-0U; Sat, 07 Feb 2026 07:10:00 -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 1voh8L-00077H-KM for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:09:56 -0500 Received: from mail-pg1-x52b.google.com ([2607:f8b0:4864:20::52b]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1voh8I-0002sD-S3 for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:09:52 -0500 Received: by mail-pg1-x52b.google.com with SMTP id 41be03b00d2f7-c65822dead7so623327a12.3 for ; Sat, 07 Feb 2026 04:09:50 -0800 (PST) Received: from brian.. (n058152022104.netvigator.com. [58.152.22.104]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-354b30f899csm2178530a91.3.2026.02.07.04.09.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 07 Feb 2026 04:09:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770466189; x=1771070989; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=e4M2Nh1IUiw+FQ6WAOCON1M0zDU5UgL7i/MkIz5UbV4=; b=fAh9IUo6obh4peqbeE652PFvNnceDaL2872VPsRWyO9Vy2/8TJPWt/HqAF8n9F12uo e4e7ZosfXKLkADHceonW+e1I5YcGSlIuAWRBDZFzK+IaYTIjhaYzjAZsLugmsqpXCe4f r4M4DsW0YcsmieMD5Q4X6Xsco34hhkGMBImY4wUH5GKQDvoCzAoo4V6S1yIFPMA6ZR4H WIlVw16nYh5CSr/zTlprJmGNk7HDj0I6FGy7WD187v1d0oJjK78Jg5s5K20zT4c6QzPp 48mYmfYVHsHdDIkdetrd6ifMD1AtTQj97dufW5AqwNJ9kLIm57K/TzPy06Kq9Si+IWmE LuTQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770466189; x=1771070989; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=e4M2Nh1IUiw+FQ6WAOCON1M0zDU5UgL7i/MkIz5UbV4=; b=OnGUKON16ULZTA3y0W+4Raygtnm7CUzM3svL7d0xfTjQYPddKwmX/f8GnNWYiQd81V 4MF7KcMNFBvwqA0UCITUkbg6lKAR1s6+9HMkGqFWlJS/zmuzCvD6P5DmmQvPeW0SzMGL l4kwXmidHy0OfsRvbTdIGtAvaizQ3ltK3N4XOK+SGydI/SNmD1AxiApYSFIIDoYI4+Md lBw0P0wgr0PWzxXDFoqUW+WFW+NPy2j/SXIsekW1HLfiu7nVPdMk2w5ubfPuA/pxcw8r 8DssLZON8GfdHDRrpVUiFYpWEF0zdNu99hYIlDbH90QItRIM8EHEqXPmovdR6io20WQT 7xog== X-Gm-Message-State: AOJu0YyNNZrp8F+VVkgSgUKW3MSSPu0ZwGY44TXJvew+7cJY/nBW9kfN FeIDi19zdM0We0HacB2RQaXaERF3xdCn98Uu2H0mNSWgSlmmCDbEQSGb X-Gm-Gg: AZuq6aJHo9Pr0KcJA/qLvowXk5dcvoiVbIsfcLj85eFQJutVs/VdpZ+a0QF95TkPIoe qJMCGQ+mIuq4jCARdUPu0HqtoQvQDZCMK8obHrFBkDF37gWZxM9qIxLeclvaeLd8FujAksHF32L DDwUcdXXkwtRCWk1xU4D8v9NPilMCDTa8z6mcoaatMT8coyBlRJrGo2Z3clDABlUR0by74Bx7QY vfZMPHycONwkuFSAKRPvN8Njbq1Kk3CgfA7e19K1Xx5YOTi2R9/yjTL9ZL/KxVfiPDM38oolFbu dvRZxN5pn9YBV45XiADeNjyDr0BoEIxIT+OQsay4owFpNMPFNDfrRB1H/w/dvZ+KkVXqmty3CBV p9YlKWXrvahbwZ9u6zQhXcVZtZmBbyHATwUHivMAtlAlrW1Nj65ZpJNDAlZTBgJj0MEZlar21cL C1HvMZ2AGKvevdd7FN1cN3rp5osNM2OyxPYYG++Mf2FS9GUfQ= X-Received: by 2002:a17:90a:d40e:b0:354:ad98:7d1c with SMTP id 98e67ed59e1d1-354b3c80c20mr5315324a91.11.1770466189298; Sat, 07 Feb 2026 04:09:49 -0800 (PST) From: Brian Song To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, hibriansong@gmail.com, hreitz@redhat.com, kwolf@redhat.com, eblake@redhat.com, armbru@redhat.com, stefanha@redhat.com, fam@euphon.net, bernd@bsbernd.com Subject: [Patch v4 1/7] aio-posix: enable 128-byte SQEs Date: Sat, 7 Feb 2026 20:08:55 +0800 Message-ID: <20260207120901.17222-2-hibriansong@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260207120901.17222-1-hibriansong@gmail.com> References: <20260207120901.17222-1-hibriansong@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2607:f8b0:4864:20::52b; envelope-from=hibriansong@gmail.com; helo=mail-pg1-x52b.google.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, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=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 @gmail.com) X-ZM-MESSAGEID: 1770466229712154100 Content-Type: text/plain; charset="utf-8" This patch enables the IORING_SETUP_SQE128 flag during io_uring initialization to support the FUSE protocol requirements. The FUSE-over-io_uring implementation embeds a protocol-specific structure directly into the Submission Queue Entry (SQE) to pass metadata such as the queue ID and commit ID. Enabling SQE128 expands the SQE size to 128 bytes, providing 80 bytes of available command space. This ensures sufficient room for the FUSE headers and future protocol extensions. Suggested-by: Kevin Wolf Suggested-by: Stefan Hajnoczi Signed-off-by: Brian Song --- util/fdmon-io_uring.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/util/fdmon-io_uring.c b/util/fdmon-io_uring.c index d2433d1d99..e6efc8d8f7 100644 --- a/util/fdmon-io_uring.c +++ b/util/fdmon-io_uring.c @@ -452,10 +452,15 @@ static const FDMonOps fdmon_io_uring_ops =3D { void fdmon_io_uring_setup(AioContext *ctx, Error **errp) { int ret; + int flags; ctx->io_uring_fd_tag =3D NULL; - ret =3D io_uring_queue_init(FDMON_IO_URING_ENTRIES, &ctx->fdmon_io_uri= ng, 0); + /* Needed by FUSE-over-io_uring */ + flags =3D IORING_SETUP_SQE128; + + ret =3D io_uring_queue_init(FDMON_IO_URING_ENTRIES, + &ctx->fdmon_io_uring, flags); if (ret !=3D 0) { error_setg_errno(errp, -ret, "Failed to initialize io_uring"); return; -- 2.43.0 From nobody Sun Feb 8 21:32:23 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=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1770466227; cv=none; d=zohomail.com; s=zohoarc; b=ZjUx2JvpTUFhdTkVYU5G87EijVY8J9OHrTHGhsrprpUM39vm5yxntcZEzA/SOyYgWZP8ZWmHLDIZlyuNBEdL7E/AVB+uoaiAIwVdMY1FCLwl1SaQLC7sNYI7Xqmj+wElTp8njwW2S+wK5ApgM5p6cCWFOAic+73mWLA+9qabjGg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770466227; 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=Mn0RB42m9zsHgb+ce7030OB0UfjmmGHf633GU5gQoUo=; b=mvse4HElh5nYieUps3ACtyXfYxZ0PKfpmmlGn8UqxD2tu5wtix+9+VADEWL/cbmgTrE9JgS8cKFmC1Kg132nq4Ktxhx4rb+ebNqrwF0V5voPXn/WHsDe03t01Jkl7cGPMTMNyAGE07HBNpAMGJAzlu45z/AvGMmjAiXpcYs9URs= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1770466227197461.65212618014164; Sat, 7 Feb 2026 04:10:27 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1voh8S-000790-Bu; Sat, 07 Feb 2026 07:10:00 -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 1voh8Q-000783-6z for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:09:58 -0500 Received: from mail-pj1-x1034.google.com ([2607:f8b0:4864:20::1034]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1voh8M-0002sV-Nr for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:09:57 -0500 Received: by mail-pj1-x1034.google.com with SMTP id 98e67ed59e1d1-35621aa8c7fso132049a91.2 for ; Sat, 07 Feb 2026 04:09:54 -0800 (PST) Received: from brian.. (n058152022104.netvigator.com. [58.152.22.104]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-354b30f899csm2178530a91.3.2026.02.07.04.09.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 07 Feb 2026 04:09:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770466193; x=1771070993; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Mn0RB42m9zsHgb+ce7030OB0UfjmmGHf633GU5gQoUo=; b=eJfUJj05Pc8AxFXL/9BSj5LIRwOiLT2mPA7JeeMJH4ACXYsqkJOLIDR0H8h514IA9W ZFHdi0wz+X98A8thMi9lVoCzOWD8QtqumN2gtmj8HgUcYNfC8xTRvBmwsZWb8oIxTv+0 uVBwrU0Trj10UmeCfkv3rEMovtfHdLysmPmahhFKYaOSe8DZOuYpGk42GMZV0OhfuHE7 1Z+1aTTWGdxPM9zKl1GiR3Am/sEN9FGKy+a0yVeNJWEg1xHMvjiRj6L6g0JxAB/8EzsP +SayyyY0DdeoZzqsu5v0AE3FDERX1YTlJ08Ht1W9O67G2Wrd/fjRsornlyLa+SxGJOCm SFeg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770466193; x=1771070993; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Mn0RB42m9zsHgb+ce7030OB0UfjmmGHf633GU5gQoUo=; b=JnU9XLh/bm7fXS4DbynF4395eqpdWUscvCAzkzN4O+OSUJdZ9R/YLT+oVEIzv4ZSZK hrX9Qui1VIxCNyrqnI71nAId8Gxb3vkWFjCEfjYNojrCKZNJ1oX4ZCGkWvgwXnvEixSt ByyXARn/FI9DClib57Dq5V1GB3+W8zfdLo8nkSQfb8/M/30IuGx1ug4gHd49Sbpl6C0f fqCuDApjT7Kvsa1cIMVrW/XKYVAsoAwtyhkMA9a2KhLUvnB0cMKNUBdEZiY5yn233jUz MDlyREPXYx4r7xz+CJUN5VMNt4ROF3K2n0r9eHPqknZKmtbBD/eOHdbONRpWiC8OR/dv 3yFA== X-Gm-Message-State: AOJu0YxQQzGm5o9lsElBBU1TTZzEZigUnplwEHbNsbQw/QO3Rk+RIm/U 0bWoZtHuPDgGZpC0dGf/dx4gVrEprl4J8/rFZchv8gnFH1CrYMLjN22iyG64ZdanuMEJpw== X-Gm-Gg: AZuq6aKolsGMPPxqo+vG6z+81SOoTHCf5xYaTG9oI/GGDMe5ztklitU7ciUGsegxLP+ KHPMn+mMO2rz+n6vLyNZeWnut/wcFROyp50CUnglSZbB7OrifLY1WNOgld0kdE8CxGbjQ5/6o+C xihHG3pqkOK5QP9E6r9he2BOnfjQmMQUEEAuXZz8eeS3Ggefg5mpUqayBDwFZWfcVHKyqQroqjx JkhKtE3JyjCmQecbY4KezUOpYOLSKYZ/lEPqaLFFB0tRO3jGO2piD46QELni/Q5h+4uexUo+Ghw 1qkoDQ1eQyQkdBKP8n6YSltToXvjcJYPQxPB3YswZXpYBff0VugpRdb5PfnYIWhv0ocYeZk5v2G T7QLFKNh0/8sxFbI2Au4jQNrXmaHVcC8F1zxMxypMOkM86zMByiGl3OifCEl9W4pz0Yb/mCB7MT F2mVGgoCHYyzPd3nPpjq+Bp7A+K0Hh6uwzsjt7 X-Received: by 2002:a17:90b:350d:b0:34e:5516:6655 with SMTP id 98e67ed59e1d1-354b3c5bb83mr4950926a91.9.1770466193180; Sat, 07 Feb 2026 04:09:53 -0800 (PST) From: Brian Song To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, hibriansong@gmail.com, hreitz@redhat.com, kwolf@redhat.com, eblake@redhat.com, armbru@redhat.com, stefanha@redhat.com, fam@euphon.net, bernd@bsbernd.com Subject: [Patch v4 2/7] fuse: io_uring mode init Date: Sat, 7 Feb 2026 20:08:56 +0800 Message-ID: <20260207120901.17222-3-hibriansong@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260207120901.17222-1-hibriansong@gmail.com> References: <20260207120901.17222-1-hibriansong@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2607:f8b0:4864:20::1034; envelope-from=hibriansong@gmail.com; helo=mail-pj1-x1034.google.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, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=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 @gmail.com) X-ZM-MESSAGEID: 1770466228371158500 Content-Type: text/plain; charset="utf-8" The kernel documentation describes in detail how FUSE-over-io_uring works: https://docs.kernel.org/filesystems/fuse/fuse-io-uring.html This patch utilizes the legacy FUSE interface (/dev/fuse) during the initialization phase to perform a protocol handshake with the kernel driver. Once FUSE-over-io_uring support is negotiated, the FUSE_IO_URING_CMD_REGISTER command is submitted to register the io_uring queues. Support for multiple IOThreads is also added to boost concurrency. Since the current Linux kernel implementation requires registering one uring queue per CPU core, we allocate the required number of queues (nproc) and distribute them across the user-specified IOThreads in a round-robin manner. To support concurrent in-flight requests per io_uring queue, each ring queue is configured with FUSE_DEFAULT_RING_QUEUE_DEPTH entries. Specifically, the workflow is as follows: - Initialize the io_uring queue depth when creating storage exports. - Upon receiving a FUSE initialization request via the legacy path: - Perform the protocol handshake to confirm feature support. - Complete FUSE-over-io_uring registration, which includes: - Pre-allocating uring queue entries and payload buffers. - Binding the CQE handler to process incoming file operations. - Initializing Submission Queue Entries (SQEs). - Distributing the uring queues across FUSE IOThreads using a round-robin strategy. After successful registration, the FUSE-over-io_uring CQE handler takes over the processing of FUSE requests. Suggested-by: Kevin Wolf Suggested-by: Stefan Hajnoczi Signed-off-by: Brian Song --- block/export/fuse.c | 430 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 414 insertions(+), 16 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index c0ad4696ce..ae7490b2a1 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -2,6 +2,7 @@ * Present a block device as a raw image through FUSE * * Copyright (c) 2020, 2025 Hanna Czenczek + * Copyright (c) 2025, 2026 Brian Song * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,6 +40,7 @@ #include "standard-headers/linux/fuse.h" #include +#include #if defined(CONFIG_FALLOCATE_ZERO_RANGE) #include @@ -63,12 +65,69 @@ (FUSE_MAX_WRITE_BYTES - FUSE_IN_PLACE_WRITE_BYTES) typedef struct FuseExport FuseExport; +typedef struct FuseQueue FuseQueue; + +#ifdef CONFIG_LINUX_IO_URING +#define FUSE_DEFAULT_URING_QUEUE_DEPTH 64 +#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32 +/* + * Under FUSE-over-io_uring mode: + * + * Each FuseUringEnt represents a FUSE request. It exposes two iovec entri= es for + * communication between the kernel driver and the userspace server: + * + * - The first iovec contains the request header (FUSE_BUFFER_HEADER_SIZE), + * holding metadata describing the request. + * - The second iovec contains the payload, used for READ/WRITE operations. + */ +#define FUSE_BUFFER_HEADER_SIZE 0x1000 + +typedef struct FuseUringQueue FuseUringQueue; + +typedef struct FuseUringEnt { + /* back pointer */ + FuseUringQueue *rq; + + /* commit id of a fuse request */ + uint64_t req_commit_id; + + /* fuse request header and payload */ + struct fuse_uring_req_header req_header; + void *req_payload; + size_t req_payload_sz; + + /* used for retry */ + enum fuse_uring_cmd last_cmd; + + /* The vector passed to the kernel */ + struct iovec iov[2]; + + CqeHandler fuse_cqe_handler; +} FuseUringEnt; + +/* + * In the current Linux kernel, FUSE-over-io_uring requires registering one + * FuseUringQueue per host CPU. These queues are allocated during setup + * and distributed to user-specified IOThreads (FuseQueue) in a round-robin + * fashion. + */ +struct FuseUringQueue { + int rqid; + + /* back pointer */ + FuseQueue *q; + FuseUringEnt *ent; + + /* List entry for uring_queues */ + QLIST_ENTRY(FuseUringQueue) next; +}; +#endif /* CONFIG_LINUX_IO_URING */ /* * One FUSE "queue", representing one FUSE FD from which requests are fetc= hed * and processed. Each queue is tied to an AioContext. */ -typedef struct FuseQueue { +struct FuseQueue { FuseExport *exp; AioContext *ctx; @@ -109,7 +168,11 @@ typedef struct FuseQueue { * Free this buffer with qemu_vfree(). */ void *spillover_buf; -} FuseQueue; + +#ifdef CONFIG_LINUX_IO_URING + QLIST_HEAD(, FuseUringQueue) uring_queue_list; +#endif +}; /* * Verify that FuseQueue.request_buf plus the spill-over buffer together @@ -133,7 +196,7 @@ struct FuseExport { */ bool halted; - int num_queues; + int num_fuse_queues; FuseQueue *queues; /* * True if this export should follow the generic export's AioContext. @@ -149,6 +212,17 @@ struct FuseExport { /* Whether allow_other was used as a mount option or not */ bool allow_other; + /* Whether to enable FUSE-over-io_uring */ + bool is_uring; + /* Whether FUSE-over-io_uring is active */ + bool uring_started; + +#ifdef CONFIG_LINUX_IO_URING + int uring_queue_depth; + int num_uring_queues; + FuseUringQueue *uring_queues; +#endif + mode_t st_mode; uid_t st_uid; gid_t st_gid; @@ -205,7 +279,7 @@ static void fuse_attach_handlers(FuseExport *exp) return; } - for (int i =3D 0; i < exp->num_queues; i++) { + for (int i =3D 0; i < exp->num_fuse_queues; i++) { aio_set_fd_handler(exp->queues[i].ctx, exp->queues[i].fuse_fd, read_from_fuse_fd, NULL, NULL, NULL, &exp->queues[i]); @@ -218,7 +292,7 @@ static void fuse_attach_handlers(FuseExport *exp) */ static void fuse_detach_handlers(FuseExport *exp) { - for (int i =3D 0; i < exp->num_queues; i++) { + for (int i =3D 0; i < exp->num_fuse_queues; i++) { aio_set_fd_handler(exp->queues[i].ctx, exp->queues[i].fuse_fd, NULL, NULL, NULL, NULL, NULL); } @@ -237,7 +311,7 @@ static void fuse_export_drained_end(void *opaque) /* Refresh AioContext in case it changed */ exp->common.ctx =3D blk_get_aio_context(exp->common.blk); if (exp->follow_aio_context) { - assert(exp->num_queues =3D=3D 1); + assert(exp->num_fuse_queues =3D=3D 1); exp->queues[0].ctx =3D exp->common.ctx; } @@ -257,6 +331,248 @@ static const BlockDevOps fuse_export_blk_dev_ops =3D { .drained_poll =3D fuse_export_drained_poll, }; +#ifdef CONFIG_LINUX_IO_URING +static void coroutine_fn fuse_uring_co_process_request(FuseUringEnt *ent); +static void fuse_uring_resubmit(struct io_uring_sqe *sqe, void *opaque); + +/** + * fuse_inc_in_flight() / fuse_dec_in_flight(): + * Wrap the lifecycle of FUSE requests being processed. This ensures the + * block layer's drain operation waits for active requests to complete + * and prevents the export from being deleted prematurely. + * + * blk_exp_ref() / blk_exp_unref(): + * Prevent the export from being deleted while there are outstanding + * dependencies. + * + * FUSE-over-io_uring mapping details: + * + * 1. SQE/CQE Lifecycle: + * blk_exp_ref() is called on SQE submission, and blk_exp_unref() on + * CQE completion. This protects the export until the kernel is done + * with the entry. + * + * 2. Request Processing: + * The coroutine processing a FUSE request must allow the drain operation + * to track it. + * + * - fuse_inc_in_flight() must be called *before* the coroutine starts + * (i.e., before qemu_coroutine_enter). + * - fuse_dec_in_flight() is called after processing ends. + * + * There is a small window where a CQE is pending in an iothread + * but the coroutine hasn't started yet. If we don't increment in_flight + * early, the main thread's drain operation might see zero in-flight + * requests and return early, falsely assuming the section is drained + * even though a request is about to be processed. + */ +static void coroutine_fn co_fuse_uring_queue_handle_cqe(void *opaque) +{ + FuseUringEnt *ent =3D opaque; + FuseExport *exp =3D ent->rq->q->exp; + + /* A uring entry returned */ + blk_exp_unref(&exp->common); + + fuse_uring_co_process_request(ent); + + /* Request is no longer in flight */ + fuse_dec_in_flight(exp); +} + +static void fuse_uring_cqe_handler(CqeHandler *cqe_handler) +{ + Coroutine *co; + FuseUringEnt *ent =3D + container_of(cqe_handler, FuseUringEnt, fuse_cqe_handler); + FuseExport *exp =3D ent->rq->q->exp; + + if (unlikely(exp->halted)) { + return; + } + + int err =3D cqe_handler->cqe.res; + + if (unlikely(err !=3D 0)) { + switch (err) { + case -EAGAIN: + case -EINTR: + aio_add_sqe(fuse_uring_resubmit, ent, &ent->fuse_cqe_handler); + break; + case -ENOTCONN: + /* Connection already gone */ + break; + default: + fuse_export_halt(exp); + break; + } + + /* A uring entry returned */ + blk_exp_unref(&exp->common); + } else { + co =3D qemu_coroutine_create(co_fuse_uring_queue_handle_cqe, ent); + /* Account this request as in-flight */ + fuse_inc_in_flight(exp); + qemu_coroutine_enter(co); + } +} + +static void +fuse_uring_sqe_set_req_data(struct fuse_uring_cmd_req *req, + const unsigned int rqid, + const unsigned int commit_id) +{ + req->qid =3D rqid; + req->commit_id =3D commit_id; + req->flags =3D 0; +} + +static void +fuse_uring_sqe_prepare(struct io_uring_sqe *sqe, FuseQueue *q, __u32 cmd_o= p) +{ + sqe->opcode =3D IORING_OP_URING_CMD; + + sqe->fd =3D q->fuse_fd; + sqe->rw_flags =3D 0; + sqe->ioprio =3D 0; + sqe->off =3D 0; + + sqe->cmd_op =3D cmd_op; + sqe->__pad1 =3D 0; +} + +static void fuse_uring_prep_sqe_register(struct io_uring_sqe *sqe, void *o= paque) +{ + FuseUringEnt *ent =3D opaque; + struct fuse_uring_cmd_req *req =3D (void *)&sqe->cmd[0]; + + ent->last_cmd =3D FUSE_IO_URING_CMD_REGISTER; + fuse_uring_sqe_prepare(sqe, ent->rq->q, ent->last_cmd); + + sqe->addr =3D (uint64_t)(ent->iov); + sqe->len =3D 2; + + fuse_uring_sqe_set_req_data(req, ent->rq->rqid, 0); +} + +static void fuse_uring_resubmit(struct io_uring_sqe *sqe, void *opaque) +{ + FuseUringEnt *ent =3D opaque; + struct fuse_uring_cmd_req *req =3D (void *)&sqe->cmd[0]; + + fuse_uring_sqe_prepare(sqe, ent->rq->q, ent->last_cmd); + + switch (ent->last_cmd) { + case FUSE_IO_URING_CMD_REGISTER: + sqe->addr =3D (uint64_t)(ent->iov); + sqe->len =3D 2; + fuse_uring_sqe_set_req_data(req, ent->rq->rqid, 0); + break; + case FUSE_IO_URING_CMD_COMMIT_AND_FETCH: + fuse_uring_sqe_set_req_data(req, ent->rq->rqid, ent->req_commit_id= ); + break; + default: + error_report("Unknown command type: %d", ent->last_cmd); + break; + } +} + +static void fuse_uring_submit_register(void *opaque) +{ + FuseUringQueue *rq =3D opaque; + FuseExport *exp =3D rq->q->exp; + + for (int j =3D 0; j < exp->uring_queue_depth; j++) { + /* Register a uring entry */ + blk_exp_ref(&exp->common); + + aio_add_sqe(fuse_uring_prep_sqe_register, &rq->ent[j], + &rq->ent[j].fuse_cqe_handler); + } +} + +/** + * Distribute uring queues across FUSE queues in the round-robin manner. + * This ensures even distribution of kernel uring queues across user-speci= fied + * FUSE queues. + * + * num_uring_queues > num_fuse_queues: Each IOThread manages multiple uring + * queues (multi-queue mapping). + * num_uring_queues < num_fuse_queues: Excess IOThreads remain idle with no + * assigned uring queues. + */ +static void fuse_uring_setup_queues(FuseExport *exp, size_t bufsize) +{ + int num_uring_queues =3D get_nprocs_conf(); + + exp->num_uring_queues =3D num_uring_queues; + exp->uring_queues =3D g_new(FuseUringQueue, num_uring_queues); + + for (int i =3D 0; i < num_uring_queues; i++) { + FuseUringQueue *rq =3D &exp->uring_queues[i]; + rq->rqid =3D i; + rq->ent =3D g_new(FuseUringEnt, exp->uring_queue_depth); + + for (int j =3D 0; j < exp->uring_queue_depth; j++) { + FuseUringEnt *ent =3D &rq->ent[j]; + ent->rq =3D rq; + ent->req_payload_sz =3D bufsize - FUSE_BUFFER_HEADER_SIZE; + ent->req_payload =3D g_malloc0(ent->req_payload_sz); + + ent->iov[0] =3D (struct iovec) { + &ent->req_header, + sizeof(struct fuse_uring_req_header) + }; + ent->iov[1] =3D (struct iovec) { + ent->req_payload, + ent->req_payload_sz + }; + + ent->fuse_cqe_handler.cb =3D fuse_uring_cqe_handler; + } + + /* Distribute uring queues across FUSE queues */ + rq->q =3D &exp->queues[i % exp->num_fuse_queues]; + QLIST_INSERT_HEAD(&(rq->q->uring_queue_list), rq, next); + } +} + +static void +fuse_schedule_ring_queue_registrations(FuseExport *exp) +{ + for (int i =3D 0; i < exp->num_fuse_queues; i++) { + FuseQueue *q =3D &exp->queues[i]; + FuseUringQueue *rq; + + QLIST_FOREACH(rq, &q->uring_queue_list, next) { + aio_bh_schedule_oneshot(q->ctx, fuse_uring_submit_register, rq= ); + } + } +} + +static void fuse_uring_start(FuseExport *exp, struct fuse_init_out *out) +{ + assert(!exp->uring_started); + exp->uring_started =3D true; + + /* + * Since we dont't enable the FUSE_MAX_PAGES feature, the value of + * fc->max_pages should be FUSE_DEFAULT_MAX_PAGES_PER_REQ, which is se= t by + * the kernel by default. Also, max_write should not exceed + * FUSE_DEFAULT_MAX_PAGES_PER_REQ * PAGE_SIZE. + */ + size_t bufsize =3D out->max_write + FUSE_BUFFER_HEADER_SIZE; + + if (!(out->flags & FUSE_MAX_PAGES)) { + bufsize =3D FUSE_DEFAULT_MAX_PAGES_PER_REQ * qemu_real_host_page_s= ize() + + FUSE_BUFFER_HEADER_SIZE; + } + + fuse_uring_setup_queues(exp, bufsize); + fuse_schedule_ring_queue_registrations(exp); +} +#endif /* CONFIG_LINUX_IO_URING */ + static int fuse_export_create(BlockExport *blk_exp, BlockExportOptions *blk_exp_args, AioContext *const *multithread, @@ -270,12 +586,24 @@ static int fuse_export_create(BlockExport *blk_exp, assert(blk_exp_args->type =3D=3D BLOCK_EXPORT_TYPE_FUSE); +#ifdef CONFIG_LINUX_IO_URING + /* TODO Add FUSE-over-io_uring Option */ + exp->is_uring =3D false; + exp->uring_queue_depth =3D FUSE_DEFAULT_URING_QUEUE_DEPTH; +#else + if (args->io_uring) { + error_setg(errp, "FUSE-over-io_uring requires CONFIG_LINUX_IO_URIN= G"); + return -ENOTSUP; + } + exp->is_uring =3D false; +#endif + if (multithread) { /* Guaranteed by common export code */ assert(mt_count >=3D 1); exp->follow_aio_context =3D false; - exp->num_queues =3D mt_count; + exp->num_fuse_queues =3D mt_count; exp->queues =3D g_new(FuseQueue, mt_count); for (size_t i =3D 0; i < mt_count; i++) { @@ -283,6 +611,10 @@ static int fuse_export_create(BlockExport *blk_exp, .exp =3D exp, .ctx =3D multithread[i], .fuse_fd =3D -1, +#ifdef CONFIG_LINUX_IO_URING + .uring_queue_list =3D + QLIST_HEAD_INITIALIZER(exp->queues[i].uring_queue_list= ), +#endif }; } } else { @@ -290,12 +622,16 @@ static int fuse_export_create(BlockExport *blk_exp, assert(mt_count =3D=3D 0); exp->follow_aio_context =3D true; - exp->num_queues =3D 1; + exp->num_fuse_queues =3D 1; exp->queues =3D g_new(FuseQueue, 1); exp->queues[0] =3D (FuseQueue) { .exp =3D exp, .ctx =3D exp->common.ctx, .fuse_fd =3D -1, +#ifdef CONFIG_LINUX_IO_URING + .uring_queue_list =3D + QLIST_HEAD_INITIALIZER(exp->queues[0].uring_queue_list), +#endif }; } @@ -383,7 +719,7 @@ static int fuse_export_create(BlockExport *blk_exp, g_hash_table_insert(exports, g_strdup(exp->mountpoint), NULL); - assert(exp->num_queues >=3D 1); + assert(exp->num_fuse_queues >=3D 1); exp->queues[0].fuse_fd =3D fuse_session_fd(exp->fuse_session); ret =3D qemu_fcntl_addfl(exp->queues[0].fuse_fd, O_NONBLOCK); if (ret < 0) { @@ -391,7 +727,7 @@ static int fuse_export_create(BlockExport *blk_exp, goto fail; } - for (int i =3D 1; i < exp->num_queues; i++) { + for (int i =3D 1; i < exp->num_fuse_queues; i++) { int fd =3D clone_fuse_fd(exp->queues[0].fuse_fd, errp); if (fd < 0) { ret =3D fd; @@ -618,7 +954,7 @@ static void fuse_export_delete(BlockExport *blk_exp) { FuseExport *exp =3D container_of(blk_exp, FuseExport, common); - for (int i =3D 0; i < exp->num_queues; i++) { + for (int i =3D 0; i < exp->num_fuse_queues; i++) { FuseQueue *q =3D &exp->queues[i]; /* Queue 0's FD belongs to the FUSE session */ @@ -685,17 +1021,37 @@ static bool is_regular_file(const char *path, Error = **errp) */ static ssize_t coroutine_fn fuse_co_init(FuseExport *exp, struct fuse_init_out *out, - uint32_t max_readahead, uint32_t flags) + uint32_t max_readahead, const struct fuse_init_in *in) { - const uint32_t supported_flags =3D FUSE_ASYNC_READ | FUSE_ASYNC_DIO; + uint64_t supported_flags =3D FUSE_ASYNC_READ | FUSE_ASYNC_DIO + | FUSE_INIT_EXT; + uint64_t outargflags =3D 0; + uint64_t inargflags =3D in->flags; + + if (inargflags & FUSE_INIT_EXT) { + inargflags =3D inargflags | (uint64_t) in->flags2 << 32; + } + +#ifdef CONFIG_LINUX_IO_URING + if (exp->is_uring) { + if (inargflags & FUSE_OVER_IO_URING) { + supported_flags |=3D FUSE_OVER_IO_URING; + } else { + exp->is_uring =3D false; + return -EOPNOTSUPP; + } + } +#endif + + outargflags =3D inargflags & supported_flags; *out =3D (struct fuse_init_out) { .major =3D FUSE_KERNEL_VERSION, .minor =3D FUSE_KERNEL_MINOR_VERSION, .max_readahead =3D max_readahead, .max_write =3D FUSE_MAX_WRITE_BYTES, - .flags =3D flags & supported_flags, - .flags2 =3D 0, + .flags =3D outargflags, + .flags2 =3D outargflags >> 32, /* libfuse maximum: 2^16 - 1 */ .max_background =3D UINT16_MAX, @@ -1404,11 +1760,24 @@ fuse_co_process_request(FuseQueue *q, void *spillov= er_buf) req_id =3D in_hdr->unique; } +#ifdef CONFIG_LINUX_IO_URING + /* + * Enable FUSE-over-io_uring mode if supported. + * FUSE_INIT is only handled in legacy mode. + * Failure returns -EOPNOTSUPP; success switches to io_uring path. + */ + bool uring_initially_enabled =3D false; + + if (unlikely(opcode =3D=3D FUSE_INIT)) { + uring_initially_enabled =3D exp->is_uring; + } +#endif + switch (opcode) { case FUSE_INIT: { const struct fuse_init_in *in =3D FUSE_IN_OP_STRUCT(init, q); ret =3D fuse_co_init(exp, FUSE_OUT_OP_STRUCT(init, out_buf), - in->max_readahead, in->flags); + in->max_readahead, in); break; } @@ -1513,7 +1882,36 @@ fuse_co_process_request(FuseQueue *q, void *spillove= r_buf) } qemu_vfree(spillover_buf); + +#ifdef CONFIG_LINUX_IO_URING + if (unlikely(opcode =3D=3D FUSE_INIT) && uring_initially_enabled) { + if (exp->is_uring && !exp->uring_started) { + /* + * Handle FUSE-over-io_uring initialization. + * If io_uring mode was requested for this export but it has n= ot + * been started yet, start it now. + */ + struct fuse_init_out *out =3D FUSE_OUT_OP_STRUCT(init, out_buf= ); + fuse_uring_start(exp, out); + } else if (ret =3D=3D -EOPNOTSUPP) { + /* + * If io_uring was requested but the kernel does not support i= t, + * halt the export. + */ + error_report("System doesn't support FUSE-over-io_uring"); + fuse_export_halt(exp); + } + } +#endif +} + +#ifdef CONFIG_LINUX_IO_URING +static void coroutine_fn fuse_uring_co_process_request(FuseUringEnt *ent) +{ + /* TODO */ + (void)ent; } +#endif /* CONFIG_LINUX_IO_URING */ const BlockExportDriver blk_exp_fuse =3D { .type =3D BLOCK_EXPORT_TYPE_FUSE, -- 2.43.0 From nobody Sun Feb 8 21:32:23 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=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1770466259; cv=none; d=zohomail.com; s=zohoarc; b=bK9vuHzjYEBRyb7izFlw4KVd3AbLn1F5NcInJPlsUAaNA0dGFFgYLaz5/XejEFls92rKUAB9AuhBYP3dIUJCaFKkWBF2qIFCQopuCF26QzqLmNCWjX9Y/g5mRPqgED1O91lXUBjiWBb3FPiAT1eMRxsR21mIGvixIDtGcsCpYsk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770466259; 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=G85lH42gCcMibdBM9mV1RiEav8F/CH9MqgVmO0gS/Qk=; b=fEW2BZyDcHAWREFeELoHt9OUr0WLh1B7KnXdopYvRNpN7OD96OBkuOiTtzz2Dq/kuihOaxku/B4GZl4wpXgUwI6NCyhjznJJf3czQFrQpo3W60sMgLqwXAGb7UCwyRBcEOybNWAmuxGnuRMpoi53sAyGHATcSbTXthL5ErWln1c= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1770466259766425.97736513826; Sat, 7 Feb 2026 04:10:59 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1voh8U-00079p-P5; Sat, 07 Feb 2026 07:10:02 -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 1voh8S-00079G-Uj for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:10:00 -0500 Received: from mail-pj1-x102c.google.com ([2607:f8b0:4864:20::102c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1voh8Q-0002sl-UI for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:10:00 -0500 Received: by mail-pj1-x102c.google.com with SMTP id 98e67ed59e1d1-354a4ef0c1eso1500407a91.2 for ; Sat, 07 Feb 2026 04:09:58 -0800 (PST) Received: from brian.. (n058152022104.netvigator.com. [58.152.22.104]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-354b30f899csm2178530a91.3.2026.02.07.04.09.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 07 Feb 2026 04:09:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770466198; x=1771070998; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=G85lH42gCcMibdBM9mV1RiEav8F/CH9MqgVmO0gS/Qk=; b=FrOS+C8k1+yKx52ZeADia87/PrxwTgqEhMPvV2QR2L+omnfLjPpkT9Y9rQuLXal9uA RDsnO3DNQ6inSXbYuYibrTz49OR8cOaxSydmous5n5/DFuCiNA8F/AiqozvjijlnpQcB IhMl1FIaPjVUCGv+LnBbI4wYU+iCbnAlDkJvxzzIqGtI39F8DDFbedRWiENjFPbq+zcH oUEfupIFq4z7CSgw1SoUyLbyQnxvU4aLhLd6Ze6P4k/6DSBAcctW/YrbFiYYl/pMINIk qZzLjKzkMovlnc5pIy+2sRIl0uJ2UX7LGYTQQHNpON86JftyU8S/Pv+TRw2IA4+HnUFY t5QA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770466198; x=1771070998; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=G85lH42gCcMibdBM9mV1RiEav8F/CH9MqgVmO0gS/Qk=; b=BxjqqaDeba4T+lreO9dzt0uqeHEXbvrPvZalSt8iwGj/2MIDDmtJJwiISMCN9bsqWh kfTdY7EEToMNsalcm6a+/DOX++NZJpzJFXhBm4geg/5TuzwuD+28EOAlqsNRjZ7rO3SU 7z6KJu6EzD/TF9m6NS3gVbHmY1QCAKDXMU50Jp1RP7eRQVMuiQw/hJuyVGN7y6SRPwVV Itkr7oNndw+KhxeVo5RPJChOc2jJl9zSc1eEue3MQLuq6sIMWHq7gk40vk2c+TH+pVE9 /OV5G+FwVdgVIsX+HUZFAz2SmCQVyC5940DOjKEnknC/vG3sqyn6MlbbycDTrOz6sU/T knaA== X-Gm-Message-State: AOJu0YwFJitdwVTOoUZshGV1bEs1K6W98nbBePJ5cO8WBn6d/y7N6Xh3 Sim0sCfVNmd8GhF1SmuhUfwoalHv1Pj60L81oHaAEG04kApZ0Bqrtfmn X-Gm-Gg: AZuq6aLnW8YzVCCTJ6GJp8UWZa6VTHvz89mQtibiHuwrhmMR2kWDliNyYXAB6G5QBMO tEy88kST7VdqxJ1Z5aFL9XJT3yKwvCYm/cthM5ZyEu7YsB+Wqv4rNlGxAiV1pfDrNtoLiDK7cFk NAI770FY87+aYzzd9NDm9px5VZ+8xowi5723RxTy8dVL5ZyqrX6R4DEoqm/zM8acJMHlKnWBZD7 TB16DnlODIiG1I1ckirP1LqJ+ijNWo9VsSk1swU89+NJwii2JwTpIdFH9XLFMLP7bs8uIQhMzu3 VXmhZiwHVjKhwArKdhDyBC47JUn6lLdylgfdQUtM6Vk+vyn4H3eqnzf21mCPMxf+O+0e+ymRA9S 51m69+8qzuyrksp6K5q9YI/UQ05RUjjFWRWDuvbPqyvHDEkpFhK5Or+NspJTMxUUqRN7henhVv9 WWbZYKbnicfTVWEe2+NIi2bXw7qqFYVNeqZug7 X-Received: by 2002:a17:90b:4f49:b0:34c:2f3f:d27e with SMTP id 98e67ed59e1d1-354b3c52e02mr4587459a91.3.1770466197548; Sat, 07 Feb 2026 04:09:57 -0800 (PST) From: Brian Song To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, hibriansong@gmail.com, hreitz@redhat.com, kwolf@redhat.com, eblake@redhat.com, armbru@redhat.com, stefanha@redhat.com, fam@euphon.net, bernd@bsbernd.com Subject: [Patch v4 3/7] fuse: uring support for write ops Date: Sat, 7 Feb 2026 20:08:57 +0800 Message-ID: <20260207120901.17222-4-hibriansong@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260207120901.17222-1-hibriansong@gmail.com> References: <20260207120901.17222-1-hibriansong@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2607:f8b0:4864:20::102c; envelope-from=hibriansong@gmail.com; helo=mail-pj1-x102c.google.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, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=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 @gmail.com) X-ZM-MESSAGEID: 1770466262251154100 Content-Type: text/plain; charset="utf-8" The payload of each uring entry serves as the buffer holding file data for read/write operations. In this patch, fuse_co_write is refactored to support using different buffer sources for write operations in legacy and io_uring modes. Suggested-by: Kevin Wolf Suggested-by: Stefan Hajnoczi Signed-off-by: Brian Song --- block/export/fuse.c | 55 ++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index ae7490b2a1..867752555a 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -1299,6 +1299,9 @@ fuse_co_read(FuseExport *exp, void **bufptr, uint64_t= offset, uint32_t size) * Data in @in_place_buf is assumed to be overwritten after yielding, so w= ill * be copied to a bounce buffer beforehand. @spillover_buf in contrast is * assumed to be exclusively owned and will be used as-is. + * In FUSE-over-io_uring mode, the actual req_payload content is stored in + * @spillover_buf. To ensure this buffer is used for writing, @in_place_buf + * is explicitly set to NULL. * Return the number of bytes written to *out on success, and -errno on er= ror. */ static ssize_t coroutine_fn @@ -1306,8 +1309,8 @@ fuse_co_write(FuseExport *exp, struct fuse_write_out = *out, uint64_t offset, uint32_t size, const void *in_place_buf, const void *spillover_buf) { - size_t in_place_size; - void *copied; + size_t in_place_size =3D 0; + void *copied =3D NULL; int64_t blk_len; int ret; struct iovec iov[2]; @@ -1322,10 +1325,12 @@ fuse_co_write(FuseExport *exp, struct fuse_write_ou= t *out, return -EACCES; } - /* Must copy to bounce buffer before potentially yielding */ - in_place_size =3D MIN(size, FUSE_IN_PLACE_WRITE_BYTES); - copied =3D blk_blockalign(exp->common.blk, in_place_size); - memcpy(copied, in_place_buf, in_place_size); + if (in_place_buf) { + /* Must copy to bounce buffer before potentially yielding */ + in_place_size =3D MIN(size, FUSE_IN_PLACE_WRITE_BYTES); + copied =3D blk_blockalign(exp->common.blk, in_place_size); + memcpy(copied, in_place_buf, in_place_size); + } /** * Clients will expect short writes at EOF, so we have to limit @@ -1349,26 +1354,38 @@ fuse_co_write(FuseExport *exp, struct fuse_write_ou= t *out, } } - iov[0] =3D (struct iovec) { - .iov_base =3D copied, - .iov_len =3D in_place_size, - }; - if (size > FUSE_IN_PLACE_WRITE_BYTES) { - assert(size - FUSE_IN_PLACE_WRITE_BYTES <=3D FUSE_SPILLOVER_BUF_SI= ZE); - iov[1] =3D (struct iovec) { - .iov_base =3D (void *)spillover_buf, - .iov_len =3D size - FUSE_IN_PLACE_WRITE_BYTES, + if (in_place_buf) { + iov[0] =3D (struct iovec) { + .iov_base =3D copied, + .iov_len =3D in_place_size, }; - qemu_iovec_init_external(&qiov, iov, 2); + if (size > FUSE_IN_PLACE_WRITE_BYTES) { + assert(size - FUSE_IN_PLACE_WRITE_BYTES <=3D FUSE_SPILLOVER_BU= F_SIZE); + iov[1] =3D (struct iovec) { + .iov_base =3D (void *)spillover_buf, + .iov_len =3D size - FUSE_IN_PLACE_WRITE_BYTES, + }; + qemu_iovec_init_external(&qiov, iov, 2); + } else { + qemu_iovec_init_external(&qiov, iov, 1); + } } else { + /* fuse over io_uring */ + iov[0] =3D (struct iovec) { + .iov_base =3D (void *)spillover_buf, + .iov_len =3D size, + }; qemu_iovec_init_external(&qiov, iov, 1); } + ret =3D blk_co_pwritev(exp->common.blk, offset, size, &qiov, 0); if (ret < 0) { goto fail_free_buffer; } - qemu_vfree(copied); + if (in_place_buf) { + qemu_vfree(copied); + } *out =3D (struct fuse_write_out) { .size =3D size, @@ -1376,7 +1393,9 @@ fuse_co_write(FuseExport *exp, struct fuse_write_out = *out, return sizeof(*out); fail_free_buffer: - qemu_vfree(copied); + if (in_place_buf) { + qemu_vfree(copied); + } return ret; } -- 2.43.0 From nobody Sun Feb 8 21:32:23 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=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1770466331; cv=none; d=zohomail.com; s=zohoarc; b=ezsWG3oCdP1Hga6TB5SaDRtH5woTo5QPfmK+VYi/UFEy5glbqhtj0doR/SRsLkrsuNgK5UIlvfi5aCy0EWCRX6vj90gyxyCkvIvNW8orIaTe+A3reGUf3nd5SmndVp9TXD8nHAzKrUlfNcPhdLTljVxTymlAx+a1DcRr5ni4Otc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770466331; 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=nqUt3VRnKO0/pU94K0c5xLOUyYWLmsrVycHnTDp9Wik=; b=TQ9B/omcwIY7xpPg+VAC6570b2Srrc8WG7Krh+8VCly3Gqc6lGtX7u3955Qy1sdhy4uSX4IFyR2uZadp5rohZCFHBHmyxlseyhdmjgcZ2CgKPQ3Jpr/RYThRvrZuhSG3Hag4Fv8Vmhwj5X5dyqN7RDPIKqLSgzBqpYJY29fcioE= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1770466331523719.5355899169208; Sat, 7 Feb 2026 04:12:11 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1voh8d-0007Cc-0g; Sat, 07 Feb 2026 07:10:11 -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 1voh8a-0007CE-2R for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:10:08 -0500 Received: from mail-pj1-x102a.google.com ([2607:f8b0:4864:20::102a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1voh8X-00035R-4V for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:10:07 -0500 Received: by mail-pj1-x102a.google.com with SMTP id 98e67ed59e1d1-34c93e0269cso2498824a91.1 for ; Sat, 07 Feb 2026 04:10:04 -0800 (PST) Received: from brian.. (n058152022104.netvigator.com. [58.152.22.104]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-354b30f899csm2178530a91.3.2026.02.07.04.09.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 07 Feb 2026 04:10:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770466203; x=1771071003; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=nqUt3VRnKO0/pU94K0c5xLOUyYWLmsrVycHnTDp9Wik=; b=dmlNpVNNMripvANhoQ1+eA3oI0Q0mEodomP0mMB4JLrl2eO7BH8HF1vG/cMcoNfaqu 1KmDiN1ZANVIBuQinr7bJPrNSiMDfxqb40EWhLoyi9N3rKNfBBsHaxOej8/bVvIWi23+ Fpu/AbFN5XLRyN8gtyQdvCMCF0LjwKCSuwKYReX0tjlqArY21g7w26UnXW6o3RCHUjT1 xvg9F1yQXTqg/xk0WvTKr9VkAgWqsD6cJHx5YyYOR6si6cN+rVi1fPxY8Kv7ooceIIDt xFaoy+5hCcQFWPKARGaBuX+zgl3j/9DfhARtHm0kppGDnwDRf+QWHxvPP8/vApMIWC1a 76SA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770466203; x=1771071003; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=nqUt3VRnKO0/pU94K0c5xLOUyYWLmsrVycHnTDp9Wik=; b=i3HTlR0cHg3xmZp73Hw+Hn643QmIlv2LHCG0J9qcywuy1i2iD3KBuFS6kXXBVOBKP6 42EF+7+QzJnqnaMKfI6ZdP9TGbF9hLXQbYaN6acO9jQTtPDdy2/UsI68QsfZpnZLS1uO cB+KCq994OT8IFqNiRZ7Exa8gGT7UqlcAiNr7ToUa3U9KOCcQvg5nH/ZPVAAXnpnd6vf 7lLyeZpljXOxd0sjsJP5R49h9WVBQ+nP8sQPFhqxTfU/jCJ9sVkBj+EUeRjEPjUzTEJ7 JVikxqL3V4ow8Mgr9c1krLauFLLmenBtiQFdK547z53SngyZ7t4IDDqqG6hH3S474GvW zxAw== X-Gm-Message-State: AOJu0YwbdaSXe5yAFi/5E4DJOdTPNWMKS6jp36RumK4lMvc+OVVjjooO a37fnRY+xdZ7ES7ImeZ9+JfnApvIEkURCkwhXuhAyHfM+9NWSsp/uego X-Gm-Gg: AZuq6aLdONoNOJ1Va1uy3FJNweJ1dh0ET2QZlui+2+u0X6Pp23EkkEJ5FNpgWeqc0PB 81wqBqrh5RGMntZH9Dq1llD0KaLbzD8robe/p/8enzC7qOw5t/cIiyOnTPTauUZ4u0phEjcMVvg 8SwfjH8Pg1sUSpvnQkbCDn1u792Z+Hmt5KcmJZCexliTZzl6ZGoaY+aZBVrRXEc0dbwoFYNiLz3 j6paDAbNW062rsZWUiHtIViTbQqzayr2rtvvD3qvtf3T53xYcFMeGhT2obVpx8SV06uhlXNPRQx 2+1yjn0BGVz4fG6fh8/2qEXpCocWxZ2h1+p4MFlks4JiV/HTyKvohekUs2VvsoPGf5tOduNk40N 7cBSWgogMkZQJSZFzXVC4AuHJaidkB5JU2usMYSA/QaCBObyZsTf9H2jSwPHT5tJyWUyu9sD1Jx 6bJFR4/JQaKvkzsTigLDLmmO7ybWO75K1rJh36WM+x1B/MM8E= X-Received: by 2002:a17:90b:4c8f:b0:354:7e46:4ab8 with SMTP id 98e67ed59e1d1-3549bc3e1f4mr8070810a91.18.1770466203215; Sat, 07 Feb 2026 04:10:03 -0800 (PST) From: Brian Song To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, hibriansong@gmail.com, hreitz@redhat.com, kwolf@redhat.com, eblake@redhat.com, armbru@redhat.com, stefanha@redhat.com, fam@euphon.net, bernd@bsbernd.com Subject: [Patch v4 4/7] fuse: refactor FUSE request handler Date: Sat, 7 Feb 2026 20:08:58 +0800 Message-ID: <20260207120901.17222-5-hibriansong@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260207120901.17222-1-hibriansong@gmail.com> References: <20260207120901.17222-1-hibriansong@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2607:f8b0:4864:20::102a; envelope-from=hibriansong@gmail.com; helo=mail-pj1-x102a.google.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, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=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 @gmail.com) X-ZM-MESSAGEID: 1770466333349154100 Content-Type: text/plain; charset="utf-8" This patch implements the CQE handler for FUSE-over-io_uring. Upon receiving a FUSE request via a Completion Queue Entry (CQE), the handler processes the request and submits the response back to the kernel via the FUSE_IO_URING_CMD_COMMIT_AND_FETCH command. Additionally, the request processing logic shared between legacy and io_uring modes has been extracted into fuse_co_process_request_common(). The execution flow now dispatches requests to the appropriate mode-specific logic based on the uring_started flag. Suggested-by: Kevin Wolf Suggested-by: Stefan Hajnoczi Signed-off-by: Brian Song --- block/export/fuse.c | 400 +++++++++++++++++++++++++++++++++----------- 1 file changed, 301 insertions(+), 99 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 867752555a..c117e081cd 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -138,8 +138,8 @@ struct FuseQueue { * 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()) and= the - * spill-over buffer below. + * which we check via the static assertion in FUSE_IN_OP_STRUCT_LEGACY= ()) + * 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). */ @@ -912,6 +912,7 @@ static void coroutine_fn co_read_from_fuse_fd(void *opa= que) } fuse_co_process_request(q, spillover_buf); + qemu_vfree(spillover_buf); no_request: fuse_dec_in_flight(exp); @@ -1684,100 +1685,75 @@ static int fuse_write_buf_response(int fd, uint32_= t req_id, } /* - * For use in fuse_co_process_request(): + * For use in fuse_co_process_request_common(): * Returns a pointer to the parameter object for the given operation (insi= de of - * queue->request_buf, which is assumed to hold a fuse_in_header first). - * Verifies that the object is complete (queue->request_buf is large enoug= h to - * hold it in one piece, and the request length includes the whole object). + * 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. * * 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(op_name, queue) \ +#define FUSE_IN_OP_STRUCT_LEGACY(op_name, queue) \ ({ \ 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); \ - uint32_t __req_len; \ \ - QEMU_BUILD_BUG_ON(sizeof((queue)->request_buf) < __param_len); \ + QEMU_BUILD_BUG_ON(sizeof((queue)->request_buf) < \ + (sizeof(struct fuse_in_header) + \ + sizeof(struct fuse_##op_name##_in))); \ \ - __req_len =3D __in_hdr->len; \ + uint32_t __req_len =3D __in_hdr->len; \ if (__req_len < __param_len) { \ warn_report("FUSE request truncated (%" PRIu32 " < %zu)", \ __req_len, __param_len); \ ret =3D -EINVAL; \ - break; \ + __in =3D NULL; \ } \ __in; \ }) /* - * For use in fuse_co_process_request(): + * For use in fuse_co_process_request_common(): * Returns a pointer to the return object for the given operation (inside = of * out_buf, which is assumed to hold a fuse_out_header first). - * Verifies that out_buf is large enough to hold the whole object. + * Only performs verification for legacy FUSE. + * Note: Buffer size verification is done via static assertions in the cal= ler + * (fuse_co_process_request) where out_buf is a local array. * - * (out_buf should be a char[] array.) + * (out_buf should be a char[] array in the caller.) */ -#define FUSE_OUT_OP_STRUCT(op_name, out_buf) \ +#define FUSE_OUT_OP_STRUCT_LEGACY(op_name, out_buf) \ ({ \ struct fuse_out_header *__out_hdr =3D \ (struct fuse_out_header *)(out_buf); \ struct fuse_##op_name##_out *__out =3D \ (struct fuse_##op_name##_out *)(__out_hdr + 1); \ \ - QEMU_BUILD_BUG_ON(sizeof(*__out_hdr) + sizeof(*__out) > \ - sizeof(out_buf)); \ - \ __out; \ }) /** - * Process a FUSE request, incl. writing the response. - * - * Note that yielding in any request-processing function can overwrite the - * contents of q->request_buf. Anything that takes a buffer needs to take - * care that the content is copied before yielding. - * - * @spillover_buf can contain the tail of a write request too large to fit= into - * q->request_buf. This function takes ownership of it (i.e. will free it= ), - * which assumes that its contents will not be overwritten by concurrent - * requests (as opposed to q->request_buf). + * Shared helper for FUSE request processing. Handles both legacy and io_u= ring + * paths. */ -static void coroutine_fn -fuse_co_process_request(FuseQueue *q, void *spillover_buf) +static void coroutine_fn fuse_co_process_request_common( + FuseExport *exp, + uint32_t opcode, + uint64_t req_id, + void *in_buf, + void *spillover_buf, + void *out_buf, + void (*send_response)(void *opaque, uint32_t req_id, int ret, + const void *buf, void *out_buf), + void *opaque /* FuseQueue* or FuseUringEnt* */) { - FuseExport *exp =3D q->exp; - uint32_t opcode; - uint64_t req_id; - /* - * Return buffer. Must be large enough to hold all return headers, bu= t does - * not include space for data returned by read requests. - * (FUSE_IN_OP_STRUCT() verifies at compile time that out_buf is indeed - * large enough.) - */ - char out_buf[sizeof(struct fuse_out_header) + - MAX_CONST(sizeof(struct fuse_init_out), - MAX_CONST(sizeof(struct fuse_open_out), - MAX_CONST(sizeof(struct fuse_attr_out), - MAX_CONST(sizeof(struct fuse_write_out), - sizeof(struct fuse_lseek_out)))))]; - struct fuse_out_header *out_hdr =3D (struct fuse_out_header *)out_buf; - /* For read requests: Data to be returned */ void *out_data_buffer =3D NULL; - ssize_t ret; - - /* Limit scope to ensure pointer is no longer used after yielding */ - { - const struct fuse_in_header *in_hdr =3D - (const struct fuse_in_header *)q->request_buf; - - opcode =3D in_hdr->opcode; - req_id =3D in_hdr->unique; - } + int ret =3D 0; #ifdef CONFIG_LINUX_IO_URING /* @@ -1794,15 +1770,32 @@ fuse_co_process_request(FuseQueue *q, void *spillov= er_buf) switch (opcode) { case FUSE_INIT: { - const struct fuse_init_in *in =3D FUSE_IN_OP_STRUCT(init, q); - ret =3D fuse_co_init(exp, FUSE_OUT_OP_STRUCT(init, out_buf), - in->max_readahead, in); + FuseQueue *q =3D opaque; + const struct fuse_init_in *in =3D + FUSE_IN_OP_STRUCT_LEGACY(init, q); + if (!in) { + break; + } + + struct fuse_init_out *out =3D + FUSE_OUT_OP_STRUCT_LEGACY(init, out_buf); + + ret =3D fuse_co_init(exp, out, in->max_readahead, in); break; } - case FUSE_OPEN: - ret =3D fuse_co_open(exp, FUSE_OUT_OP_STRUCT(open, out_buf)); + case FUSE_OPEN: { + struct fuse_open_out *out; + + if (exp->uring_started) { + out =3D out_buf; + } else { + out =3D FUSE_OUT_OP_STRUCT_LEGACY(open, out_buf); + } + + ret =3D fuse_co_open(exp, out); break; + } case FUSE_RELEASE: ret =3D 0; @@ -1812,37 +1805,105 @@ fuse_co_process_request(FuseQueue *q, void *spillo= ver_buf) ret =3D -ENOENT; /* There is no node but the root node */ break; - case FUSE_GETATTR: - ret =3D fuse_co_getattr(exp, FUSE_OUT_OP_STRUCT(attr, out_buf)); + case FUSE_GETATTR: { + struct fuse_attr_out *out; + + if (exp->uring_started) { + out =3D out_buf; + } else { + out =3D FUSE_OUT_OP_STRUCT_LEGACY(attr, out_buf); + } + + ret =3D fuse_co_getattr(exp, out); break; + } case FUSE_SETATTR: { - const struct fuse_setattr_in *in =3D FUSE_IN_OP_STRUCT(setattr, q); - ret =3D fuse_co_setattr(exp, FUSE_OUT_OP_STRUCT(attr, out_buf), - in->valid, in->size, in->mode, in->uid, in->= gid); + const struct fuse_setattr_in *in; + struct fuse_attr_out *out; + + 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); + } + + ret =3D fuse_co_setattr(exp, out, in->valid, in->size, in->mode, + in->uid, in->gid); break; } case FUSE_READ: { - const struct fuse_read_in *in =3D FUSE_IN_OP_STRUCT(read, q); + 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; + } + } + ret =3D fuse_co_read(exp, &out_data_buffer, in->offset, in->size); break; } case FUSE_WRITE: { - const struct fuse_write_in *in =3D FUSE_IN_OP_STRUCT(write, q); - uint32_t req_len; - - req_len =3D ((const struct fuse_in_header *)q->request_buf)->len; - if (unlikely(req_len < sizeof(struct fuse_in_header) + sizeof(*in)= + - in->size)) { - warn_report("FUSE WRITE truncated; received %zu bytes of %" PR= Iu32, - req_len - sizeof(struct fuse_in_header) - sizeof(*= in), - in->size); - ret =3D -EINVAL; - break; - } + const struct fuse_write_in *in; + struct fuse_write_out *out; + const void *in_place_buf; + const void *spill_buf; + + if (exp->uring_started) { + FuseUringEnt *ent =3D opaque; + + in =3D in_buf; + out =3D out_buf; + + assert(in->size <=3D ent->req_header.ring_ent_in_out.payload_s= z); + /* + * In uring mode, the "out_buf" (ent->payload) actually holds = the + * input data for WRITE requests. + */ + 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; + + if (unlikely(req_len < sizeof(struct fuse_in_header) + sizeof(= *in) + + in->size)) { + warn_report("FUSE WRITE truncated; received %zu bytes of %" + PRIu32, + req_len - sizeof(struct fuse_in_header) - sizeof(*in), + in->size); + ret =3D -EINVAL; + break; + } + + /* Legacy buffer setup */ + in_place_buf =3D in + 1; + spill_buf =3D spillover_buf; + } /* * poll_fuse_fd() has checked that in_hdr->len matches the number = of * bytes read, which cannot exceed the max_write value we set @@ -1856,13 +1917,24 @@ fuse_co_process_request(FuseQueue *q, void *spillov= er_buf) * fuse_co_write() takes care to copy its contents before potentia= lly * yielding. */ - ret =3D fuse_co_write(exp, FUSE_OUT_OP_STRUCT(write, out_buf), - in->offset, in->size, in + 1, spillover_buf); + ret =3D fuse_co_write(exp, out, in->offset, in->size, + in_place_buf, spill_buf); break; } case FUSE_FALLOCATE: { - const struct fuse_fallocate_in *in =3D FUSE_IN_OP_STRUCT(fallocate= , q); + 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; + } + } + ret =3D fuse_co_fallocate(exp, in->offset, in->length, in->mode); break; } @@ -1877,9 +1949,23 @@ fuse_co_process_request(FuseQueue *q, void *spillove= r_buf) #ifdef CONFIG_FUSE_LSEEK case FUSE_LSEEK: { - const struct fuse_lseek_in *in =3D FUSE_IN_OP_STRUCT(lseek, q); - ret =3D fuse_co_lseek(exp, FUSE_OUT_OP_STRUCT(lseek, out_buf), - in->offset, in->whence); + const struct fuse_lseek_in *in; + struct fuse_lseek_out *out; + + 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); + } + + ret =3D fuse_co_lseek(exp, out, in->offset, in->whence); break; } #endif @@ -1888,20 +1974,12 @@ fuse_co_process_request(FuseQueue *q, void *spillov= er_buf) ret =3D -ENOSYS; } - /* Ignore errors from fuse_write*(), nothing we can do anyway */ + send_response(opaque, req_id, ret, out_data_buffer, out_buf); + if (out_data_buffer) { - assert(ret >=3D 0); - fuse_write_buf_response(q->fuse_fd, req_id, out_hdr, - out_data_buffer, ret); qemu_vfree(out_data_buffer); - } else { - fuse_write_response(q->fuse_fd, req_id, out_hdr, - ret < 0 ? ret : 0, - ret < 0 ? 0 : ret); } - qemu_vfree(spillover_buf); - #ifdef CONFIG_LINUX_IO_URING if (unlikely(opcode =3D=3D FUSE_INIT) && uring_initially_enabled) { if (exp->is_uring && !exp->uring_started) { @@ -1910,7 +1988,8 @@ fuse_co_process_request(FuseQueue *q, void *spillover= _buf) * If io_uring mode was requested for this export but it has n= ot * been started yet, start it now. */ - struct fuse_init_out *out =3D FUSE_OUT_OP_STRUCT(init, out_buf= ); + struct fuse_init_out *out =3D + FUSE_OUT_OP_STRUCT_LEGACY(init, out_buf); fuse_uring_start(exp, out); } else if (ret =3D=3D -EOPNOTSUPP) { /* @@ -1923,12 +2002,135 @@ fuse_co_process_request(FuseQueue *q, void *spillo= ver_buf) } #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) +{ + FuseQueue *q =3D (FuseQueue *)opaque; + struct fuse_out_header *out_hdr =3D (struct fuse_out_header *)out_buf; + if (buf) { + assert(ret >=3D 0); + fuse_write_buf_response(q->fuse_fd, req_id, out_hdr, buf, ret); + } else { + fuse_write_response(q->fuse_fd, req_id, out_hdr, + ret < 0 ? ret : 0, + ret < 0 ? 0 : ret); + } +} + +static void coroutine_fn +fuse_co_process_request(FuseQueue *q, void *spillover_buf) +{ + FuseExport *exp =3D q->exp; + uint32_t opcode; + uint64_t req_id; + + /* + * Return buffer. Must be large enough to hold all return headers, bu= t does + * not include space for data returned by read requests. + */ + char out_buf[sizeof(struct fuse_out_header) + + MAX_CONST(sizeof(struct fuse_init_out), + MAX_CONST(sizeof(struct fuse_open_out), + MAX_CONST(sizeof(struct fuse_attr_out), + MAX_CONST(sizeof(struct fuse_write_out), + sizeof(struct fuse_lseek_out)))))] =3D {0}; + + /* Verify that out_buf is large enough for all output structures */ + QEMU_BUILD_BUG_ON(sizeof(struct fuse_out_header) + + sizeof(struct fuse_init_out) > sizeof(out_buf)); + QEMU_BUILD_BUG_ON(sizeof(struct fuse_out_header) + + sizeof(struct fuse_open_out) > sizeof(out_buf)); + QEMU_BUILD_BUG_ON(sizeof(struct fuse_out_header) + + sizeof(struct fuse_attr_out) > sizeof(out_buf)); + QEMU_BUILD_BUG_ON(sizeof(struct fuse_out_header) + + sizeof(struct fuse_write_out) > sizeof(out_buf)); +#ifdef CONFIG_FUSE_LSEEK + QEMU_BUILD_BUG_ON(sizeof(struct fuse_out_header) + + sizeof(struct fuse_lseek_out) > sizeof(out_buf)); +#endif + + /* Limit scope to ensure pointer is no longer used after yielding */ + { + const struct fuse_in_header *in_hdr =3D + (const struct fuse_in_header *)q->request_buf; + + opcode =3D in_hdr->opcode; + req_id =3D in_hdr->unique; + } + + fuse_co_process_request_common(exp, opcode, req_id, NULL, spillover_bu= f, + out_buf, send_response_legacy, q); +} #ifdef CONFIG_LINUX_IO_URING +static void fuse_uring_prep_sqe_commit(struct io_uring_sqe *sqe, void *opa= que) +{ + FuseUringEnt *ent =3D opaque; + struct fuse_uring_cmd_req *req =3D (void *)&sqe->cmd[0]; + + ent->last_cmd =3D FUSE_IO_URING_CMD_COMMIT_AND_FETCH; + + fuse_uring_sqe_prepare(sqe, ent->rq->q, ent->last_cmd); + fuse_uring_sqe_set_req_data(req, ent->rq->rqid, ent->req_commit_id); +} + +static void +fuse_uring_send_response(FuseUringEnt *ent, uint32_t req_id, int ret, + const void *out_data_buffer) +{ + FuseExport *exp =3D ent->rq->q->exp; + + struct fuse_uring_req_header *rrh =3D &ent->req_header; + struct fuse_out_header *out_header =3D (struct fuse_out_header *)&rrh-= >in_out; + struct fuse_uring_ent_in_out *ent_in_out =3D + (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out; + + /* FUSE_READ */ + if (out_data_buffer && ret > 0) { + memcpy(ent->req_payload, out_data_buffer, ret); + } + + out_header->error =3D ret < 0 ? ret : 0; + out_header->unique =3D req_id; + ent_in_out->payload_sz =3D ret > 0 ? ret : 0; + + /* Commit and fetch a uring entry */ + blk_exp_ref(&exp->common); + aio_add_sqe(fuse_uring_prep_sqe_commit, ent, &ent->fuse_cqe_handler); +} + +/* Helper to send response for uring */ +static void send_response_uring(void *opaque, uint32_t req_id, int ret, + const void *out_data_buffer, void *payload) +{ + FuseUringEnt *ent =3D (FuseUringEnt *)opaque; + + fuse_uring_send_response(ent, req_id, ret, out_data_buffer); +} + static void coroutine_fn fuse_uring_co_process_request(FuseUringEnt *ent) { - /* TODO */ - (void)ent; + FuseExport *exp =3D ent->rq->q->exp; + struct fuse_uring_req_header *rrh =3D &ent->req_header; + struct fuse_uring_ent_in_out *ent_in_out =3D + (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 opcode =3D in_hdr->opcode; + uint64_t req_id =3D in_hdr->unique; + + ent->req_commit_id =3D ent_in_out->commit_id; + + if (unlikely(ent->req_commit_id =3D=3D 0)) { + error_report("If this happens kernel will not find the response - " + "it will be stuck forever - better to abort immediately."); + fuse_export_halt(exp); + return; + } + + fuse_co_process_request_common(exp, opcode, req_id, &rrh->op_in, + NULL, ent->req_payload, send_response_uring, ent); } #endif /* CONFIG_LINUX_IO_URING */ -- 2.43.0 From nobody Sun Feb 8 21:32:23 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=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1770466323; cv=none; d=zohomail.com; s=zohoarc; b=HbVAYjKhqVyhXPwYx7t0Jn5vfANBvNM90UgRtcAL86KhdpbSRYoliCcYT6L+jNjcJCrEa5eLyEjthFRsEb20Nt9xzUMUJZ4iuB4zkqD89EhSdb6iT1QVQA1vt2fV9UDBB+jyHOzoJkvenlnkL7nmV3bKaGbeGP65Sm5Zs8wq6g4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770466323; 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=H78Df0v0meU3GDrKU4J2lfRzsB4Ror34DjemRoX9SzM=; b=Ri7wgRi6SWf313ZFy2gj6g7jiAchIRAkpU74c2weNjQeqjVxzSW8vOXmxeH15d8dGQrGfsGHChihkmkXxx7EEMJV35Ss6OQhLa4lMysrXbghnZTKr2s/t+SJohZfkpfZf7jBNt9c7g21AJwayQ8JqrnVWYzrZWciPibbRaHOWWI= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1770466323572719.7498351048462; Sat, 7 Feb 2026 04:12:03 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1voh8h-0007FR-76; Sat, 07 Feb 2026 07:10:15 -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 1voh8d-0007DV-GK for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:10:12 -0500 Received: from mail-pj1-x1034.google.com ([2607:f8b0:4864:20::1034]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1voh8a-00036L-TH for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:10:10 -0500 Received: by mail-pj1-x1034.google.com with SMTP id 98e67ed59e1d1-3530e7b3dc2so2570090a91.3 for ; Sat, 07 Feb 2026 04:10:08 -0800 (PST) Received: from brian.. (n058152022104.netvigator.com. [58.152.22.104]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-354b30f899csm2178530a91.3.2026.02.07.04.10.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 07 Feb 2026 04:10:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770466207; x=1771071007; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=H78Df0v0meU3GDrKU4J2lfRzsB4Ror34DjemRoX9SzM=; b=fKn5MkuZlDjaeZwMGaXkYQl+JYdNYMv0Ljh8y+pwyqAW42XUroEEpyOQb+rXR2SC0L rTveQBD8nZvh8sX/C9Xe06by/uuN4PEIPeINxdNj7HPcF+KI28iBXSDl/w83CaL7exbB CwxMJ/ha0lypORF3mW+DSAzVcf41i661BChEcx0718/J3he6Q6s7lnIgA/WB/MdjAk4H A9S8biGAhMitiiQSWQue1x47ErzL4czESS5mZsc0nB4ylItrUQdZ5atOHibrFLU6wVBZ Qtxzy2myHK32MWxgLZNxmGpKucPGDuKQL6MJRsbTEvNz5HYnCQcj5LEJWh3TxFBMVY8C uNyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770466207; x=1771071007; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=H78Df0v0meU3GDrKU4J2lfRzsB4Ror34DjemRoX9SzM=; b=ngQyok/NClFUyJYi4BXkwy2efA9nqh0SZye/KNTeHXtSA7c2QmG8712irl8u6bEbde 4Oni6dCs+uL8+jfhz0Wd9Z6D5/dMhM63MOJFQu5nto0FUWi9rv2MBTw3skXV4CNIKGDn imjHAWi3uUUPe5oddmtdfDLxu9CEWbr0dCwaCYqSqa5JLH4OU9FJyE/TBuQJ/XUCJ+0v QUbZvyCod14s9G6x+9wiRFykm36fHn2Oy0sQnz/uvejQY9GpoePo39fKDSbTGpt6hVbB Ux37OL/UHLl3SRJedWjL0D/2slh7SHTRD1meir68C5IG3bBOqZrcAVqOOIJOdWVy+uSv FNAQ== X-Gm-Message-State: AOJu0YwraELw4cgNbsLGhTYtARwsDoA+/Tn5kSeyQpl6U9A8tLCW3dDb NlHsBbpWu18ulAdUZPc+BiHtIyQl7ZRCsIUlyDHLXbQORD/+ZQYsHizf X-Gm-Gg: AZuq6aKIyl/8aJm2RAm+kB3fxrVkMBfHO4qPxXcCnPDJejs3bUfBGb+N7uOmzGSSH0k NcNcafnvXWsXvRL2zq8UE1N06jaj2QhZiseJV315r1ujRxqQCrSSgOTuB8EZ3vcyyXBifYYM8XH 2RqFpCNhDtmqYdAK7L229t4R3xCz1zOSlki7OVP0wYK4dZzq1ljYSydsTxeCDWwt1NuEeCLUpYW ZVvCm71JSexaKsjQmmf/KGqpzhi02+HAMoV2fUIlhL2ufxIgBdSo6qfGthVctY1g5WVnhIwMW8D BJvtgBzB7d9j36sT4J7XEuSnoLLKFJsq+OsEjLueBlWUnfEH5xIMUh7CTeLxizOUciDzykJK/+N dEx4b+34+59wsEW+WU+6TEyz0l0wQ6drW+LG9p6ezlbW+M9WOIFvC7K/wHDIcjWcgNe7xSmKBlU ZUxtxcJHrOim6Lh3WdmX4F13XLsiqIbDenh2V2UHEnwqBK5W6Q X-Received: by 2002:a17:90b:35cc:b0:353:5595:3247 with SMTP id 98e67ed59e1d1-354b3c74a3fmr6051387a91.12.1770466207514; Sat, 07 Feb 2026 04:10:07 -0800 (PST) From: Brian Song To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, hibriansong@gmail.com, hreitz@redhat.com, kwolf@redhat.com, eblake@redhat.com, armbru@redhat.com, stefanha@redhat.com, fam@euphon.net, bernd@bsbernd.com Subject: [Patch v4 5/6] fuse: safe termination for io_uring Date: Sat, 7 Feb 2026 20:08:59 +0800 Message-ID: <20260207120901.17222-6-hibriansong@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260207120901.17222-1-hibriansong@gmail.com> References: <20260207120901.17222-1-hibriansong@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2607:f8b0:4864:20::1034; envelope-from=hibriansong@gmail.com; helo=mail-pj1-x1034.google.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, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=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 @gmail.com) X-ZM-MESSAGEID: 1770466324336158500 Content-Type: text/plain; charset="utf-8" When a termination signal is received, the storage-export-daemon stops the export, exits the main loop (main_loop_wait), and begins resource cleanup. However, some FUSE_IO_URING_CMD_COMMIT_AND_FETCH SQEs may remain pending in the kernel, waiting for incoming FUSE requests. Currently, there is no way to manually cancel these pending CQEs in the kernel. As a result, after export termination, the related data structures might be deleted before the pending CQEs return, causing the CQE handler to be invoked after it has been freed, which may lead to a segfault. As a workaround, when submitting an SQE to the kernel, we increment the block reference (blk_exp_ref) to prevent the CQE handler from being deleted during export termination. Once the CQE is received, we decrement the reference (blk_exp_unref). However, this introduces a new issue: if no new FUSE requests arrive, the pending SQEs held by the kernel will never complete. Consequently, the export reference count never drops to zero, preventing the export from shutting down cleanly. To resolve this, we schedule a Bottom Half (BH) for each FUSE queue during the export shutdown phase. The BH closes the fuse_fd to prevent race conditions, while the session is unmounted during the remainder of the shutdown sequence. This explicitly aborts all pending SQEs in the kernel, forcing the corresponding CQEs to return. This triggers the release of held references, allowing the export to be freed safely. Suggested-by: Kevin Wolf Suggested-by: Stefan Hajnoczi Signed-off-by: Brian Song --- block/export/fuse.c | 100 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 90 insertions(+), 10 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index c117e081cd..abae83041b 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -934,6 +934,57 @@ static void read_from_fuse_fd(void *opaque) qemu_coroutine_enter(co); } +#ifdef CONFIG_LINUX_IO_URING +static void fuse_export_delete_uring(FuseExport *exp) +{ + exp->is_uring =3D false; + exp->uring_started =3D false; + + for (int i =3D 0; i < exp->num_uring_queues; i++) { + FuseUringQueue *rq =3D &exp->uring_queues[i]; + + for (int j =3D 0; j < FUSE_DEFAULT_URING_QUEUE_DEPTH; j++) { + g_free(rq->ent[j].req_payload); + } + g_free(rq->ent); + } + + g_free(exp->uring_queues); +} +#endif + +/** + * The Linux kernel currently lacks support for asynchronous cancellation + * of FUSE-over-io_uring SQEs. This can lead to a race where an IOThread m= ay + * access fuse_fd after it is closed but before pending SQEs are canceled, + * potentially operating on a newly reused file descriptor. + * + * Therefore, schedule a BH in the IOThread to close and invalidate fuse_f= d, + * to avoid races on fuse_fd. + */ +#ifdef CONFIG_LINUX_IO_URING +static void close_fuse_fd(void *opaque) +{ + FuseQueue *q =3D opaque; + + if (q->fuse_fd >=3D 0) { + close(q->fuse_fd); + q->fuse_fd =3D -1; + } +} +#endif + +/** + * During exit in FUSE-over-io_uring mode, qemu-storage-daemon requests + * shutdown in main() and then immediately tears down the block export. + * However, SQEs already submitted under FUSE-over-io_uring may still comp= lete + * and generate CQEs that continue to hold references to the block export, + * preventing it from being freed cleanly. + * + * Since the Linux kernel currently lacks support for asynchronous cancell= ation + * of FUSE-over-io_uring SQEs, this function aborts the connection and can= cels + * all pending SQEs to ensure a safe teardown. + */ static void fuse_export_shutdown(BlockExport *blk_exp) { FuseExport *exp =3D container_of(blk_exp, FuseExport, common); @@ -949,18 +1000,42 @@ static void fuse_export_shutdown(BlockExport *blk_ex= p) */ g_hash_table_remove(exports, exp->mountpoint); } + +#ifdef CONFIG_LINUX_IO_URING + if (exp->uring_started) { + for (size_t i =3D 0; i < exp->num_fuse_queues; i++) { + FuseQueue *q =3D &exp->queues[i]; + + /* Queue 0's FD belongs to the FUSE session */ + if (i > 0) { + aio_bh_schedule_oneshot(q->ctx, close_fuse_fd, q); + } + } + + /* To cancel all pending SQEs */ + if (exp->fuse_session) { + if (exp->mounted) { + fuse_session_unmount(exp->fuse_session); + } + fuse_session_destroy(exp->fuse_session); + } + g_free(exp->mountpoint); + } +#endif } static void fuse_export_delete(BlockExport *blk_exp) { FuseExport *exp =3D container_of(blk_exp, FuseExport, common); - for (int i =3D 0; i < exp->num_fuse_queues; i++) { + for (size_t i =3D 0; i < exp->num_fuse_queues; i++) { FuseQueue *q =3D &exp->queues[i]; - /* Queue 0's FD belongs to the FUSE session */ - if (i > 0 && q->fuse_fd >=3D 0) { - close(q->fuse_fd); + if (!exp->uring_started) { + /* Queue 0's FD belongs to the FUSE session */ + if (i > 0 && q->fuse_fd >=3D 0) { + close(q->fuse_fd); + } } if (q->spillover_buf) { qemu_vfree(q->spillover_buf); @@ -968,15 +1043,20 @@ static void fuse_export_delete(BlockExport *blk_exp) } g_free(exp->queues); - if (exp->fuse_session) { - if (exp->mounted) { - fuse_session_unmount(exp->fuse_session); + if (exp->uring_started) { +#ifdef CONFIG_LINUX_IO_URING + fuse_export_delete_uring(exp); +#endif + } else { + if (exp->fuse_session) { + if (exp->mounted) { + fuse_session_unmount(exp->fuse_session); + } + fuse_session_destroy(exp->fuse_session); } - fuse_session_destroy(exp->fuse_session); + g_free(exp->mountpoint); } - - g_free(exp->mountpoint); } /** -- 2.43.0 From nobody Sun Feb 8 21:32:23 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=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1770466250; cv=none; d=zohomail.com; s=zohoarc; b=AvZgbwlEW3uogIecUdgDFlnPzkJ9nSpQK0ZfKHSa6g/pcyi1D2uCYYe2LQmMYNbbkrJrlsFwkD4haMZ+JtXsLHfRH8Nw5C/0mrcRrBJgLCHvfdpcitBUTa2YgoQALXg3HNCtmB57n+yh4E77XRx6BQk51Bsx7pAzw+hLNnp885A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770466250; 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=yRvq4zI7MIK6rCqCt35/LJLjg5NnaBCJ0/CBYvfVPw8=; b=NTmeNPwmXe9hG/o0hOBi9nPHqQEIzFdzEKb9y18Pp0cIgXEeTTPSqYUPLEEL1GcI1rmqTDOhw9WOIlRakajrSFiFskV6E0+vwUUd5oYnyRlujPMsTx1I2vgzpecgKjkT6o2Hn8RzNXmZLQ3BPV0o5SlwGN80Oai2+SI32/WpOiY= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1770466250896889.0580359763587; Sat, 7 Feb 2026 04:10:50 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1voh8n-0007GH-LH; Sat, 07 Feb 2026 07:10:21 -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 1voh8i-0007Fa-NM for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:10:17 -0500 Received: from mail-pj1-x1033.google.com ([2607:f8b0:4864:20::1033]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1voh8g-000387-PU for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:10:16 -0500 Received: by mail-pj1-x1033.google.com with SMTP id 98e67ed59e1d1-35621aa8c7fso132187a91.2 for ; Sat, 07 Feb 2026 04:10:13 -0800 (PST) Received: from brian.. (n058152022104.netvigator.com. [58.152.22.104]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-354b30f899csm2178530a91.3.2026.02.07.04.10.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 07 Feb 2026 04:10:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770466213; x=1771071013; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=yRvq4zI7MIK6rCqCt35/LJLjg5NnaBCJ0/CBYvfVPw8=; b=O6yL/A9C80lt4wDTjHRHZ8sOiHWXKCmm02XLO57mhcYwDqlmz/JPOwiJ0SXf7Qi2gF /7siuQZEh/duC7j5Gh9swRf7qfcClam8nU6oRQrN4eC5dlCVDJL9451SdmdZHzVJywhL faxbO2vWbqdpf/lkhi03QVyzaV7Gh2BmvQWgQoPxII7jt2ZOSifOJBfC8Hv7ecxpOaVZ Ds/hMKYJyHLaZBFf855aCyAswhiyywUfQR3Ci5ns9Nd2s2B5mqDX1oBE/fGH4NCL6Kq6 Ky31r3jMjoiZsPCwbrE67tGrnf65YA6hMbvH8D82RHJJo2DMyZLQMnardvZvQdjwZtQ+ UQ+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770466213; x=1771071013; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=yRvq4zI7MIK6rCqCt35/LJLjg5NnaBCJ0/CBYvfVPw8=; b=reRhcDEEcoQEVKBbQU79tAz9oqE1BfUPfziHyilWwBWzWeQUptblrqdcGgABKeEhT1 GW/BHdGpII9/43nUsvrSSK09ycCSfNkoKfaRZuPLiwUszCWwGyGZh56BshArcTD/ahxF /M4POsU9C7G49eYNgQnzRo0h0UVaKv0jvYBnUJmegIl2Mal419ufhEE3dIBj4TDSiA4e AIHFWIoL9ngdfEnrpG8Z4MXylPMvIgD6lbLrCTpYs9wlDP08qHt+zxSq8HTOVKx+Y64z Lv/6PeQ822MhAe2pihZZuflHI0P/MMX2CHHjYAhnFXlRVQLm5HagZ1/F+aQ6YLi96t96 WJfg== X-Gm-Message-State: AOJu0Ywt/LHvtkvrTTA6rS2i00WmWb0atzIVpHkk4X0tvO0GMhqCHAhO Ih4bnFp7f84h3NhmYH4VE/l0EZVsYvE1vwSqq0JuZ8AHwMJ/tNVDRGaG X-Gm-Gg: AZuq6aKFtLnw3/h4qdxPUBuCb//UZa0leR/qIj30yTW+zE8rCPBYm9pxJPRVP1gSnCF BBxZ6hbW3wxm839VYAMfvflXA6GZK6tBACbb2WsHKOtrVaHI22/lGgza37fNhiuVeM7XwPpkqUF cuJcQOJwkPP7IPviAyuOYfivCBzYNo7Wo3AB/0dG1bnZBNcwgeoqrVUDJUUedG3qcez0Tg831ZS 1t2EqLXTxS2OQ5J8f0nmofStNYUVYESl/Eowe8h4/Jb4Y1EVcF0KL0JVURFtTCDwzkC0XGVxSJg hPVQLnxmbxBAkDZH5YD59QumpgubuBwIpbow6MQ/tuE+26q5lTiB0Oaq13Znlj13lwDw/vcd2q+ f5pjcbk78+5lTAoTV1zxM81ajQnC/ZGi9Anbio47QSSyGWD3dfX1cReTXJWgWaPnHEql28gUrHV x2E+gjCmoI62uBw5MX1TXKxD1/A1dBRM9o/Tzi X-Received: by 2002:a17:90b:3945:b0:356:1edc:b64 with SMTP id 98e67ed59e1d1-3561edc1183mr1148725a91.8.1770466212791; Sat, 07 Feb 2026 04:10:12 -0800 (PST) From: Brian Song To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, hibriansong@gmail.com, hreitz@redhat.com, kwolf@redhat.com, eblake@redhat.com, armbru@redhat.com, stefanha@redhat.com, fam@euphon.net, bernd@bsbernd.com Subject: [Patch v4 6/7] fuse: add 'io-uring' option Date: Sat, 7 Feb 2026 20:09:00 +0800 Message-ID: <20260207120901.17222-7-hibriansong@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260207120901.17222-1-hibriansong@gmail.com> References: <20260207120901.17222-1-hibriansong@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2607:f8b0:4864:20::1033; envelope-from=hibriansong@gmail.com; helo=mail-pj1-x1033.google.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, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable 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 @gmail.com) X-ZM-MESSAGEID: 1770466254181154100 Content-Type: text/plain; charset="utf-8" This patch adds a new storage export option for storage-export-daemon to enable FUSE-over-io_uring via 'io-uring=3Don|off' (default: off). The initialization phase performs a protocol handshake via the legacy /dev/fuse interface before transitioning to the io_uring mode. If multiple IOThreads are configured, the export distributes the uring queues to handle requests concurrently. Suggested-by: Kevin Wolf Suggested-by: Stefan Hajnoczi Signed-off-by: Brian Song --- block/export/fuse.c | 3 +-- docs/tools/qemu-storage-daemon.rst | 7 +++++-- qapi/block-export.json | 5 ++++- storage-daemon/qemu-storage-daemon.c | 1 + 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index abae83041b..09642ccf5a 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -587,8 +587,7 @@ static int fuse_export_create(BlockExport *blk_exp, assert(blk_exp_args->type =3D=3D BLOCK_EXPORT_TYPE_FUSE); #ifdef CONFIG_LINUX_IO_URING - /* TODO Add FUSE-over-io_uring Option */ - exp->is_uring =3D false; + exp->is_uring =3D args->io_uring; exp->uring_queue_depth =3D FUSE_DEFAULT_URING_QUEUE_DEPTH; #else if (args->io_uring) { diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-d= aemon.rst index 35ab2d7807..ad0f41a78f 100644 --- a/docs/tools/qemu-storage-daemon.rst +++ b/docs/tools/qemu-storage-daemon.rst @@ -78,7 +78,7 @@ Standard options: .. option:: --export [type=3D]nbd,id=3D,node-name=3D[,name= =3D][,writable=3Don|off][,bitmap=3D] --export [type=3D]vhost-user-blk,id=3D,node-name=3D,addr.= type=3Dunix,addr.path=3D[,writable=3Don|off][,logical-block-si= ze=3D][,num-queues=3D] --export [type=3D]vhost-user-blk,id=3D,node-name=3D,addr.= type=3Dfd,addr.str=3D[,writable=3Don|off][,logical-block-size=3D][,num-queues=3D] - --export [type=3D]fuse,id=3D,node-name=3D,mountpoint=3D[,growable=3Don|off][,writable=3Don|off][,allow-other=3Don|off|auto] + --export [type=3D]fuse,id=3D,node-name=3D,mountpoint=3D[,growable=3Don|off][,writable=3Don|off][,allow-other=3Don|off|auto][,i= o-uring=3Don|off] --export [type=3D]vduse-blk,id=3D,node-name=3D,name=3D[,writable=3Don|off][,num-queues=3D][,queue-size=3D][,logical-block-size=3D][,serial=3D] is a block export definition. ``node-name`` is the block node that shoul= d be @@ -111,7 +111,10 @@ Standard options: that enabling this option as a non-root user requires enabling the user_allow_other option in the global fuse.conf configuration file. Set= ting ``allow-other`` to auto (the default) will try enabling this option, and= on - error fall back to disabling it. + error fall back to disabling it. Once ``io-uring`` is enabled (off by de= fault), + the FUSE-over-io_uring-related settings will be initialized to bypass the + traditional /dev/fuse communication mechanism and instead use io_uring to + handle FUSE operations. The ``vduse-blk`` export type takes a ``name`` (must be unique across th= e host) to create the VDUSE device. diff --git a/qapi/block-export.json b/qapi/block-export.json index 9ae703ad01..37f2fc47e2 100644 --- a/qapi/block-export.json +++ b/qapi/block-export.json @@ -184,12 +184,15 @@ # mount the export with allow_other, and if that fails, try again # without. (since 6.1; default: auto) # +# @io-uring: Use FUSE-over-io-uring. (since 10.2; default: false) +# # Since: 6.0 ## { 'struct': 'BlockExportOptionsFuse', 'data': { 'mountpoint': 'str', '*growable': 'bool', - '*allow-other': 'FuseExportAllowOther' }, + '*allow-other': 'FuseExportAllowOther', + '*io-uring': 'bool' }, 'if': 'CONFIG_FUSE' } ## diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-sto= rage-daemon.c index eb72561358..0cd4cd2b58 100644 --- a/storage-daemon/qemu-storage-daemon.c +++ b/storage-daemon/qemu-storage-daemon.c @@ -107,6 +107,7 @@ static void help(void) #ifdef CONFIG_FUSE " --export [type=3D]fuse,id=3D,node-name=3D,mountpoint=3D<= file>\n" " [,growable=3Don|off][,writable=3Don|off][,allow-other=3Don|off= |auto]\n" +" [,io-uring=3Don|off]" " export the specified block node over FUSE\n" "\n" #endif /* CONFIG_FUSE */ -- 2.43.0 From nobody Sun Feb 8 21:32:23 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=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1770466322; cv=none; d=zohomail.com; s=zohoarc; b=UTfukdHzVAhPs0MX/H7AkImHRS3Yko4RaWw/n68kvCYTD6MROGmarkfCtGo7xMLb3hlT4ys5SP3Hd6knzu9+FMkrhJvQy3rqn5JjKzi29DqEGQfpREZ/47DjYuyUl2uLmM2k1eJcgOmBhLLTb6a5u3djPsXu229AEH/j9Wb1Epw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770466322; 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=JCy3i99i+qLbs/wAQI3hvrm5l/vGSJb2OpG7ZQh/YMA=; b=jMGcO35vP0QaMoe+hpMH7++O8lokIbTf4lYCKkEt4i17B5a/Lr/zyEt26wg5XwkRoH44ORLkQao5d2RuyK5KcYlUHBtakuMX3cI//ym3xvvUrqk9B6Ra6aEoXWss+IjMojH5cxyeTjXvEguwTKRFNsqroaE3ZyY+Lu6qe7I0EuE= 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=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1770466322284940.7180708658567; Sat, 7 Feb 2026 04:12:02 -0800 (PST) Received: from [::1] (helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1voh8v-0007W3-Kn; Sat, 07 Feb 2026 07:10:31 -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 1voh8m-0007GI-Lj for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:10:21 -0500 Received: from mail-pj1-x1035.google.com ([2607:f8b0:4864:20::1035]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1voh8k-00038S-Ng for qemu-devel@nongnu.org; Sat, 07 Feb 2026 07:10:20 -0500 Received: by mail-pj1-x1035.google.com with SMTP id 98e67ed59e1d1-3530715386cso1260650a91.2 for ; Sat, 07 Feb 2026 04:10:17 -0800 (PST) Received: from brian.. (n058152022104.netvigator.com. [58.152.22.104]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-354b30f899csm2178530a91.3.2026.02.07.04.10.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 07 Feb 2026 04:10:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770466217; x=1771071017; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=JCy3i99i+qLbs/wAQI3hvrm5l/vGSJb2OpG7ZQh/YMA=; b=LNVSBaasX0HGb4h/d0CaoETSNAsUhQtvqCemdbZvTnhzjhKXtF94Vj80QebxVJqsIO VZ14NzV2LRvK7D7M+0HPsrrog48DlhIBRlk188AWLmsGDULMjF+Vtpbwc8IWcZjKMuKz 5Vk2+Ws/v7WONu4tAc47E0lGwagl2ym3XQUsEa+CGeTjf4rehgIIpUfIJbCvdlVNNxKC ffsOBfFvF55XtRFVZ5IwS4Rey/KchINAcD6uce2iuxzUNZ80ksVq6/pty0kz78305avc NDvugQYSL1Jw+mj78OVxXnc7T7wEAOss9nAYUeL4qmaTSI3V/koHlqdyu13jrF0EvXYs CqIw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770466217; x=1771071017; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=JCy3i99i+qLbs/wAQI3hvrm5l/vGSJb2OpG7ZQh/YMA=; b=M9bYv9I6/7EC2KOK0knOq1FgbJhvVC3Hx1BttBG1C/hlO91TCDKqI5eDbLVgHZxDVk 0J9hqqgzpqeJ0NN61dcgovv7WM9cP77YxRwm9VM/QTJaCcpO5oUnEwxalxVvErwkol7w VSQr7xgIaBiFyfu4Ap/CKDzSBX0nugInO9s6+LlEwQTZUexlP8Y335bxYz2C/yivTAkX Pri7xVw2ULgjxbDqEdYkYTUqmQDX3v7D3y4+TR3fzB+nAO/5jOGBph4j0hTzddeZinOb Z7Dvj8hbSJSTKZqvgEkggVULiivV7/w4mnqkWHR/ElH6t8ClgOPlUv7N1PivjC1enZlm 81RA== X-Gm-Message-State: AOJu0YyTiOm6JCpedXoc4MW5oIfNkoFjiWWzTwuLthwESrO7axo6CjVH fOkc93ANKEpBBwOmVnoxbHghFrvv1xPxB/7+3jSf2NaBnVPTm2GTsmkX X-Gm-Gg: AZuq6aI8W2u1dX0Rhhfs9ONe+esXFwv0th08gZkOc0fR/NogTOYTAaw7+G5b6hkciKJ 2r//kh5/8ilyFk/cyDBSoyClA1Qb3NRIytT7LWjBIV4ZrIdTFPImyo5/0a+6HxrR5NrMAD/xAg6 bNqBCmDmbJG3ofIP8PyiIJCh6N3gUPhB5cGQxl61282PJ5eFbsYWk8OidXUtYAMZXdTkjjiWTs5 u6jPpXL2sUwI5y5fG2wnbwa//ZCy81pDJ/KAs8sEAhi+aIczS3+xoY3HUsjg6g1WgjXlMeLzBBW zXS0n0hwoKPfY6IjJZNuFrokOjGJR+1mW8bO5tJbSARgz03/4/dW8Rx0AyNnQIJZh6Y+I/bq04c W6mehdfOJBYkz3TtmBFXGVzZJsyqWtCflrqg7myQRcqbpG6oaQYrWQ1KQG8ugKaL/YbTK1YVqvx /0Rp8vuDNHnj1aJ/w+QCjAef8hEYPKBeP0KY0p X-Received: by 2002:a17:90b:380b:b0:340:ca7d:936a with SMTP id 98e67ed59e1d1-354b3e338d5mr4916969a91.18.1770466216716; Sat, 07 Feb 2026 04:10:16 -0800 (PST) From: Brian Song To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, hibriansong@gmail.com, hreitz@redhat.com, kwolf@redhat.com, eblake@redhat.com, armbru@redhat.com, stefanha@redhat.com, fam@euphon.net, bernd@bsbernd.com Subject: [Patch v4 7/7] fuse: add io_uring test support Date: Sat, 7 Feb 2026 20:09:01 +0800 Message-ID: <20260207120901.17222-8-hibriansong@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260207120901.17222-1-hibriansong@gmail.com> References: <20260207120901.17222-1-hibriansong@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2607:f8b0:4864:20::1035; envelope-from=hibriansong@gmail.com; helo=mail-pj1-x1035.google.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, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=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 @gmail.com) X-ZM-MESSAGEID: 1770466323278154100 Content-Type: text/plain; charset="utf-8" This patch adds support for testing FUSE-over-io_uring. It can be enabled by setting the environment variable FUSE_OVER_IO_URING=3D1. $ FUSE_OVER_IO_URING=3D1 ./check -fuse Additionally, the unmount detection logic is switched from `df` to `mount`. Using `df` triggers `statfs()`, which attempts to communicate with the FUSE daemon. During test teardown (when the daemon is being killed), this often fails or returns stale data, causing the test to misjudge the mount status. Suggested-by: Kevin Wolf Suggested-by: Stefan Hajnoczi Signed-off-by: Brian Song --- tests/qemu-iotests/check | 2 ++ tests/qemu-iotests/common.rc | 47 +++++++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 545f9ec7bd..c6fa0f9e3d 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -94,6 +94,8 @@ def make_argparser() -> argparse.ArgumentParser: mg.add_argument('-' + fmt, dest=3D'imgfmt', action=3D'store_const', const=3Dfmt, help=3Df'test {fmt}') + # To test FUSE-over-io_uring, set the environment variable + # FUSE_OVER_IO_URING=3D1. This applies only when using the 'fuse' prot= ocol protocol_list =3D ['file', 'rbd', 'nbd', 'ssh', 'nfs', 'fuse'] g_prt =3D p.add_argument_group( ' image protocol options', diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index e977cb4eb6..a3e0ccb3d2 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -546,10 +546,37 @@ _make_test_img() # iotests. The default allow-other=3Dauto has the downside of pri= nting a # fusermount error on its first attempt if allow_other is not # permissible, which we would need to filter. - QSD_NEED_PID=3Dy $QSD \ - --blockdev file,node-name=3Dexport-node,filename=3D$img_name= ,discard=3Dunmap \ - --export fuse,id=3Dfuse-export,node-name=3Dexport-node,mount= point=3D"$export_mp",writable=3Don,growable=3Don,allow-other=3Doff \ - & + if [ -n "$FUSE_OVER_IO_URING" ]; then + # The current Linux kernel requires registering `nr_cpu` Ring = Queues + # when FUSE-over-io_uring is enabled. Here, we set half of the + # Ring Queues to FUSE Queues (`nr_iothreads`) to test the queue + # distribution feature. + # See the comments in fuse.c regarding the round-robin distrib= ution + # between Ring Queues and FUSE Queues. + nr_cpu=3D$(nproc 2>/dev/null || echo 1) + nr_iothreads=3D$((nr_cpu / 2)) + if [ $nr_iothreads -lt 1 ]; then + nr_iothreads=3D1 + fi + + iothread_args=3D"" + iothread_export_args=3D"" + for ((i=3D0; i<$nr_iothreads; i++)); do + iothread_args=3D"$iothread_args --object iothread,id=3Diot= hread$i" + iothread_export_args=3D"$iothread_export_args,iothread.$i= =3Diothread$i" + done + + QSD_NEED_PID=3Dy $QSD \ + $iothread_args \ + --blockdev file,node-name=3Dexport-node,filename=3D$im= g_name,discard=3Dunmap \ + --export fuse,id=3Dfuse-export,node-name=3Dexport-node= ,mountpoint=3D"$export_mp",writable=3Don,growable=3Don,allow-other=3Doff,io= -uring=3Don$iothread_export_args \ + & + else + QSD_NEED_PID=3Dy $QSD \ + --blockdev file,node-name=3Dexport-node,filename=3D$img_na= me,discard=3Dunmap \ + --export fuse,id=3Dfuse-export,node-name=3Dexport-node,mou= ntpoint=3D"$export_mp",writable=3Don,growable=3Don,allow-other=3Doff \ + & + fi pidfile=3D"$QEMU_TEST_DIR/qemu-storage-daemon.pid" @@ -595,16 +622,8 @@ _rm_test_img() # Wait until the mount is gone timeout=3D10 # *0.5 s while true; do - # Will show the mount point; if the mount is still there, - # it will be $img. - df_output=3D$(df "$img" 2>/dev/null) - - # But df may also show an error ("Transpoint endpoint not - # connected"), so retry in such cases - if [ -n "$df_output" ]; then - if ! echo "$df_output" | grep -q "$img"; then - break - fi + if ! mount | grep -q "$img"; then + break fi sleep 0.5 -- 2.43.0