From nobody Sat Apr 11 23:08:12 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1773069066; cv=none; d=zohomail.com; s=zohoarc; b=GIBGWv3ebuXYLe7AnL490Ab1olhAFge2ZDqmarXXi9Cgw8zESlKwk0nLowFqfqzj/WMZY/3DLi+Dsvf33F7abBceiTNbN61Rtdq+XfMKA/sz+RsJDg2zojYHP2CMuWWTnSFdNyFto+23hbfmGIDpu0N/smVaQaBF4vxTsYNnRhk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1773069066; h=Content-Type: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=KIrJYrtnoXwxSw4V3NuTZZEpmlWDoM3vKo2sYuFFuvk=; b=QKrhJqwNlp9DMalsBKEho9jBGi+UNKYuJ5/HEX5Bsco+hSm66mRkM6ftnRmWOKC4tyNo856UrY9JpMUPcGTgzy6LgnWvIQhPYxvcQ+fxDaK9hNU5dP2OIQKZ7OMqL/cuziQiQr6Du6xpCJE2oabipTNeTFLmvDZ+LYT38AMbEuQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 177306906675798.43781781281609; Mon, 9 Mar 2026 08:11:06 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vzcEP-0000bg-JC; Mon, 09 Mar 2026 11:09:17 -0400 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 1vzcEO-0000as-7L for qemu-devel@nongnu.org; Mon, 09 Mar 2026 11:09:16 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vzcEL-0008Hq-AA for qemu-devel@nongnu.org; Mon, 09 Mar 2026 11:09:15 -0400 Received: from mail-ej1-f72.google.com (mail-ej1-f72.google.com [209.85.218.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-202-nPU_imrOOH6DdHWrn6IHfQ-1; Mon, 09 Mar 2026 11:09:11 -0400 Received: by mail-ej1-f72.google.com with SMTP id a640c23a62f3a-b8f848ebcbbso815831266b.0 for ; Mon, 09 Mar 2026 08:09:11 -0700 (PDT) Received: from localhost (p200300cfd737d0cf29d515fbd6051d53.dip0.t-ipconnect.de. [2003:cf:d737:d0cf:29d5:15fb:d605:1d53]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-439dae2ba5bsm24847050f8f.22.2026.03.09.08.09.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Mar 2026 08:09:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1773068952; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=KIrJYrtnoXwxSw4V3NuTZZEpmlWDoM3vKo2sYuFFuvk=; b=fQuAqKsBF/vIIZy86DtNIN5I6NHNtmCE+oFFfcJKOePkeppGdBwchfY0ueoA3i48xAfdfZ cgUhRk1gAEcOnHTkndQIdqOikyA50mpb0V57oviw58UKABsXfWjuftFDFpCvdb730L9i98 x0E0LKs6eGsloYLKb+Atna6uIDcIMqk= X-MC-Unique: nPU_imrOOH6DdHWrn6IHfQ-1 X-Mimecast-MFC-AGG-ID: nPU_imrOOH6DdHWrn6IHfQ_1773068950 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1773068950; x=1773673750; 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=KIrJYrtnoXwxSw4V3NuTZZEpmlWDoM3vKo2sYuFFuvk=; b=nPhAm6FIKMcNP0uDsbBUV2NLSYkAyZ2P0IYWEOrIzeGWj5INHF9ffu0ImIhKcyupMN VvNoVLUXeneqwszyP2eCvMB2nOmCylIgGxYFSz6zE/SfWWIBweNc2nEu6xZch0oOxWuO WusvtBjyUZE9U1BPv7fPeJddqxk5FMtq/onlYux5aVpU+30V4BFCwrhJwUS4LF4lLiNJ na3WJL++ryeQa5XZSfV+FgcSuJS1PYBjjUjWXAqLeNV01yDnxQwDGIlFHaypJBgfHWgU 4UNgx+3YyJHWJfa4lXxrf4hrxaXth9nDS7lyNhZnDfpp6Fob6Il5C2VoiIk/sgW86XLs vG1Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773068950; x=1773673750; 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=KIrJYrtnoXwxSw4V3NuTZZEpmlWDoM3vKo2sYuFFuvk=; b=b0BQX7o83xwH2guOmUtgtF99wX4hv3v2f+D0meF5M1jqI7I88kYnLBJ2xo/BUgSPuF 6n0mgOiRCyDxwrhNrIHPDrUhUiRuem56MfZnE+5gGqWArlnl0qX9NsBrP9LtllrlyUgm A0ITEG2Uo2NlODCi+FYU7gP3UfI4A/Mf63aBWk77DvOF+tjZuK3O+etbMLs+PN4g4vgi ohe9yZCremSDXSaGAAM+xB7f6KWLS/b1Qx3Z7AEskrhtVBrTc1WcpSVBgeitcOPANzxA JEeYlDFzL6GQ7JfUApetnl0xhwhyCR9/pK9u3rT9LUsRBOJiytj7nrHhVZxINYe117lG C/Qw== X-Gm-Message-State: AOJu0Yzx65BuW6qyFZ/eNfYRw768EgN3XApu1gcz6Q4BrzYq3r3VcbWh 0vfoWioNgwU3eGkr4abXQ74IdvHA3vPBctybPKDx8p29ELRIr+lkacoEM35wJoYZRlpMNxTENOp Xpva1huzRmx7laQhPB4gnpDxyUqk6xIxHM8FIe6kXTsXDR5bXX64Q6D1B6/ZtxY/p X-Gm-Gg: ATEYQzwQ2aI2+86Z9LVbYj1SP1cei1t9sZeciirm15PxIz2zsIub/peIJvtuOOEk6SI 1gyf2HOy4Gw628ONpwgXRTZ+dRpqKBt9619NDDTSybxNUSeB/NzSCiQ8vPTZesIDxJ5eiYQRt+4 muw37raqZ5tKNrX2tjPMetyP1mjTS00JoP4CDeKHXi0gczvlp2kB//KYP1tz/TVs7frFBHWQ8Tj ducReEzp3svsiaogce6oWE5m7GVcioKwIY7JNZhuuvF/FYBuBxnBCcOjZk0Q3k2aBHFfTgiovQx J3poD+nT6jqyZezJG/1fAzWnzSTrgMnUouj5M/QKNnI/zYJfpf34zPjga9PEBzfb9/kQcQNNG8b DQP9+yItv2sYY/fhCrAuRzHBylX8Z8c40gQbksxKEr3ACsrGWNC5HPz6AOJLFqgEJyZuZ2sI9UD WD1IFz X-Received: by 2002:a17:906:fe4c:b0:b87:1fe6:f223 with SMTP id a640c23a62f3a-b942dbafa2emr620155266b.6.1773068949892; Mon, 09 Mar 2026 08:09:09 -0700 (PDT) X-Received: by 2002:a17:906:fe4c:b0:b87:1fe6:f223 with SMTP id a640c23a62f3a-b942dbafa2emr620153166b.6.1773068949296; Mon, 09 Mar 2026 08:09:09 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf , Brian Song Subject: [PATCH v5 01/25] fuse: Copy write buffer content before polling Date: Mon, 9 Mar 2026 16:08:32 +0100 Message-ID: <20260309150856.26800-2-hreitz@redhat.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260309150856.26800-1-hreitz@redhat.com> References: <20260309150856.26800-1-hreitz@redhat.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=170.10.133.124; envelope-from=hreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -3 X-Spam_score: -0.4 X-Spam_bar: / X-Spam_report: (-0.4 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.819, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.903, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1773069069781154100 Content-Type: text/plain; charset="utf-8" aio_poll() in I/O functions can lead to nested read_from_fuse_export() calls, overwriting the request buffer's content. The only function affected by this is fuse_write(), which therefore must use a bounce buffer or corruption may occur. Note that in addition we do not know whether libfuse-internal structures can cope with this nesting, and even if we did, we probably cannot rely on it in the future. This is the main reason why we want to remove libfuse from the I/O path. I do not have a good reproducer for this other than: $ dd if=3D/dev/urandom of=3Dimage bs=3D1M count=3D4096 $ dd if=3D/dev/zero of=3Dcopy bs=3D1M count=3D4096 $ touch fuse-export $ qemu-storage-daemon \ --blockdev file,node-name=3Dfile,filename=3Dcopy \ --export \ fuse,id=3Dexp,node-name=3Dfile,mountpoint=3Dfuse-export,writable=3Dtrue= \ & Other shell: $ qemu-img convert -p -n -f raw -O raw -t none image fuse-export $ killall -SIGINT qemu-storage-daemon $ qemu-img compare image copy Content mismatch at offset 0! (The -t none in qemu-img convert is important.) I tried reproducing this with throttle and small aio_write requests from another qemu-io instance, but for some reason all requests are perfectly serialized then. I think in theory we should get parallel writes only if we set fi->parallel_direct_writes in fuse_open(). In fact, I can confirm that if we do that, that throttle-based reproducer works (i.e. does get parallel (nested) write requests). I have no idea why we still get parallel requests with qemu-img convert anyway. Also, a later patch in this series will set fi->parallel_direct_writes and note that it makes basically no difference when running fio on the current libfuse-based version of our code. It does make a difference without libfuse. So something quite fishy is going on. I will try to investigate further what the root cause is, but I think for now let's assume that calling blk_pwrite() can invalidate the buffer contents through nested polling. Cc: qemu-stable@nongnu.org Reviewed-by: Kevin Wolf Signed-off-by: Hanna Czenczek --- block/export/fuse.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 8cf4572f78..cea9de61f1 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -301,6 +301,12 @@ static void read_from_fuse_export(void *opaque) goto out; } =20 + /* + * Note that aio_poll() in any request-processing function can lead to= a + * nested read_from_fuse_export() call, which will overwrite the conte= nts of + * exp->fuse_buf. Anything that takes a buffer needs to take care tha= t the + * content is copied before potentially polling via aio_poll(). + */ fuse_session_process_buf(exp->fuse_session, &exp->fuse_buf); =20 out: @@ -624,6 +630,7 @@ static void fuse_write(fuse_req_t req, fuse_ino_t inode= , const char *buf, size_t size, off_t offset, struct fuse_file_info *f= i) { FuseExport *exp =3D fuse_req_userdata(req); + QEMU_AUTO_VFREE void *copied =3D NULL; int64_t length; int ret; =20 @@ -638,6 +645,14 @@ static void fuse_write(fuse_req_t req, fuse_ino_t inod= e, const char *buf, return; } =20 + /* + * Heed the note on read_from_fuse_export(): If we call aio_poll() (wh= ich + * any blk_*() I/O function may do), read_from_fuse_export() may be ne= sted, + * overwriting the request buffer content. Therefore, we must copy it= here. + */ + copied =3D blk_blockalign(exp->common.blk, size); + memcpy(copied, buf, size); + /** * Clients will expect short writes at EOF, so we have to limit * offset+size to the image length. @@ -660,7 +675,7 @@ static void fuse_write(fuse_req_t req, fuse_ino_t inode= , const char *buf, } } =20 - ret =3D blk_pwrite(exp->common.blk, offset, size, buf, 0); + ret =3D blk_pwrite(exp->common.blk, offset, size, copied, 0); if (ret >=3D 0) { fuse_reply_write(req, size); } else { --=20 2.53.0