From nobody Wed Apr 2 13:15:35 2025 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=1742919138; cv=none; d=zohomail.com; s=zohoarc; b=oK5DjpZsWtCuAAZSe1vVqWH0fTAev/FQok/uPqA9MKuEe3SoC1uCJf8mhcm65yVwYsA9ju3X7z81BLLBSbD8S2Ps74v3aLbH3W+mLvttCuU+N4jHTkg9mPp28u83asenjWxQwYACccjwIlnD0aYj9vbdBS103CLsriH+aG3451U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742919138; 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=vMGs3E6Ei0m6WABpctn8IHBAUugpx7h6jWwNQOkWU5M=; b=bCEQCFbJssIrYmq9QOEdaMjObNuLH/X914VgvQ6vX4lq5wTCyFmrGmrgy9RpU1wXgDYUTRsbpgUNCTKgMDHlJdAVSvhvjQmhjJm4jyLS4ZAPX80NAtao7ig/hSqQx8Ag3jBi0iAZhACATdyh3pSpvbBYTdkIMvyV3AMfJnMgPzo= 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 1742919138619378.55440600372856; Tue, 25 Mar 2025 09:12:18 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6qd-0007D3-0B; Tue, 25 Mar 2025 12:09:51 -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 1tx6ox-0005Tz-4n for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:08:12 -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 1tx6ot-0007Z4-HX for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:08:06 -0400 Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-554-E_QsW6--Pd2H0sbhOk-UMg-1; Tue, 25 Mar 2025 12:06:41 -0400 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-43cf327e9a2so46327995e9.3 for ; Tue, 25 Mar 2025 09:06:41 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-43d4fd277d5sm155950915e9.19.2025.03.25.09.06.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:06:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918882; 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=vMGs3E6Ei0m6WABpctn8IHBAUugpx7h6jWwNQOkWU5M=; b=bM15d98EwDwnq3JswC1SurV+wvlmxiZVK3h92R7tc+kkS4R6OFhyyr4WwcHPY4IHCzoq5z hUGaoOKMXqTGAIbZGAxTsbfbTIqor+bi3maMFR2VAsBUFotKf+Sd/wXUXpHEQBUaoZhuTz ofSqEXR997r1gIQSuTspgW9tP1UgOXM= X-MC-Unique: E_QsW6--Pd2H0sbhOk-UMg-1 X-Mimecast-MFC-AGG-ID: E_QsW6--Pd2H0sbhOk-UMg_1742918800 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918800; x=1743523600; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=vMGs3E6Ei0m6WABpctn8IHBAUugpx7h6jWwNQOkWU5M=; b=uoyg0MV56P5xYgbbuKgFLKi6maqFBV+tXWQIZ/X9ng3kNn1f7G7H9euDiI+lB58N8C zbTyBC44cZ+eDRaP8k/0U2WLCedXzpBWJ3wrZXFPTAU0nJpZDS1aS0w5B76v0k9bQReS ncA8VQDrZ3bs0YR+8yl1jR1agbDzLoza0hRXNUlxZl0QEnTy/+dH9REu6MxGPFpUuSsI OMlIfoXNFOm2w89aRyA7SuPVDNKdUG7pSrnjYlRmqc8dq/Kiwp3ex4+6s4hFsB06A9Q1 SI1/qB9DqYVqiTwZgW+LFiDx0HXu4YK4p4ohd/5ZzOKp5GpN3f2x2sKdhNl6xn8LbQV0 NKKw== X-Gm-Message-State: AOJu0YwOGy04sgv7ajk+WsDAoVb81Kj12gI6bv1BJoA9TDQplnnWk0lx z0cKz/Ptv37sg/YVZ04ZHRNbUtohL/1YbXQGU6VR6aAl4HAb81t4Zo5p5BD4QGvQxaiCOObC1IJ V2dERIwyOn4e935SFWiDhA5dq8yeuzMENe5IWfMCnD3wSvO61HAi/ X-Gm-Gg: ASbGncvlKVvRYTMZ4pp/raAN3e7r45LTXB3mARLeKjIHCWXH0ViKpbMuRYXsy9pXE8g pXtG8Hkbo4k3gs5utUVzmiMdse8Z2uoAxB7O2eW2Iq3emcQXgIXKWWgmbNYpdljAAVJUYnkSldG AeK2mbH8eaIqQ8JAVoa+Z2IssTpzHDPiIq8p/DkidwHwIISwQ8egm9AMzsty3NWrd+SXbs//31a gyhcKsOAFBbcFVza+0ZP/KGHqNiFCZlBR3rPl1YkuqfT4w/uXedJ3MCibH2Fktdzur3uPGtnOmr lD77EqLeddoZILdxOT/+6LuYYu+NqAmNCTdbTuIV9XU3MVaaNJrrES1OlIlIRGgoxZzCO3NVdw= = X-Received: by 2002:a05:600c:b8d:b0:43b:ce08:c382 with SMTP id 5b1f17b1804b1-43d509f6797mr176878155e9.16.1742918798719; Tue, 25 Mar 2025 09:06:38 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEkCedYmAoZ641KoSS1am6gtapvsT19N1TBNd5OEUdcmp12ej5vJPMbwQWip3GAukepRcpNYQ== X-Received: by 2002:a05:600c:b8d:b0:43b:ce08:c382 with SMTP id 5b1f17b1804b1-43d509f6797mr176876355e9.16.1742918797260; Tue, 25 Mar 2025 09:06:37 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf , qemu-stable@nongnu.org Subject: [PATCH 01/15] fuse: Copy write buffer content before polling Date: Tue, 25 Mar 2025 17:06:35 +0100 Message-ID: <20250325160635.118812-1-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-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: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742919140157019000 Content-Type: text/plain; charset="utf-8" Polling 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 Signed-off-by: Hanna Czenczek --- block/export/fuse.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 465cc9891d..a12f479492 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 polling in any request-processing function can lead to a = nested + * read_from_fuse_export() call, which will overwrite the contents of + * exp->fuse_buf. Anything that takes a buffer needs to take care tha= t the + * content is copied before potentially polling. + */ 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); + void *copied; 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 poll (which any blk= _*() + * I/O function may do), read_from_fuse_export() may be nested, overwr= iting + * 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. @@ -645,7 +660,7 @@ static void fuse_write(fuse_req_t req, fuse_ino_t inode= , const char *buf, length =3D blk_getlength(exp->common.blk); if (length < 0) { fuse_reply_err(req, -length); - return; + goto free_buffer; } =20 if (offset + size > length) { @@ -653,19 +668,22 @@ static void fuse_write(fuse_req_t req, fuse_ino_t ino= de, const char *buf, ret =3D fuse_do_truncate(exp, offset + size, true, PREALLOC_MO= DE_OFF); if (ret < 0) { fuse_reply_err(req, -ret); - return; + goto free_buffer; } } else { size =3D length - offset; } } =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 { fuse_reply_err(req, -ret); } + +free_buffer: + qemu_vfree(copied); } =20 /** --=20 2.48.1 From nobody Wed Apr 2 13:15:35 2025 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=1742918882; cv=none; d=zohomail.com; s=zohoarc; b=J8bYJWpin8RhNQajOz88a66TPDw7AVmyRB8bSfUSc0s3QE/6wYo9CMfa6XXVF5YczU8PxL/dee8pufBddfHfC/J2qS/2VnQs24yXVxH6lvgEeua74SpwdFu4FZN5+Bd3z5LOgxVFmo2wfsLGarL2zSys/ucsGKxpPCKtpxesCeg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742918882; 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=ehiVzbvvOQFr7YUJ9/vdGbUS2C1aGZiIVOQbC1KmTxg=; b=DFFQCoCtqoQOGnOWRCNzMgt+kn/3UWzijQkTBECZpPffoaNVueA/m0Kl3oT08oAxMSOTm8gHq5elJ9dk/3cmm2aoguGvJ3eTqprPJbNK6Haq6O5URM1fozDy3Jc/K8Inbm81Cy/hOqx10ZqcTwgYJXX2ttnI9CYvfFJNF/NxO+o= 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 1742918882145146.17575573781232; Tue, 25 Mar 2025 09:08:02 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6nz-0004QS-Ay; Tue, 25 Mar 2025 12:07:07 -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 1tx6nw-0004Pj-Fb for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:05 -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 1tx6nu-0007Jr-7a for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:03 -0400 Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-650-L--i5pZHOoquXAD6gUS4Aw-1; Tue, 25 Mar 2025 12:06:59 -0400 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-3913f546dfdso3136578f8f.1 for ; Tue, 25 Mar 2025 09:06:58 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-43d43f556afsm203550785e9.19.2025.03.25.09.06.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:06:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918821; 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=ehiVzbvvOQFr7YUJ9/vdGbUS2C1aGZiIVOQbC1KmTxg=; b=JqDEjOt1Ts+OeWJN/PYDQsfoo/3P2pabCsSRW+AhSNzcPkRlV1KNejhXH4NKExJ+wcKs/+ 62FWr0CQl0Gk2u0meUNQ3lFFdJ90Rp6JO2rmZb+YZudNHXmk3t205HPyClSxthtsHw4Ptm ukR3IQ74G9daVZuSCO7+CzmTEkTcQqA= X-MC-Unique: L--i5pZHOoquXAD6gUS4Aw-1 X-Mimecast-MFC-AGG-ID: L--i5pZHOoquXAD6gUS4Aw_1742918818 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918818; x=1743523618; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ehiVzbvvOQFr7YUJ9/vdGbUS2C1aGZiIVOQbC1KmTxg=; b=Vb0440iJZYzMRdAF09PlwkquAur2AjJVgBbxikLGDBMGaAUUM9ixUMIvalkRLGLWwE wpU6sAuauy/1TCiE+mKsJBoQaGeSReUvywLuWsp1xLzzABYI9accp3UkOFEHmlwzF/gY VizG+e/IlW6My3JCXKIZrswU8eb+bM7HcfRxfIeQhOSFekmR8zz9WTqjRBn5oyPrP+Nh 3vhMIf3dTVyKuGvy2oTey7FZY5Vikk2RL19bDSD5V02HEN/6rZrjvI5U+Vsx7oX1+OnE 1jZ1RKXXt8zPf68J42EjecdnIqMv7upQrIDpCkH+xmniEiEJd46XZzHT+MFQ0ppajJhj 66SQ== X-Gm-Message-State: AOJu0YwY38jDmdyzXsMBT+cx8Eo0sjuwA8+6/NzFjTehk6LHJJwNIJJH YpfOZc67wwcZnbiZ7Klyjc0wF1YtGo+wIp9LsMTzc4gGmmR4sTSEcQp+z0MNw2JXYEkZI7iAFhD HQyJ/eWqVneeSPPRSfbZWaP7gW+VYekXKs0deVxHgU54xwIanIvOr X-Gm-Gg: ASbGncszgjgucVGg/TwYE0ae6CyC0QizfIDg+bVs10exlYzerq+EoZHk8Uja1i4Yx9A h8Sj5ajdPJn1Mi9+Jrp6oOWOgL4hUuKySSlWSfDYiRJ9uc5il0yr93fbV4ZxFcKNJqgSCbfnqlT HzR/8qG0dBd4FrmH3ZvLMgJl047ixsZoe0cufrUgJHaCzaW9bd/w3tXzR+tkfzW8fuGpFTjq9hb /4CriNDYeKO61KMPa3ij1BWnmx6o/H6zcVn6vI/TSYhSA6BWjmHjmoJ1zO2cEaArxH8yHRfaCkk owNw1FFAemUSD7JC6g+mcTVEsPLU2P5essuEA5pLO/sZada6EsQ9GWgrW+FK+Pku8oP26pJnPg= = X-Received: by 2002:a05:6000:2801:b0:39a:c9cb:8296 with SMTP id ffacd0b85a97d-39ac9cb82ffmr1855246f8f.22.1742918817855; Tue, 25 Mar 2025 09:06:57 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFzjwPgzg4o/qXq6inyog6I78Gddk11DDmqtMmY52xljdoT7Rvla6jHSHRiRdM2pLcDj7Fnrw== X-Received: by 2002:a05:6000:2801:b0:39a:c9cb:8296 with SMTP id ffacd0b85a97d-39ac9cb82ffmr1855218f8f.22.1742918817530; Tue, 25 Mar 2025 09:06:57 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 02/15] fuse: Ensure init clean-up even with error_fatal Date: Tue, 25 Mar 2025 17:06:42 +0100 Message-ID: <20250325160655.119407-1-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-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: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742918882801019000 Content-Type: text/plain; charset="utf-8" When exports are created on the command line (with the storage daemon), errp is going to point to error_fatal. Without ERRP_GUARD, we would exit immediately when *errp is set, i.e. skip the clean-up code under the `fail` label. Use ERRP_GUARD so we always run that code. As far as I know, this has no actual impact right now[1], but it is still better to make this right. [1] Not cleaning up the mount point is the only thing I can imagine would be problematic, but that is the last thing we attempt, so if it fails, it will clean itself up. Signed-off-by: Hanna Czenczek Reviewed-by: Stefan Hajnoczi --- block/export/fuse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/export/fuse.c b/block/export/fuse.c index a12f479492..7c035dd6ca 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -119,6 +119,7 @@ static int fuse_export_create(BlockExport *blk_exp, BlockExportOptions *blk_exp_args, Error **errp) { + ERRP_GUARD(); /* ensure clean-up even with error_fatal */ FuseExport *exp =3D container_of(blk_exp, FuseExport, common); BlockExportOptionsFuse *args =3D &blk_exp_args->u.fuse; int ret; --=20 2.48.1 From nobody Wed Apr 2 13:15:35 2025 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=1742918922; cv=none; d=zohomail.com; s=zohoarc; b=krJdIrhxPAeItaBIh1FcBWandDfY+eA1LwQJqfxFlqg7k2YtESCOmf07JqjfCGhbL8JKJa0guQ5wS5Gd60sFZ0puVubdbyU9BCF+tqz3freGV4/KwxCDd4512lqp+HAfBcVIIsxoaROcf7BitcZGmcJJyINbidAfqYGVmWgwMMs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742918922; 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=ImDkB0+F2AZZ6nVMjW8YwmsQbVMtET9p6F1zLsjNo7U=; b=cUKZgoUYTiXHlyBiDZHe/aMViqmki6oWtms78B7G5Qa1pz07VAeFOFO0FQGhJE+LJQKuALkilrwqhBBbiKWU2tcZ+4PMUwKR8Oc9XSs4Ex/KBgBxj8MwtRr+QsnwK4MfZ6wHJsCAPygsb0Vji6IrP4MPsERtNswzTCDtJYlgI8w= 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 174291892240388.55440473851183; Tue, 25 Mar 2025 09:08:42 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6o6-0004Ti-KR; Tue, 25 Mar 2025 12:07:14 -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 1tx6o2-0004SH-HT for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:10 -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 1tx6o0-0007Lr-LO for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:09 -0400 Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-186-5DpyGNxtOZW8r-5WyVNuTg-1; Tue, 25 Mar 2025 12:07:04 -0400 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-43d4d15058dso41030505e9.0 for ; Tue, 25 Mar 2025 09:07:03 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3997f9ef098sm13817927f8f.84.2025.03.25.09.06.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:06:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918827; 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=ImDkB0+F2AZZ6nVMjW8YwmsQbVMtET9p6F1zLsjNo7U=; b=PaP5TffHGIVJ6KW8KbAfzalAB3gpK5Lj3KSDxTmWYWRgT+vjEgiPpH2BnhsRXfbaUefa+7 DBeOdQOftLzoX5miWJz9A1NhEFI9+W6e8u/TNCPEaw3z7kzXbYMtIG1uu6hKJCXLAPQzme hXEDYNN431j5DCQp98ySMxPw18mr9KE= X-MC-Unique: 5DpyGNxtOZW8r-5WyVNuTg-1 X-Mimecast-MFC-AGG-ID: 5DpyGNxtOZW8r-5WyVNuTg_1742918823 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918823; x=1743523623; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ImDkB0+F2AZZ6nVMjW8YwmsQbVMtET9p6F1zLsjNo7U=; b=oxtYwaTW3zo7M2Ki09lcwkhP6q++SRrbhxQWYERPFPBL7W9veJUlCyjBPVWMQssubt werYNu0O3z+h9afrv0vH0hc56M90Q8rJzqV9a80e9x9q5QOzBWYiOhhs314SrXf9OlPS 2QYhK08CgUAw6miGryWXGUtfQsuv4XW3MAEWRxmc7qiHoScn3/4IYSbqrg5QNGLVXier 1J0G312uCDNzxAus9qFJ/dHfG7wtX5xcSrbZgkKxTDxGo+iifnhE2opLbEQ+MGeOqFm0 yGSE6efTV2UCrj6owjmClo94kyvA3XoUd6En7sLp1WNsMHiOFDTPecVsA5IQtOoZ9oGf oDEg== X-Gm-Message-State: AOJu0YzzyM+XBnQhpWNJzXnBOVefmmfcFyk22hrNHTr+lOZs/tP7L8pj CyuLixcJJzVINbG6Qzqs8u8x+D9edVRJ0tqcNmU1Rd+EUNRigm6KS52E5qDR9PZ02HsuqjxZSjV +8QfF2PJfuabfkz9B63HFk7wNnocXsZaJNqb+NeZhakWYzUpWxP6h X-Gm-Gg: ASbGnctendWqyvFv8y9PQubl/Zee4SAlXkU33PblbeluAgZyTefgMYNvCkz/SIrpKGZ HEDnQmfEHBAkh5JLzCs8S/McJj4y0XbTxXuL1EVpHtxNhKPYkHd3N8giKkdmnZWRYVvhCujujC1 4j2eHZ4tBfYAGKgGgaVmmdugr28HMdh7+giOWk2vsnGV9/2TShqoP8PNQ2r3FIV+V+Ao90IY8s7 HntAfIfQFSP3mu57IKPC4EV50h0IYl1u9mQ4UVMyrYhHxjNeV4gL5+s2VK4dBn2WO9C+JYVk7FI fgyNHO66d60Mw/AiDQre4IbvnWX36kV10ij/5EtEFZnYQI7srIGL5ld2PJOM9TB4G5VC7JcU3w= = X-Received: by 2002:a05:600c:3c9a:b0:43c:ec28:d303 with SMTP id 5b1f17b1804b1-43d5a36f0d4mr93134565e9.5.1742918821645; Tue, 25 Mar 2025 09:07:01 -0700 (PDT) X-Google-Smtp-Source: AGHT+IF3DGszoH+yrDZ111N/7wi06iAhmWrV66Fa/FOz+AkC7suYLZQBJlrnfUysDiZPFb7hecHvfw== X-Received: by 2002:a05:600c:3c9a:b0:43c:ec28:d303 with SMTP id 5b1f17b1804b1-43d5a36f0d4mr93133995e9.5.1742918820945; Tue, 25 Mar 2025 09:07:00 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 03/15] fuse: Remove superfluous empty line Date: Tue, 25 Mar 2025 17:06:43 +0100 Message-ID: <20250325160655.119407-2-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-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: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742918924072019100 Content-Type: text/plain; charset="utf-8" Signed-off-by: Hanna Czenczek Reviewed-by: Stefan Hajnoczi --- block/export/fuse.c | 1 - 1 file changed, 1 deletion(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 7c035dd6ca..17ad1d7b90 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -464,7 +464,6 @@ static int fuse_do_truncate(const FuseExport *exp, int6= 4_t size, } =20 if (add_resize_perm) { - if (!qemu_in_main_thread()) { /* Changing permissions like below only works in the main thre= ad */ return -EPERM; --=20 2.48.1 From nobody Wed Apr 2 13:15:35 2025 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=1742919024; cv=none; d=zohomail.com; s=zohoarc; b=leCR/IYGKYVNG2D4vbGvgtP38LaF13lmNEoGAlGKnZRxl+ublvwltOG2W5EfAEceEIi8OrPHBrkyl4FK9eViEY6Bnsp6ysyUNXAx+IYsXFuvVajZs8z5ThrIVWJfBEwBKsvLjbA+iC/g6CdAWoZ8OOt9vtRuJC68ezQE0Pyo5V8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742919024; 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=jUQnGlHs5herHOASbjnzqcyWsb2S34k63P/LGi0N478=; b=UTqPyPK0LRTWRZYEGqR/YR1jbrRdx38mBGV+J0Yy5dO1346byd+kxsaT+Uie0PYoNI5tw72VcXYCtm6mT8snsH+gmIeLSFCH3i0kshoVRtE5PprVytmenX45oArZhwAr1FLFRc+1P57g9nIwFumkQ9vQ7zdGIzOGv3HtGiK2GS0= 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 1742919024307543.2981937696043; Tue, 25 Mar 2025 09:10:24 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6o6-0004Tm-K6; Tue, 25 Mar 2025 12:07:14 -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 1tx6o1-0004S3-Ta for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:10 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tx6o0-0007Lh-6n for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:09 -0400 Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-641-Ph5CsxDDPcqeFndm62fv3Q-1; Tue, 25 Mar 2025 12:07:05 -0400 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-3912fe32b08so2992582f8f.3 for ; Tue, 25 Mar 2025 09:07:05 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-43d6eaa2fe6sm18189345e9.1.2025.03.25.09.07.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:07:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918827; 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=jUQnGlHs5herHOASbjnzqcyWsb2S34k63P/LGi0N478=; b=EeECdsVlHa4CpxOiUAf6XuUf40Yzywm8tDe871EDYzEgVXSJa9sV130X8bGiYQZK0I2p4c 4befOKTPKcOyyehZ+V3QeivoZYZ1MEq+caW2U8QU9VQNvCjHPW5YPaXZcHdnKBQyEbv9Th dYQD748lSns589tENwioF0wBv8IPKgc= X-MC-Unique: Ph5CsxDDPcqeFndm62fv3Q-1 X-Mimecast-MFC-AGG-ID: Ph5CsxDDPcqeFndm62fv3Q_1742918824 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918824; x=1743523624; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=jUQnGlHs5herHOASbjnzqcyWsb2S34k63P/LGi0N478=; b=vYRqxB6Sr+o05clvhJ3KpOrOF+6c1PhbdkHOjUifYoWcXqsFHEWoXrN/LSGsa2lOzY zPaUKe3GEIPjAueQl27Hh+KvIgfr/3AUh1X+lT5HOuRLmJmqat6SQ/i7x2jODh1aRJFT drpT4IaBToMYrRgP1BVaqXbOUGg8btDjM0as5NYNBpW7sIYTLPh/Y4g8WQkrpp8TYgaD /2gUX4M5KY53Vc86uTecap+To9tIPqIu+Ej46/XNCuiGqYaukHd+Nq4ojxGQ3sv1SE3N pzVBnmuofg7EaxVIK4OMgHYUOv2K0NvzcpsQNKJvSXssefyNrINqUcvxZHtq9Kj4DPOf yrZQ== X-Gm-Message-State: AOJu0YxnREdJwx70qBKxht01AwDu9swM39y4VaHUOk/Ap/QZT9SpJzwE 50Z1qeDcnzVzlMCh7ROHNvkmtuQ3VjvDsjgrATtQv/aXOvZqffHkDDGKA7v0+FJQG6ZtnockyLk bvaAkAscKpdu5AqHi2HJEW89niL18U3Y7qMprYrH/atJxLmAQI8aN X-Gm-Gg: ASbGncuFILnU3/NekEokGUJZkSK4pEYg+Hj7dpx38soqv81k+Ha8hFKseTxM4++yhGl U722e62qqYtDN4pmS/D/YVtSEHBjLdrGnlSSNcEpRCvI84k6NtaN8V13Ue6VDjTVIPHP7XI3Gbg GWYVeuEmG9exBysKxQZZP5eK0TW8RFkBgNka1qsM+lLYM/CnCC9JO4PaobB5BP7lmd3og6PPVOU NAWDtFDCUEwsyESjRLFvE7BJO405aqV5cvbAEkGecaZ2LSQJ3Juvir3CrW3m88X8MnhlGN1sUau O0Di9k3F24xwLDcsK7KhoMvGak5f8Kq2BgI6plVKVlEg7xNlJ0o9RkkahdMGdx1GoqDibnT2Ow= = X-Received: by 2002:a5d:64e7:0:b0:391:13ef:1af8 with SMTP id ffacd0b85a97d-3997f9423admr15435986f8f.54.1742918824222; Tue, 25 Mar 2025 09:07:04 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEaf0YLrRC/R+zcROFM6QCU8cTlxCMK+lfkNomyXJgbPKFJFbTxGOheDY38iULhnmPgOAhJog== X-Received: by 2002:a5d:64e7:0:b0:391:13ef:1af8 with SMTP id ffacd0b85a97d-3997f9423admr15435945f8f.54.1742918823796; Tue, 25 Mar 2025 09:07:03 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 04/15] fuse: Explicitly set inode ID to 1 Date: Tue, 25 Mar 2025 17:06:44 +0100 Message-ID: <20250325160655.119407-3-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-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.129.124; envelope-from=hreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742919025217019000 Content-Type: text/plain; charset="utf-8" Setting .st_ino to the FUSE inode ID is kind of arbitrary. While in practice it is going to be fixed (to FUSE_ROOT_ID, which is 1) because we only have the root inode, that is not obvious in fuse_getattr(). Just explicitly set it to 1 (i.e. no functional change). Signed-off-by: Hanna Czenczek Reviewed-by: Stefan Hajnoczi --- block/export/fuse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 17ad1d7b90..10606454c3 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -432,7 +432,7 @@ static void fuse_getattr(fuse_req_t req, fuse_ino_t ino= de, } =20 statbuf =3D (struct stat) { - .st_ino =3D inode, + .st_ino =3D 1, .st_mode =3D exp->st_mode, .st_nlink =3D 1, .st_uid =3D exp->st_uid, --=20 2.48.1 From nobody Wed Apr 2 13:15:35 2025 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=1742919227; cv=none; d=zohomail.com; s=zohoarc; b=lop512rHJb56DaCA+tRc8WPDxvVZXqJDC+xlqte7T6KqkIiXiyBN4JaFAhPjDSWe/7AouwwAwW0hpcl/mdUGHzclmQkjjFEqerUnTbo/NCsEP8pDnx9DuXsAxTwV/rZs1TKO7oV9dlftyrOuL1Ce9WoDlYeoFyhJuFevclNQno0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742919227; 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=jhcRNjx2BrP+0kRyGk0tVLJsIELhnDkDYM8TRdfrTQA=; b=UuM4Gyt2uMdldS0Nh4LH0aj+N0v6JUw3XhUNgbbllN9za2zV64blnC65CnipkXFaufzzv9zjpm08yYkba3blaXzNSh5ojOapYdyesd3Z/5EUVmZFDKj/jlEQhleUTFq7+QR+fNUSlmaVNX24VLx4GUuM5rEIzS750wnhHpHfgzQ= 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 1742919227512584.708369713475; Tue, 25 Mar 2025 09:13:47 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6oU-0004Vp-43; Tue, 25 Mar 2025 12:07:40 -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 1tx6o5-0004Th-Q2 for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:14 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tx6o3-0007NJ-UT for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:13 -0400 Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-365-xxzk1bPrPd2iLJQ1RvTv3Q-1; Tue, 25 Mar 2025 12:07:09 -0400 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-39ac9b0cb6aso534651f8f.2 for ; Tue, 25 Mar 2025 09:07:09 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3997f9eef37sm13852281f8f.85.2025.03.25.09.07.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:07:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918831; 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=jhcRNjx2BrP+0kRyGk0tVLJsIELhnDkDYM8TRdfrTQA=; b=XdDtLRRg1aD81kcszyHJ4NB6JkFLEtCNUuWZgPjiTibzOVePm8c9A6VhDF07FsmIwj8ZZH WLPbxm6cpETnHB2OfyoL4fsCskGLOLIEr1x9/ChQg2KpJnvrnm4Cp1URqEDp+pNoIPRm+I ezuB80ZM3l05qeSDgOEWl7YSJ5qeOM0= X-MC-Unique: xxzk1bPrPd2iLJQ1RvTv3Q-1 X-Mimecast-MFC-AGG-ID: xxzk1bPrPd2iLJQ1RvTv3Q_1742918828 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918828; x=1743523628; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=jhcRNjx2BrP+0kRyGk0tVLJsIELhnDkDYM8TRdfrTQA=; b=UVBpmw7yNWhKzsLj8ylErD0nZjwbObHHQaC0slCFIeBJ5jAiuhxDJ98kvT7b9OE+Q6 I5mswI/Mqu5CGsjRDP0IEv6Z/GRlDJE58qc7H90Gvl/mOowUvi8GqXFpGrTWp6A7Qeik HiGdidGvWu2iwyLJr3xtpidrKnuovclLM3J5dVK28y45B2vAiGuGs6gWR5OJj7WutFlg FMsHpNU02u/8KvspvW/juABemZrBgHfQdTKNbv1zsaOjkY3F+C1tSL3oiAXY60cE35TO LtbIkf+BRKOXb/ZQTK0dgvwSvL2Un9EtozupHeIjRd2EzYa5rbLdYCMXPHT4baCtDCp+ ugPw== X-Gm-Message-State: AOJu0YycD6XzOX0qGGoBHqouQvD/BP9R0WbMoNVqMW569Ae+Thvoc1CP p9TbFEn1RgSQkkac8Rf2VgZ9GsEKxh6sqzxlz2LhFMXbz3EtYBtfBhDud68nVfDPFZLLEl5vgl4 4szujzIZjGOQjnpixL0DLmchwWI8X5uU8q6TPrIwFvz9Ft1PzJUMq X-Gm-Gg: ASbGncucMXbBYv9uPJM3mLSRZLvvLLt5pHytSScjIQlQ9FyAb8crXjrAoYqA50Td1xk V5BCzi1hZG/yWFf6kQ0i/cOXisizUpYWi6ZSbD+ooAeO8yhnZSdC+rud+/WdoK5VQtCSgzdPCYH DcJJZy5htovHFIO1SSNzQmeG2SlvDkRj09c2xebdErQkBzOl9nFIozDo+PwhfTCR7+Lp3AgDATp VKjzkzw/fw08+YaENA3wgPpvsH1ruhUSh+sEMVNPz8ceUam8X+XONbSQvFZkbVeUVtlUhknOYoE Cpy0ziYnxXFuAqyG4j9s/5UnfxpQEg/M4a0SuZ8GQF/oN/Uz+eIUnyoPQ9ol1EqY6BxcyxMShQ= = X-Received: by 2002:a05:6000:178c:b0:391:3207:2e75 with SMTP id ffacd0b85a97d-3997f8fc3cemr13654817f8f.18.1742918828337; Tue, 25 Mar 2025 09:07:08 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGCkrD/wzEorkAVHvh1K8UNAFCtoVb4CUf6LTpZKu2/s/1cTGrAe7sXbe3mn+oCr0e5ot2hJQ== X-Received: by 2002:a05:6000:178c:b0:391:3207:2e75 with SMTP id ffacd0b85a97d-3997f8fc3cemr13654785f8f.18.1742918827936; Tue, 25 Mar 2025 09:07:07 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 05/15] fuse: Change setup_... to mount_fuse_export() Date: Tue, 25 Mar 2025 17:06:45 +0100 Message-ID: <20250325160655.119407-4-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-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.129.124; envelope-from=hreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742919228913019100 Content-Type: text/plain; charset="utf-8" There is no clear separation between what should go into setup_fuse_export() and what should stay in fuse_export_create(). Make it clear that setup_fuse_export() is for mounting only. Rename it, and move everything that has nothing to do with mounting up into fuse_export_create(). Signed-off-by: Hanna Czenczek Reviewed-by: Stefan Hajnoczi --- block/export/fuse.c | 49 ++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 10606454c3..7bdec43b5c 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -72,8 +72,7 @@ static void fuse_export_delete(BlockExport *exp); =20 static void init_exports_table(void); =20 -static int setup_fuse_export(FuseExport *exp, const char *mountpoint, - bool allow_other, Error **errp); +static int mount_fuse_export(FuseExport *exp, Error **errp); static void read_from_fuse_export(void *opaque); =20 static bool is_regular_file(const char *path, Error **errp); @@ -193,23 +192,32 @@ static int fuse_export_create(BlockExport *blk_exp, exp->st_gid =3D getgid(); =20 if (args->allow_other =3D=3D FUSE_EXPORT_ALLOW_OTHER_AUTO) { - /* Ignore errors on our first attempt */ - ret =3D setup_fuse_export(exp, args->mountpoint, true, NULL); - exp->allow_other =3D ret =3D=3D 0; + /* Try allow_other =3D=3D true first, ignore errors */ + exp->allow_other =3D true; + ret =3D mount_fuse_export(exp, NULL); if (ret < 0) { - ret =3D setup_fuse_export(exp, args->mountpoint, false, errp); + exp->allow_other =3D false; + ret =3D mount_fuse_export(exp, errp); } } else { exp->allow_other =3D args->allow_other =3D=3D FUSE_EXPORT_ALLOW_OT= HER_ON; - ret =3D setup_fuse_export(exp, args->mountpoint, exp->allow_other,= errp); + ret =3D mount_fuse_export(exp, errp); } if (ret < 0) { goto fail; } =20 + g_hash_table_insert(exports, g_strdup(exp->mountpoint), NULL); + + aio_set_fd_handler(exp->common.ctx, + fuse_session_fd(exp->fuse_session), + read_from_fuse_export, NULL, NULL, NULL, exp); + exp->fd_handler_set_up =3D true; + return 0; =20 fail: + fuse_export_shutdown(blk_exp); fuse_export_delete(blk_exp); return ret; } @@ -227,10 +235,10 @@ static void init_exports_table(void) } =20 /** - * Create exp->fuse_session and mount it. + * Create exp->fuse_session and mount it. Expects exp->mountpoint, + * exp->writable, and exp->allow_other to be set as intended for the mount. */ -static int setup_fuse_export(FuseExport *exp, const char *mountpoint, - bool allow_other, Error **errp) +static int mount_fuse_export(FuseExport *exp, Error **errp) { const char *fuse_argv[4]; char *mount_opts; @@ -243,7 +251,7 @@ static int setup_fuse_export(FuseExport *exp, const cha= r *mountpoint, */ mount_opts =3D g_strdup_printf("max_read=3D%zu,default_permissions%s", FUSE_MAX_BOUNCE_BYTES, - allow_other ? ",allow_other" : ""); + exp->allow_other ? ",allow_other" : ""); =20 fuse_argv[0] =3D ""; /* Dummy program name */ fuse_argv[1] =3D "-o"; @@ -256,30 +264,17 @@ static int setup_fuse_export(FuseExport *exp, const c= har *mountpoint, g_free(mount_opts); if (!exp->fuse_session) { error_setg(errp, "Failed to set up FUSE session"); - ret =3D -EIO; - goto fail; + return -EIO; } =20 - ret =3D fuse_session_mount(exp->fuse_session, mountpoint); + ret =3D fuse_session_mount(exp->fuse_session, exp->mountpoint); if (ret < 0) { error_setg(errp, "Failed to mount FUSE session to export"); - ret =3D -EIO; - goto fail; + return -EIO; } exp->mounted =3D true; =20 - g_hash_table_insert(exports, g_strdup(mountpoint), NULL); - - aio_set_fd_handler(exp->common.ctx, - fuse_session_fd(exp->fuse_session), - read_from_fuse_export, NULL, NULL, NULL, exp); - exp->fd_handler_set_up =3D true; - return 0; - -fail: - fuse_export_shutdown(&exp->common); - return ret; } =20 /** --=20 2.48.1 From nobody Wed Apr 2 13:15:35 2025 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=1742918911; cv=none; d=zohomail.com; s=zohoarc; b=bHKXUP34g4yyoMLbxnngDG5/Uj0inAXCLqOkRk2jSClbsEAWXbIRnuqVtqYNP+UUUmWwkp/GWiRNsQnbSJ4JoYPZXf2AoKgVEvalFqtxL0KDZXiMLP/uEg+35rlXGGTW7diMQW9En5xGX7da4EVc404Fu4T3o9xbJs+6jqofJmE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742918911; 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=rjFF7/NAnTPz1YSqozhAn7Ks81w0e1zU5LPdNmpLML8=; b=Hws9+aJU84j97PPrBFR4KwaXjYX9dijmKmabNjbDc7RsU4n7a5NDhsXFCO1I1XgOs00BNH3rnCUvisY9OkLKwqQ8E1la8XcZkDVlJPzj7bSuyjdMXJTEJ6092QSJJltoXyMXAGMC6h3A13r056vY6aFQh7aIMAjYdkG2ajNgccQ= 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 1742918911648823.4921460511191; Tue, 25 Mar 2025 09:08:31 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6oe-0004jZ-Pk; Tue, 25 Mar 2025 12:07:49 -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 1tx6oC-0004VL-Ez for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:21 -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 1tx6oA-0007PJ-Hx for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:20 -0400 Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-682-VsC58CdeM1WAo8h1dX5nwg-1; Tue, 25 Mar 2025 12:07:13 -0400 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-43cf172ffe1so49082065e9.3 for ; Tue, 25 Mar 2025 09:07:13 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-43d6eab2466sm14707875e9.1.2025.03.25.09.07.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:07:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918835; 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=rjFF7/NAnTPz1YSqozhAn7Ks81w0e1zU5LPdNmpLML8=; b=ei8t3ds+Ds0v4EHFovElFwxLYYbotIg6mbcaJ0OnTKriGr7cuk4H6UK3FC7KCIWaibC7xF A3lTUje+4N0VRNyEfBf5E9dPOU5fVvzLTvYORnykJyAYMEo+xV8oOe5/U1HTyxwM809qMb OZrdNZymHjoRjZeN3UTstRiLnKBzDD4= X-MC-Unique: VsC58CdeM1WAo8h1dX5nwg-1 X-Mimecast-MFC-AGG-ID: VsC58CdeM1WAo8h1dX5nwg_1742918832 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918832; x=1743523632; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=rjFF7/NAnTPz1YSqozhAn7Ks81w0e1zU5LPdNmpLML8=; b=gyAugOK7y8qdgbeHdc/iCSqZ+D2oHu8Y8Au0v+Ef3Jm/IDkMIrInSGItxagBW7lAKf ZFNZA7VTQIun4Px+ZBd1DqOOwob+WONRhXlh6QCf6aMADtSux7Oh4gZXB51EW5NSrwUi UvPoGEKNwFkSYCBaFfYPCSwSIJ/J9gJynzxwQw+9hiYQjsy38RDgxgtjv+1UnW4Rqn49 py1i0ArUKgvd21KOkfnqBZBT5JvcrW/12O6yH/hA2xdFPq/1NdJaQDDS7fZCNCW+UiPW fjvdcbjiPvYnP6scsiUU0KcDftq5eutUUIlMgTOSCDtttSFDMLWhjqRg9ipsC9f2Byyo 9Y+w== X-Gm-Message-State: AOJu0YxEt0U2xVN98JxiWS8NE+kSivCOY6Lssw3IO1g2AaSvpc1Jjucl UGdmfi/tyAT/wgFSlaqM3o/hRP5W5+TO+l/QGENCF8TK8GNgwymRdlDbZtyw/b3MX+xDlTsW5rq vN+F7PfwCpPH5pGopcLdEpIdoQdlTyHa34y5QFpz7xmRCga+9wfXM X-Gm-Gg: ASbGnctW/1TYrQaLPo3jCNfKPY4WLNQEveLMrBN6ACfFuCbO8f/vVhVsoQ9F9ixyaIU Tj/kfrrAx/EDGYrIFYlKt2Sp3/JY6FdkZfuUsswHmjxZxHW/dykKMWrMPVeIjasGGYVfBiqSauG 3qX4VONtzChhnyHqp9kbo30UJr2x8XZMNoEdyZoRIjR5C1cDYSTdvpOfV+irknj+Br9LQtbziyP Pb9ahrjXWA5CLkavqGr5P1kc3bHnYQPoajRZ/6NB70RSf5EV+uVk1hqzl48XiSv79o25AtzjDGF a45fHbrQ8ZfvTXa/0GfEikGTpUQ5BX5ck8vkolIpPlVheLdmJFL/BXuCrwKxoDVGr65W+h1vrQ= = X-Received: by 2002:a05:600c:4512:b0:43c:f87c:24ce with SMTP id 5b1f17b1804b1-43d50a3781amr120915875e9.21.1742918832346; Tue, 25 Mar 2025 09:07:12 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEUBgrGpYPXbqZB6tLBOLQtQlBqo13vqTWJnk1A1xcnG1uyuXkYtseU9zsy2hosH8lYgud0OQ== X-Received: by 2002:a05:600c:4512:b0:43c:f87c:24ce with SMTP id 5b1f17b1804b1-43d50a3781amr120915145e9.21.1742918831558; Tue, 25 Mar 2025 09:07:11 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 06/15] fuse: Fix mount options Date: Tue, 25 Mar 2025 17:06:46 +0100 Message-ID: <20250325160655.119407-5-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-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: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742918913202019000 Content-Type: text/plain; charset="utf-8" Since I actually took a look into how mounting with libfuse works[1], I now know that the FUSE mount options are not exactly standard mount system call options. Specifically: - We should add "nosuid,nodev,noatime" because that is going to be translated into the respective MS_ mount flags; and those flags make sense for us. - We can set rw/ro to make the mount writable or not. It makes sense to set this flag to produce a better error message for read-only exports (EROFS instead of EACCES). This changes behavior as can be seen in iotest 308: It is no longer possible to modify metadata of read-only exports. In addition, in the comment, we can note that the FUSE mount() system call actually expects some more parameters that we can omit because fusermount3 (i.e. libfuse) will figure them out by itself: - fd: /dev/fuse fd - rootmode: Inode mode of the root node - user_id/group_id: Mounter's UID/GID [1] It invokes fusermount3, an SUID libfuse helper program, which parses and processes some mount options before actually invoking the mount() system call. Signed-off-by: Hanna Czenczek Reviewed-by: Stefan Hajnoczi --- block/export/fuse.c | 14 +++++++++++--- tests/qemu-iotests/308 | 4 ++-- tests/qemu-iotests/308.out | 3 ++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 7bdec43b5c..0d20995a0e 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -246,10 +246,18 @@ static int mount_fuse_export(FuseExport *exp, Error *= *errp) int ret; =20 /* - * max_read needs to match what fuse_init() sets. - * max_write need not be supplied. + * Note that these mount options differ from what we would pass to a d= irect + * mount() call: + * - nosuid, nodev, and noatime are not understood by the kernel; libf= use + * uses those options to construct the mount flags (MS_*) + * - The FUSE kernel driver requires additional options (fd, rootmode, + * user_id, group_id); these will be set by libfuse. + * Note that max_read is set here, while max_write is set via the FUSE= INIT + * operation. */ - mount_opts =3D g_strdup_printf("max_read=3D%zu,default_permissions%s", + mount_opts =3D g_strdup_printf("%s,nosuid,nodev,noatime,max_read=3D%zu= ," + "default_permissions%s", + exp->writable ? "rw" : "ro", FUSE_MAX_BOUNCE_BYTES, exp->allow_other ? ",allow_other" : ""); =20 diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308 index ea81dc496a..266b109ff3 100755 --- a/tests/qemu-iotests/308 +++ b/tests/qemu-iotests/308 @@ -177,7 +177,7 @@ stat -c 'Permissions pre-chmod: %a' "$EXT_MP" chmod u+w "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt stat -c 'Permissions post-+w: %a' "$EXT_MP" =20 -# But that we can set, say, +x (if we are so inclined) +# Same for other flags, like, say +x chmod u+x "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt stat -c 'Permissions post-+x: %a' "$EXT_MP" =20 @@ -235,7 +235,7 @@ output=3D$($QEMU_IO -f raw -c 'write -P 42 1M 64k' "$TE= ST_IMG" 2>&1 \ =20 # Expected reference output: Opening the file fails because it has no # write permission -reference=3D"Could not open 'TEST_DIR/t.IMGFMT': Permission denied" +reference=3D"Could not open 'TEST_DIR/t.IMGFMT': Read-only file system" =20 if echo "$output" | grep -q "$reference"; then echo "Writing to read-only export failed: OK" diff --git a/tests/qemu-iotests/308.out b/tests/qemu-iotests/308.out index e5e233691d..aa96faab6d 100644 --- a/tests/qemu-iotests/308.out +++ b/tests/qemu-iotests/308.out @@ -53,7 +53,8 @@ Images are identical. Permissions pre-chmod: 400 chmod: changing permissions of 'TEST_DIR/t.IMGFMT.fuse': Read-only file sy= stem Permissions post-+w: 400 -Permissions post-+x: 500 +chmod: changing permissions of 'TEST_DIR/t.IMGFMT.fuse': Read-only file sy= stem +Permissions post-+x: 400 =20 =3D=3D=3D Mount over existing file =3D=3D=3D {'execute': 'block-export-add', --=20 2.48.1 From nobody Wed Apr 2 13:15:35 2025 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=1742918888; cv=none; d=zohomail.com; s=zohoarc; b=muT3TwPfZvyqTKqsCwgCgqYDevOE5eAwmPfRd2baTdPFKXVuIUBBCkgh5cNUh146OsmMUvtCTFT78ZoLStbAuGZOc8fk/xDfe2fQFetud4svIMuAtl2kf4vtf+Sdqr8YL4DR20yLdMPsaMMGRH5cBaaARVVXAEdRTt3ylOQdoI4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742918888; 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=7d4MlmImkWG2UAQtaVplRdJ/rZ7XuvAmCbc1IVeJbTM=; b=HyLxOwxd6jTYAHkCcED7wfA7T+m5vv+ZAh7fe98ECy5y7CsQXnZSmP54sU84gGN7dzQlNyG22tzitX3qJWJesXOr62sw354QnO0e5kviCQfJGfitHnLSU2NlNuCaIYStReDaBxbumSKZoJja+8LWVic6R4AbxqVhL6cuuL9JnF0= 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 1742918888844948.6241002128035; Tue, 25 Mar 2025 09:08:08 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6of-0004nt-UA; Tue, 25 Mar 2025 12:07:49 -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 1tx6oG-0004Vr-2A for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:27 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tx6oE-0007QP-Cf for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:23 -0400 Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-575-te1NtLWhPkGxtHAOPVnZUA-1; Tue, 25 Mar 2025 12:07:18 -0400 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-43d51bd9b41so38335635e9.3 for ; Tue, 25 Mar 2025 09:07:18 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-43d43f55c99sm205914325e9.24.2025.03.25.09.07.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:07:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918840; 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=7d4MlmImkWG2UAQtaVplRdJ/rZ7XuvAmCbc1IVeJbTM=; b=cOujmWATrI/Y5YYdLo/yf8W80fW6L7OmaUB8BVrN8c9F27tKLRxEqEIrqcKdw1G3rNJ4C1 IZOSeRtSHWX+I3EHRIzz5jfHR10WMVoSBsdw+fonmu6vjqu51zBYdJlSz6Ov7kvUWn6JYL IXc2xl0slDdhHW2sVvl2VQSfSfZCetk= X-MC-Unique: te1NtLWhPkGxtHAOPVnZUA-1 X-Mimecast-MFC-AGG-ID: te1NtLWhPkGxtHAOPVnZUA_1742918837 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918837; x=1743523637; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=7d4MlmImkWG2UAQtaVplRdJ/rZ7XuvAmCbc1IVeJbTM=; b=E97duDxAzmi70Cju0Atq/mexwwWk5qCrju5UB0fTd0+7pJq7+p934ik3GydN0E+RpY w4jWa9tKkmhLMHml0G9giKjVo1jUSR7/MMhdVN3aZhVBxHRR+qEBUSSDKnOlI9TPbJbp YWP9pb2mP87SaIEfUevPleaDC+6UpPuezfASk9KlnueKgAShtaGmVUaOthAZOlcxPoSE O/O4u6lv5a6GuelnzvPdbLAaQRZlqTSN9bGzGQNrnkemdS2X2fpbzfTMp3K/JP/pdDrC HxB9CqCbPxGeiwbU83O3aGyZY5xFbbJE0bt6DeTZ7khyEG65CLAUUrcaAKs9f+mRxD1t RS/A== X-Gm-Message-State: AOJu0YxD37Bun0g4azVwOYYdGeIe5um2UNSMxHA9IoJP3/slwWsDQAYz HS3vIPkTHnT5EclH5AjIjcrCoHND0IA8+LVPwx7Cy7V7f+ongYnYNO9uTFy0YTyM1J6FJtFWqq1 JkLt3iDjCD2I2WxI3dbFj/QnLFQrih46WVgHgyDjYA2dgv4HeHd74 X-Gm-Gg: ASbGnctPrncQ5IqXvMME74Wp/oaKjvx8sFwh14XNtNxErV2TzcnckkW3qqONT+q/xJb 0WCk/FjPt7TcX8unHH4GuVabmrtKbkz0M26TNpEXIKS6fV2oilePPcjmlSa3VbhTfg2FutkzozT EYPrR9Q+hJuwRnMLYAPhG2ZJpoqCoX+5UsBC9XWiopKbTn1CAMsauuX4BKG+7qQGY1Yntr74rcm e+ROaoV5JCEnR5uotmD0JXMjt26nTkydwiqMTpbUfWD9+VGnlJNDLX93fiBvYhMBeTZ95PUFyU3 llwq5sdi6yP6pYCCXwif4atoFPjoE4OhvUZQ4s+RFlyz16DMkIP0K29MAd/ConYXLMDEtR3hog= = X-Received: by 2002:a05:600c:1e07:b0:43c:fdbe:439b with SMTP id 5b1f17b1804b1-43d509e374bmr176932375e9.4.1742918837108; Tue, 25 Mar 2025 09:07:17 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEvSJ3v6Q6u8oyl9O5UShLbPhsOhO1UOwaMBIE+BCxpck3GSZiLxNRn79X9aARqY4HhH9e6IA== X-Received: by 2002:a05:600c:1e07:b0:43c:fdbe:439b with SMTP id 5b1f17b1804b1-43d509e374bmr176931355e9.4.1742918836299; Tue, 25 Mar 2025 09:07:16 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 07/15] fuse: Set direct_io and parallel_direct_writes Date: Tue, 25 Mar 2025 17:06:47 +0100 Message-ID: <20250325160655.119407-6-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-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.129.124; envelope-from=hreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742918890659019000 Content-Type: text/plain; charset="utf-8" In fuse_open(), set these flags: - direct_io: We probably actually don't want to have the host page cache be used for our exports. QEMU block exports are supposed to represent the image as-is (and thus potentially changing). This causes a change in iotest 308's reference output. - parallel_direct_writes: We can (now) cope with parallel writes, so we should set this flag. For some reason, it doesn't seem to make an actual performance difference with libfuse, but it does make a difference without it, so let's set it. (See "fuse: Copy write buffer content before polling" for further discussion.) Signed-off-by: Hanna Czenczek Reviewed-by: Stefan Hajnoczi --- block/export/fuse.c | 2 ++ tests/qemu-iotests/308.out | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 0d20995a0e..2df6297d61 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -576,6 +576,8 @@ static void fuse_setattr(fuse_req_t req, fuse_ino_t ino= de, struct stat *statbuf, static void fuse_open(fuse_req_t req, fuse_ino_t inode, struct fuse_file_info *fi) { + fi->direct_io =3D true; + fi->parallel_direct_writes =3D true; fuse_reply_open(req, fi); } =20 diff --git a/tests/qemu-iotests/308.out b/tests/qemu-iotests/308.out index aa96faab6d..2d7a38d63d 100644 --- a/tests/qemu-iotests/308.out +++ b/tests/qemu-iotests/308.out @@ -131,7 +131,7 @@ wrote 65536/65536 bytes at offset 1048576 =20 --- Try growing non-growable export --- (OK: Lengths of export and original are the same) -dd: error writing 'TEST_DIR/t.IMGFMT.fuse': Input/output error +dd: error writing 'TEST_DIR/t.IMGFMT.fuse': No space left on device 1+0 records in 0+0 records out =20 --=20 2.48.1 From nobody Wed Apr 2 13:15:35 2025 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=1742919133; cv=none; d=zohomail.com; s=zohoarc; b=cmqXm8yVqWMY0UsWAy6kV1KrQpMDqts7nUtW57oAeU7X1YOWWYJ5G+In0cQWWfn5leAoxbCd/FnDjybrXjgrOhvK8Krij43nwNj5jrqae24beHuSE/TjF96dFhWi0Z6vFMlDNX+x4o6JZVeOgjoKYYYFENQQzqFeJrRLPtDGTCk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742919133; 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=eTb0IClszg1ZXtQsdOfv/iJZx5LC/obmIaW+5tk5J0E=; b=kMdX6cI2hjMyc9zsawpLZz1NID5clMxFjZfVDJX83G5p0tYnYH2H0Mj21iczC9HTQZ+/nrgiY5YWGBY+ywb2gt/8xM6jIVLQnckqQznjjrrzsu8EtU175msfqp9bnugVusgDrO4hOzstsx8SKu9An85JYjAECk8/4PUb/cYNaXA= 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 1742919133094292.1172104341615; Tue, 25 Mar 2025 09:12:13 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6pV-0005no-K4; Tue, 25 Mar 2025 12:08:43 -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 1tx6oN-0004X2-C5 for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:38 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tx6oH-0007RS-Kb for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:28 -0400 Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-41-eTdPcjjjM0WJxc5I1-NRCg-1; Tue, 25 Mar 2025 12:07:21 -0400 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-43cf44b66f7so41134895e9.1 for ; Tue, 25 Mar 2025 09:07:20 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3997f9a6326sm13775029f8f.29.2025.03.25.09.07.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:07:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918844; 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=eTb0IClszg1ZXtQsdOfv/iJZx5LC/obmIaW+5tk5J0E=; b=R6Ui93I0ztI/6iXuM6lucs0A02ZwZN0iq70NSm2cZty6a6+qEpqcfjQMp0+O4gkkGw3lvJ JfDO9GFJndV4cJXqjp2xuKfMEL/2whu7mFywBUWm4asjPX+Bwg7FrG95V9etPigknRsxwI OIL2B6HtoidyygLL45lU8hKv+GSYzu4= X-MC-Unique: eTdPcjjjM0WJxc5I1-NRCg-1 X-Mimecast-MFC-AGG-ID: eTdPcjjjM0WJxc5I1-NRCg_1742918840 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918840; x=1743523640; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=eTb0IClszg1ZXtQsdOfv/iJZx5LC/obmIaW+5tk5J0E=; b=byiqWSnZ31Esjy6xDN5VDvKnNvFBIVYEr/jZDkY5VTD6ATwhBkQtp/rCLeTiVPaU2w mR80WgN+ReIjfF06kUU15wo1VLAl5+xfmDb/uJ9W4iOdC23oON/jeQO2GqHyMcBkZ3Y3 xRHTh/ZATqgjzzm4DjUJsolLdMDCC1rqx/y78ve0gF9VwT3V/K9InXiY+cNHHkmI3Cbv GiGIrcsr0SYX0t1xRt1LXpNogL0B6rJ6NGQ7oaORabZCRjJKVlgzQd8FhYOO41u09wCb UxwSvz+5wIlcr0jUXc6JiZnBFKfhqZ4uZ0oCyXk6HqMCrJZeuZKb+Sod9HKn/AESIpAy zzbg== X-Gm-Message-State: AOJu0YyyGmefokxEIwoaNau/m0kMo9/cefjpZSe9OO30tht716h/Iu0a kni4aJv99hAAc01jzMR2e0BK9aMu3OAi754IWs48eIIib2FmWZgWcf88yhTp05UAVhdxAFDs4xu op0f6doV6r/mAMNXjjJ/JbXMxbcOXxFxwchx2qQMjqdW0Ao3C86hC X-Gm-Gg: ASbGncteL6D9r+YcljNSiLGN+MWTcKldcIErdG7WPW3beUYAfY1BZMeuvk1TlyPQEY4 SbRc//K6nnWWkgORbm+7GoLUhO2hV3vou3mJcIfzWVHlrZiykleeSwt5/Hr33NTkSL5Em9GqIrl nCy/C7qKYBd+PEBYfjBfOuksAFXGwfhDZJfSTO02kHwYRXs97JTCgUOVBJGQtNmADirk2f3CNmS tyA6CVDa+sxkHjHi/lUS7JSdquJCjeudpz6B0ie1WpmjdZ5SZMh4JDeFplsPYLu3ZstsDRqQej6 t1CBkWiVJoTncaOtctzobP3AM4sqF6W6nZv77OMre3/EDrvaa0OVwpdQGcfO7UsLdy0ghfrnTQ= = X-Received: by 2002:a5d:64af:0:b0:38f:3e39:20ae with SMTP id ffacd0b85a97d-3997f92dbd3mr17016508f8f.43.1742918839938; Tue, 25 Mar 2025 09:07:19 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHANclsPL2CceE+DE+AM3Qu+t4mRm34pTVahJ91iUH7g4cB8v3lzoZWphWlfzFLkzgX5jlICg== X-Received: by 2002:a5d:64af:0:b0:38f:3e39:20ae with SMTP id ffacd0b85a97d-3997f92dbd3mr17016462f8f.43.1742918839477; Tue, 25 Mar 2025 09:07:19 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 08/15] fuse: Introduce fuse_{at,de}tach_handlers() Date: Tue, 25 Mar 2025 17:06:48 +0100 Message-ID: <20250325160655.119407-7-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-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.129.124; envelope-from=hreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742919133712019000 Content-Type: text/plain; charset="utf-8" Pull setting up and tearing down the AIO context handlers into two dedicated functions. Signed-off-by: Hanna Czenczek Reviewed-by: Stefan Hajnoczi --- block/export/fuse.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 2df6297d61..bd98809d71 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -78,27 +78,34 @@ static void read_from_fuse_export(void *opaque); static bool is_regular_file(const char *path, Error **errp); =20 =20 -static void fuse_export_drained_begin(void *opaque) +static void fuse_attach_handlers(FuseExport *exp) { - FuseExport *exp =3D opaque; + aio_set_fd_handler(exp->common.ctx, + fuse_session_fd(exp->fuse_session), + read_from_fuse_export, NULL, NULL, NULL, exp); + exp->fd_handler_set_up =3D true; +} =20 +static void fuse_detach_handlers(FuseExport *exp) +{ aio_set_fd_handler(exp->common.ctx, fuse_session_fd(exp->fuse_session), NULL, NULL, NULL, NULL, NULL); exp->fd_handler_set_up =3D false; } =20 +static void fuse_export_drained_begin(void *opaque) +{ + fuse_detach_handlers(opaque); +} + static void fuse_export_drained_end(void *opaque) { FuseExport *exp =3D opaque; =20 /* Refresh AioContext in case it changed */ exp->common.ctx =3D blk_get_aio_context(exp->common.blk); - - aio_set_fd_handler(exp->common.ctx, - fuse_session_fd(exp->fuse_session), - read_from_fuse_export, NULL, NULL, NULL, exp); - exp->fd_handler_set_up =3D true; + fuse_attach_handlers(exp); } =20 static bool fuse_export_drained_poll(void *opaque) @@ -209,11 +216,7 @@ static int fuse_export_create(BlockExport *blk_exp, =20 g_hash_table_insert(exports, g_strdup(exp->mountpoint), NULL); =20 - aio_set_fd_handler(exp->common.ctx, - fuse_session_fd(exp->fuse_session), - read_from_fuse_export, NULL, NULL, NULL, exp); - exp->fd_handler_set_up =3D true; - + fuse_attach_handlers(exp); return 0; =20 fail: @@ -329,10 +332,7 @@ static void fuse_export_shutdown(BlockExport *blk_exp) fuse_session_exit(exp->fuse_session); =20 if (exp->fd_handler_set_up) { - aio_set_fd_handler(exp->common.ctx, - fuse_session_fd(exp->fuse_session), - NULL, NULL, NULL, NULL, NULL); - exp->fd_handler_set_up =3D false; + fuse_detach_handlers(exp); } } =20 --=20 2.48.1 From nobody Wed Apr 2 13:15:36 2025 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=1742919057; cv=none; d=zohomail.com; s=zohoarc; b=XmV6tp7JRxH6cVRJ0Fy3h8BMJ1+R5Cqaoy4uCfVNkmnjTSD84IrxmKv0h9SCo6ame2tZvZ/CoQXPpiqSijD6K0G4TG915CjW7OkYCDMLnKsUTNa2GRF8/K+WEWjzJ9vB9oEnwNxkoLAyMCbanp4ag7D7Yad2mU6v85OeCJCvXjU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742919057; 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=7g6V5yw9DWfXsXW3/hYJlzhy4WFzBO20U7FvoBzK+Rc=; b=XX1yfUT7BkRKS2q9XPNbCt3gce/9F6BDEFeQeZ72/oqrmwLMrgSHqNWsag9S8ubYIoURKo4QIyi1zWWtsWhS6dFSD0V61DOmON1wt+J/RXbEZGzB6AsrtdT0xfT0GW5dIRVhL+T5/CpfssIXr9XjgRfKJ3zvUxzcI4JRBIP+EAQ= 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 1742919057674447.5640930052606; Tue, 25 Mar 2025 09:10:57 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6qW-0006qt-VT; Tue, 25 Mar 2025 12:09:45 -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 1tx6oN-0004X1-Bg for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:38 -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 1tx6oJ-0007Rb-5a for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:28 -0400 Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-636-3SfynMNKN3mGWBdBDP1JTw-1; Tue, 25 Mar 2025 12:07:23 -0400 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-39abdadb0f0so1325316f8f.0 for ; Tue, 25 Mar 2025 09:07:23 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3997f9b26a6sm13908244f8f.44.2025.03.25.09.07.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:07:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918845; 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=7g6V5yw9DWfXsXW3/hYJlzhy4WFzBO20U7FvoBzK+Rc=; b=BkWDj2i5kv7ZiWHo7dOoyupYnaMw6Tc3n4vuPMPD5Nd1Zj4SAQrscmB9QfZPRAUMOJdkI1 zyhBFGvyq+ZjcJWVVt9lFvdJlT27TruZzFQa5JpMn2ta9lSRQIsSwHfciSZcyqray8gB2C XQVpTda3WmezzLXygcQ5sd7XLnkrKRw= X-MC-Unique: 3SfynMNKN3mGWBdBDP1JTw-1 X-Mimecast-MFC-AGG-ID: 3SfynMNKN3mGWBdBDP1JTw_1742918842 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918842; x=1743523642; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=7g6V5yw9DWfXsXW3/hYJlzhy4WFzBO20U7FvoBzK+Rc=; b=utVUIvztj19zI/OI3XHmq+bzmE5j6+4pnfdrXtDxiW9wpVru49aLqbhujRQxvk5CWY O/4Ng/hPTtqOSW7WKP2iWjPfxASH0SNG9K7sRqoOG1SOzSvcHYBaY8U23OXNhRW+ubuG c5ky8l+/8v0pcDwcjT9rQFFRGZqUMk9/7yY5246dhTFkkPVn9xGcAqGBxcWFBlWAthq3 trB4XuD4qaHSBBW5xFm68Q6xUUYOPzK5LY/Yiue7lFgHWv0UnmX69jMCDXhXM4NunIed ddMKvINY/IAxxlyEU9UarCiG/NfIb10U82ASMqkasEwyhmmvOGNESTDe39cbFo7I0JLC cmMg== X-Gm-Message-State: AOJu0YzJrMm1SCzIwB8isVAg+5wGnNNPnLPzG78OOVTeF+iWcPGbuHoM jqmfmMLHpVHKKzT1Z7CVRwJ47EGmkpVWEe6F+p4BFvGGBnFyqtO4dUtYbkVvWfLBQAF5+gRCuAD km7FR18AT9JTC8HysWkFHKnz+GkSem3MqGIp62fKSsNcLQAH4DFsJ X-Gm-Gg: ASbGncva2ZjZjGSdr84LFxxzCBtDphpEOgbccTthDmK401NvIRcigf5zHwhGtR1kT9r GxXFIlTeMt1UkHUUwkQsd+e2iH4WX21SEIfnJmg8AqlxlJzpOKg+4yrw0Fhz+XnxFxry622dgeJ EDcd2AB6S8PT43SH9F2As5g5NGktjwpGUROgUuJ2sdVJnpUdOPRqKktLaFZ5Sf1olnkIevFEPd5 mwoZL/LyeUB361XuZGGT1+fyDcTL0/tb/utcVd0HSGbKrd0ZLpIAzc4x6zw21x192lLQwUsgK78 vbtD8x1lWGefQ4V0H5hwv+Ia5GBHfGhemx+c5i/rjmHSgOUck3CouP+ERylyCCCQ1banMb80Qw= = X-Received: by 2002:a05:6000:42c2:b0:39a:c9d9:877b with SMTP id ffacd0b85a97d-39ac9d98801mr1864169f8f.27.1742918842232; Tue, 25 Mar 2025 09:07:22 -0700 (PDT) X-Google-Smtp-Source: AGHT+IG9izasiYkaOt4rgszJi1eDiuvT5QFDDqoPJQ4t6Flwi/8c2lCe5/t07j/+AdM0gjEpwIXKEA== X-Received: by 2002:a05:6000:42c2:b0:39a:c9d9:877b with SMTP id ffacd0b85a97d-39ac9d98801mr1864122f8f.27.1742918841656; Tue, 25 Mar 2025 09:07:21 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 09/15] fuse: Introduce fuse_{inc,dec}_in_flight() Date: Tue, 25 Mar 2025 17:06:49 +0100 Message-ID: <20250325160655.119407-8-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-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: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742919058553019100 Content-Type: text/plain; charset="utf-8" This is how vduse-blk.c does it, and it does seem better to have dedicated functions for it. Signed-off-by: Hanna Czenczek Reviewed-by: Stefan Hajnoczi --- block/export/fuse.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index bd98809d71..e50dd91d3e 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -78,6 +78,25 @@ static void read_from_fuse_export(void *opaque); static bool is_regular_file(const char *path, Error **errp); =20 =20 +static void fuse_inc_in_flight(FuseExport *exp) +{ + if (qatomic_fetch_inc(&exp->in_flight) =3D=3D 0) { + /* Prevent export from being deleted */ + blk_exp_ref(&exp->common); + } +} + +static void fuse_dec_in_flight(FuseExport *exp) +{ + if (qatomic_fetch_dec(&exp->in_flight) =3D=3D 1) { + /* Wake AIO_WAIT_WHILE() */ + aio_wait_kick(); + + /* Now the export can be deleted */ + blk_exp_unref(&exp->common); + } +} + static void fuse_attach_handlers(FuseExport *exp) { aio_set_fd_handler(exp->common.ctx, @@ -297,9 +316,7 @@ static void read_from_fuse_export(void *opaque) FuseExport *exp =3D opaque; int ret; =20 - blk_exp_ref(&exp->common); - - qatomic_inc(&exp->in_flight); + fuse_inc_in_flight(exp); =20 do { ret =3D fuse_session_receive_buf(exp->fuse_session, &exp->fuse_buf= ); @@ -317,11 +334,7 @@ static void read_from_fuse_export(void *opaque) fuse_session_process_buf(exp->fuse_session, &exp->fuse_buf); =20 out: - if (qatomic_fetch_dec(&exp->in_flight) =3D=3D 1) { - aio_wait_kick(); /* wake AIO_WAIT_WHILE() */ - } - - blk_exp_unref(&exp->common); + fuse_dec_in_flight(exp); } =20 static void fuse_export_shutdown(BlockExport *blk_exp) --=20 2.48.1 From nobody Wed Apr 2 13:15:36 2025 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=1742918889; cv=none; d=zohomail.com; s=zohoarc; b=ZPnXpIAsbX/P/5Vi2avsFHKJzUkd6bj94yeRYSrEvUO2unzE83I/TAAwKp2VYbX8Oobby+G0wL+z5qmAVErXb7MNErTRM2XaSJCH3i0OsW99xNiRumolVwd4/53JgrJIGIxjqB/PTAuPfx+rWlw3bCF2j21K1G9khUBd+gYNc+g= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742918889; 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=/gh+riUJHAn43i3neBpAg2kBaqXyzek2lfyG6O1xMac=; b=kbWqluDHMbZm8aB6iio08GWXVRw7HCYgs89j7IurJyQLmwl8wDiYlgtFbE4AO9YwqWAcDbNzQB+vANkw6EYrt2fFcjv0+BQFMDezUeUabCa/kFOtS05uK2YvYp1ssuoP8N/oT6Fpyhx21bXFOJjD5TkbgQ9DnHSpuQDaWe4vufU= 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 1742918889037874.1940215645471; Tue, 25 Mar 2025 09:08:09 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6oi-0004vT-OY; Tue, 25 Mar 2025 12:07:53 -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 1tx6oP-0004Zm-5W for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:40 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tx6oN-0007SQ-47 for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:32 -0400 Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-663-I8NwrMEjMb2gAv-656oELw-1; Tue, 25 Mar 2025 12:07:26 -0400 Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-39131851046so2517744f8f.0 for ; Tue, 25 Mar 2025 09:07:26 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-43d440ed793sm209097485e9.39.2025.03.25.09.07.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:07:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918848; 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=/gh+riUJHAn43i3neBpAg2kBaqXyzek2lfyG6O1xMac=; b=EGVbQHfMX60THwjfqEH5cRQJs78GQ3QodrOyvSSSChSC4TLn+W02AAyaM1U5xaYucEzvv/ arilaS01RGjF6OCvwypPOsQSjMvpA6+5SzjQ4Vp52eCVkv7kkJra56fKcM8jOASnxs1qqD PWpP7dSM+CHyUXCzml75H+t0FoemveI= X-MC-Unique: I8NwrMEjMb2gAv-656oELw-1 X-Mimecast-MFC-AGG-ID: I8NwrMEjMb2gAv-656oELw_1742918845 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918845; x=1743523645; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/gh+riUJHAn43i3neBpAg2kBaqXyzek2lfyG6O1xMac=; b=l1vdMMF4LdzXLY9U6viGGEci1ZA52z9Nz6UVRr+Nip4UqYRNjHPtvfcuBAUZgyDyqm j7+AHgpX70PeqtxU4dKR4XTqnC/4oPPl0Z+hcHbg71TfKOAJIlKbf3XFme99YCFT2Uth 2Z9o0Ge/7Ovzpw5Hz5XpVS22SoLnDOq4fMnwbSe7pDubXU5VNoQZD0195WLue+IWw1kJ 8XJpm8pXZQv0nzTbNRpyOtrD4obON/3UtoD1WCMNvvReGnGqwJe6tBSfqF9fSA+7Ig9y G1IvR9eFI6RM8oK/pb9qeKV4dLGs3nSWpU3gxV3eo8ap3fKD1sQyDFxS/xkdS+EBumJh av/g== X-Gm-Message-State: AOJu0YyyF5ULO2WaPA/OmLHtk9vFkvTd8qKoFE6MKEyqmNEEIFQ5bPTj 9FAUeHrANokYj85fqX8nB2ODZ0DS3GujoZPvEyrO2/WI5fyftOTyBh8rHYApvqrsQ31j1CL5GI5 DGGABVH2UEUiEDcwUS66WATdIdQs8DFmIlLAPOWANvhF55C+bM2hv X-Gm-Gg: ASbGncunhfjF+32Rm4MXQSxLAuabOt+4GDPD2dTjpONbrsS2HdXwKxYtSKDyjOrQRsQ xfAa259Kw6SdEioVQtFOWM4CuzxjiqYIX/29gxgPkpUHl3MtiKPPy87vPbD3Xjbfs2isfDhNz7h oZeOFv2bu/zOiR/5YUeOrUq4E2KyNUcAfflxdKL5OlX5rCyXEGkZyn4XA8mWA1bY+8gsVhcqGQl cNXtab8XfgFGJNWpes/AwY4cMKw0uJyA1NV36ytKk3F/klXjPFT4Vxr2uQBXVxhaBr0J/+LLfs2 Cw/yf6jaSJYDNmH78WAKeEggV+hDle6wkRL6RIAeU1faeMgEcrmRRZL9fIcjNtLG2HdK0rjbOA= = X-Received: by 2002:a5d:5f8c:0:b0:391:275a:273f with SMTP id ffacd0b85a97d-3997f8f6089mr14869808f8f.4.1742918845110; Tue, 25 Mar 2025 09:07:25 -0700 (PDT) X-Google-Smtp-Source: AGHT+IF5D0xrWkxlEClrr2p2DL62m+X3C+u0kcvDOMwMgPl9A6x+og7fc3oMXy9l4SSs2p5R7lp33A== X-Received: by 2002:a5d:5f8c:0:b0:391:275a:273f with SMTP id ffacd0b85a97d-3997f8f6089mr14869757f8f.4.1742918844634; Tue, 25 Mar 2025 09:07:24 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 10/15] fuse: Add halted flag Date: Tue, 25 Mar 2025 17:06:50 +0100 Message-ID: <20250325160655.119407-9-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-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.129.124; envelope-from=hreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742918892031019100 Content-Type: text/plain; charset="utf-8" This is a flag that we will want when processing FUSE requests ourselves: When the kernel sends us e.g. a truncated request (i.e. we receive less data than the request's indicated length), we cannot rely on subsequent data to be valid. Then, we are going to set this flag, halting all FUSE request processing. We plan to only use this flag in cases that would effectively be kernel bugs. (Right now, the flag is unused because libfuse still does our request processing.) Signed-off-by: Hanna Czenczek Reviewed-by: Stefan Hajnoczi --- block/export/fuse.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/block/export/fuse.c b/block/export/fuse.c index e50dd91d3e..3dd50badb3 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -53,6 +53,13 @@ typedef struct FuseExport { unsigned int in_flight; /* atomic */ bool mounted, fd_handler_set_up; =20 + /* + * Set when there was an unrecoverable error and no requests should be= read + * from the device anymore (basically only in case of something we wou= ld + * consider a kernel bug) + */ + bool halted; + char *mountpoint; bool writable; bool growable; @@ -69,6 +76,7 @@ static const struct fuse_lowlevel_ops fuse_ops; =20 static void fuse_export_shutdown(BlockExport *exp); static void fuse_export_delete(BlockExport *exp); +static void fuse_export_halt(FuseExport *exp) G_GNUC_UNUSED; =20 static void init_exports_table(void); =20 @@ -99,6 +107,10 @@ static void fuse_dec_in_flight(FuseExport *exp) =20 static void fuse_attach_handlers(FuseExport *exp) { + if (exp->halted) { + return; + } + aio_set_fd_handler(exp->common.ctx, fuse_session_fd(exp->fuse_session), read_from_fuse_export, NULL, NULL, NULL, exp); @@ -316,6 +328,10 @@ static void read_from_fuse_export(void *opaque) FuseExport *exp =3D opaque; int ret; =20 + if (unlikely(exp->halted)) { + return; + } + fuse_inc_in_flight(exp); =20 do { @@ -374,6 +390,20 @@ static void fuse_export_delete(BlockExport *blk_exp) g_free(exp->mountpoint); } =20 +/** + * Halt the export: Detach FD handlers, and set exp->halted to true, preve= nting + * fuse_attach_handlers() from re-attaching them, therefore stopping all f= urther + * request processing. + * + * Call this function when an unrecoverable error happens that makes proce= ssing + * all future requests unreliable. + */ +static void fuse_export_halt(FuseExport *exp) +{ + exp->halted =3D true; + fuse_detach_handlers(exp); +} + /** * Check whether @path points to a regular file. If not, put an * appropriate message into *errp. --=20 2.48.1 From nobody Wed Apr 2 13:15:36 2025 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=1742919068; cv=none; d=zohomail.com; s=zohoarc; b=dOVYy1gSJavPlytfY+vzTo6VarGAx15jCJIy6P5Q02GeY7sZlfGmeTzlPmkaZ/sqsWAcfhe/rfeowkMsNZRSYEelr3i5eKDzgPi+xmyn50XbKfpty7wKpTE3CSook/aC7yFa4YHwhc7Z/WGdfXcJwJkh3fQzK2TpDONGr/ymQrg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742919068; 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=8YqxBFTLMD3kFmJ6w3lYR8PvdAHkFOJCazq0+SYILIA=; b=CQ1pc4FkzZtPLqKrBdrv1P/kBirJX9Y2zsxdYWokSgcsYqnHd8scPZMACZBhbrlbVnmmEELX3+7HhaO+PaPf86/9z8Nxr5FIaX7Ig2Y78CsAvvsX8hPWnvTveMHQ1bycc9p83l4bvpcO9WJ9/S44g6p6BfZZLE3u8f6X8Y8vlXY= 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 17429190682541007.7032572750754; Tue, 25 Mar 2025 09:11:08 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6qd-0007Ex-8u; Tue, 25 Mar 2025 12:09:51 -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 1tx6oX-0004bm-98 for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:44 -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 1tx6oO-0007TD-S0 for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:37 -0400 Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-44-Jp-QaPiTOV25q6NV0OVxEA-1; Tue, 25 Mar 2025 12:07:30 -0400 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-391425471d6so2523750f8f.3 for ; Tue, 25 Mar 2025 09:07:30 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3997f9a3372sm13955885f8f.21.2025.03.25.09.07.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:07:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918852; 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-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8YqxBFTLMD3kFmJ6w3lYR8PvdAHkFOJCazq0+SYILIA=; b=Nk5UNE2Sa8xHvNX2Uqg9Ij5CZ/agZXCH650+3DHRrWxW99H/26mp/2s95ORwurMczgjpyQ 4e5ej3G/Ey5j1eWiAb2j6YatX6MSrl93VgffmMMZGJAzb+PWeX1m91Q9XMHNwSFn9eesfp n5p+5U1uA5aFGPTxw20ihoqevdD01mo= X-MC-Unique: Jp-QaPiTOV25q6NV0OVxEA-1 X-Mimecast-MFC-AGG-ID: Jp-QaPiTOV25q6NV0OVxEA_1742918849 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918849; x=1743523649; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=8YqxBFTLMD3kFmJ6w3lYR8PvdAHkFOJCazq0+SYILIA=; b=ly8ljvIceY3V6dJwsPIICqQVnQ4uqetse75W7RFECmJKa6sCN3OXwP+jh0dX/91ojB ZiCDl0tJOZUddjsHH+lE0nU2ORzD4rMikeMtVxDR2pOGPKabT/+pO9WoKqh9UQ2Dckdg Wv713s3o5XdshzlhJ2RH/XtxMKK1VkOG7Hzh43hzXLka1wLcCA/nx02uujx+Y1oYIHCf 2iKzCzJ8rz7G0RuCZC73We9lnq1ec9KnJ3+rDr4jaEjO4bBDhFpTYpTBGTVDzoObkVNl xBoyLdZjkV3FmtSxjab3CoolqZvH+bH4bt4heBXwW10xxBFEbTbFtMFfmY9QzVcfX0rs encQ== X-Gm-Message-State: AOJu0Yx8SDsLrPlVVBFtn3K774Tn/2/wzlqSL5Cwbg7ScCT/U3TUTbco mdJBOTXgSlUOHJ57zDunlEwh9tm/JvV5RdeAKFva4jA054iK5IhBmL+jzmEBktmKXcP8g76uceo iqjPTIYoUsxVHAB23Sg9MSNGoq1T3zNbrr6S+hx39Uosxv10wGsDa X-Gm-Gg: ASbGnctkNYSxxdssLHL4QlC+LIW6j+Guu0JYakdzVuol0a8suR3WTs6Y5qmkuplEa82 kfnc78fT05vYtKgl5U7lRlxWda3hbSfazkLB4E5NhfqhMlDYt1HWxmoxvTND8XFKZE2dxUtrePk QbwD7nz2DQ3IUgAbHyYyoZvJ7kAk/lGFmbqbyETcudTjfQLljdjMxGY9O/G+4A5XjCTtja+z4Z7 8aI8roWthU6qSWGM4TzZlFuzis8+hTg0etFLdnMiasgUwXntiT2a8g+pFjvLSgBGW/5wVxS5uEP TIPpx4chrprArWh8reOTslJ1ACu/4xt/BqkGQ0NMIMaDALxbEUAvIwiiU33HCDAPKMBOuqyabg= = X-Received: by 2002:a5d:64a5:0:b0:391:31f2:b99e with SMTP id ffacd0b85a97d-3997f900bd7mr15875085f8f.2.1742918848106; Tue, 25 Mar 2025 09:07:28 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGRyjDPMP96UmXqVVm4yE3IqX2L4YH+t8UE4XwndyXOYPOSb0pMDq++HvvoTG0v1k4owCud3Q== X-Received: by 2002:a5d:64a5:0:b0:391:31f2:b99e with SMTP id ffacd0b85a97d-3997f900bd7mr15875027f8f.2.1742918847436; Tue, 25 Mar 2025 09:07:27 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 11/15] fuse: Manually process requests (without libfuse) Date: Tue, 25 Mar 2025 17:06:51 +0100 Message-ID: <20250325160655.119407-10-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-1-hreitz@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Type: text/plain; charset=UTF-8 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: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742919070584019100 Manually read requests from the /dev/fuse FD and process them, without using libfuse. This allows us to safely add parallel request processing in coroutines later, without having to worry about libfuse internals. (Technically, we already have exactly that problem with read_from_fuse_export()/read_from_fuse_fd() nesting.) We will continue to use libfuse for mounting the filesystem; fusermount3 is a effectively a helper program of libfuse, so it should know best how to interact with it. (Doing it manually without libfuse, while doable, is a bit of a pain, and it is not clear to me how stable the "protocol" actually is.) Take this opportunity of quite a major rewrite to update the Copyright line with corrected information that has surfaced in the meantime. Here are some benchmarks from before this patch (4k, iodepth=3D16, libaio; except 'sync', which are iodepth=3D1 and pvsync2): file: read: seq aio: 78.6k =C2=B11.3k IOPS rand aio: 39.3k =C2=B12.9k seq sync: 32.5k =C2=B10.7k rand sync: 9.9k =C2=B10.1k write: seq aio: 61.9k =C2=B10.5k rand aio: 61.2k =C2=B10.6k seq sync: 27.9k =C2=B10.2k rand sync: 27.6k =C2=B10.4k null: read: seq aio: 214.0k =C2=B15.9k rand aio: 212.7k =C2=B14.5k seq sync: 90.3k =C2=B16.5k rand sync: 89.7k =C2=B15.1k write: seq aio: 203.9k =C2=B11.5k rand aio: 201.4k =C2=B13.6k seq sync: 86.1k =C2=B16.2k rand sync: 84.9k =C2=B15.3k And with this patch applied: file: read: seq aio: 76.6k =C2=B11.8k (- 3 %) rand aio: 26.7k =C2=B10.4k (-32 %) seq sync: 47.7k =C2=B11.2k (+47 %) rand sync: 10.1k =C2=B10.2k (+ 2 %) write: seq aio: 58.1k =C2=B10.5k (- 6 %) rand aio: 58.1k =C2=B10.5k (- 5 %) seq sync: 36.3k =C2=B10.3k (+30 %) rand sync: 36.1k =C2=B10.4k (+31 %) null: read: seq aio: 268.4k =C2=B13.4k (+25 %) rand aio: 265.3k =C2=B12.1k (+25 %) seq sync: 134.3k =C2=B12.7k (+49 %) rand sync: 132.4k =C2=B11.4k (+48 %) write: seq aio: 275.3k =C2=B11.7k (+35 %) rand aio: 272.3k =C2=B11.9k (+35 %) seq sync: 130.7k =C2=B11.6k (+52 %) rand sync: 127.4k =C2=B12.4k (+50 %) So clearly the AIO file results are actually not good, and random reads are indeed quite terrible. On the other hand, we can see from the sync and null results that request handling should in theory be quicker. How does this fit together? I believe the bad AIO results are an artifact of the accidental parallel request processing we have due to nested polling: Depending on how the actual request processing is structured and how long request processing takes, more or less requests will be submitted in parallel. So because of the restructuring, I think this patch accidentally changes how many requests end up being submitted in parallel, which decreases performance. (I have seen something like this before: In RSD, without having implemented a polling mode, the debug build tended to have better performance than the more optimized release build, because the debug build, taking longer to submit requests, ended up processing more requests in parallel.) In any case, once we use coroutines throughout the code, performance will improve again across the board. Signed-off-by: Hanna Czenczek --- block/export/fuse.c | 793 +++++++++++++++++++++++++++++++------------- 1 file changed, 567 insertions(+), 226 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 3dd50badb3..407b101018 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -1,7 +1,7 @@ /* * Present a block device as a raw image through FUSE * - * Copyright (c) 2020 Max Reitz + * Copyright (c) 2020, 2025 Hanna Czenczek * * 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 @@ -27,12 +27,15 @@ #include "block/qapi.h" #include "qapi/error.h" #include "qapi/qapi-commands-block.h" +#include "qemu/error-report.h" #include "qemu/main-loop.h" #include "system/block-backend.h" =20 #include #include =20 +#include "standard-headers/linux/fuse.h" + #if defined(CONFIG_FALLOCATE_ZERO_RANGE) #include #endif @@ -42,17 +45,27 @@ #endif =20 /* Prevent overly long bounce buffer allocations */ -#define FUSE_MAX_BOUNCE_BYTES (MIN(BDRV_REQUEST_MAX_BYTES, 64 * 1024 * 102= 4)) - +#define FUSE_MAX_READ_BYTES (MIN(BDRV_REQUEST_MAX_BYTES, 64 * 1024 * 1024)) +/* Small enough to fit in the request buffer */ +#define FUSE_MAX_WRITE_BYTES (4 * 1024) =20 typedef struct FuseExport { BlockExport common; =20 struct fuse_session *fuse_session; - struct fuse_buf fuse_buf; unsigned int in_flight; /* atomic */ bool mounted, fd_handler_set_up; =20 + /* + * The request buffer must be able to hold a full write, and/or at lea= st + * FUSE_MIN_READ_BUFFER (from linux/fuse.h) bytes + */ + char request_buf[MAX_CONST( + sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + + FUSE_MAX_WRITE_BYTES, + FUSE_MIN_READ_BUFFER + )]; + /* * Set when there was an unrecoverable error and no requests should be= read * from the device anymore (basically only in case of something we wou= ld @@ -60,6 +73,8 @@ typedef struct FuseExport { */ bool halted; =20 + int fuse_fd; + char *mountpoint; bool writable; bool growable; @@ -72,19 +87,20 @@ typedef struct FuseExport { } FuseExport; =20 static GHashTable *exports; -static const struct fuse_lowlevel_ops fuse_ops; =20 static void fuse_export_shutdown(BlockExport *exp); static void fuse_export_delete(BlockExport *exp); -static void fuse_export_halt(FuseExport *exp) G_GNUC_UNUSED; +static void fuse_export_halt(FuseExport *exp); =20 static void init_exports_table(void); =20 static int mount_fuse_export(FuseExport *exp, Error **errp); -static void read_from_fuse_export(void *opaque); =20 static bool is_regular_file(const char *path, Error **errp); =20 +static bool poll_fuse_fd(void *opaque); +static void read_fuse_fd(void *opaque); +static void fuse_process_request(FuseExport *exp); =20 static void fuse_inc_in_flight(FuseExport *exp) { @@ -105,22 +121,27 @@ static void fuse_dec_in_flight(FuseExport *exp) } } =20 +/** + * Attach FUSE FD read and poll handlers. + */ static void fuse_attach_handlers(FuseExport *exp) { if (exp->halted) { return; } =20 - aio_set_fd_handler(exp->common.ctx, - fuse_session_fd(exp->fuse_session), - read_from_fuse_export, NULL, NULL, NULL, exp); + aio_set_fd_handler(exp->common.ctx, exp->fuse_fd, + read_fuse_fd, NULL, poll_fuse_fd, + read_fuse_fd, exp); exp->fd_handler_set_up =3D true; } =20 +/** + * Detach FUSE FD read and poll handlers. + */ static void fuse_detach_handlers(FuseExport *exp) { - aio_set_fd_handler(exp->common.ctx, - fuse_session_fd(exp->fuse_session), + aio_set_fd_handler(exp->common.ctx, exp->fuse_fd, NULL, NULL, NULL, NULL, NULL); exp->fd_handler_set_up =3D false; } @@ -247,6 +268,14 @@ static int fuse_export_create(BlockExport *blk_exp, =20 g_hash_table_insert(exports, g_strdup(exp->mountpoint), NULL); =20 + exp->fuse_fd =3D fuse_session_fd(exp->fuse_session); + ret =3D fcntl(exp->fuse_fd, F_SETFL, O_NONBLOCK); + if (ret < 0) { + ret =3D -errno; + error_setg_errno(errp, errno, "Failed to make FUSE FD non-blocking= "); + goto fail; + } + fuse_attach_handlers(exp); return 0; =20 @@ -292,7 +321,7 @@ static int mount_fuse_export(FuseExport *exp, Error **e= rrp) mount_opts =3D g_strdup_printf("%s,nosuid,nodev,noatime,max_read=3D%zu= ," "default_permissions%s", exp->writable ? "rw" : "ro", - FUSE_MAX_BOUNCE_BYTES, + FUSE_MAX_READ_BYTES, exp->allow_other ? ",allow_other" : ""); =20 fuse_argv[0] =3D ""; /* Dummy program name */ @@ -301,8 +330,8 @@ static int mount_fuse_export(FuseExport *exp, Error **e= rrp) fuse_argv[3] =3D NULL; fuse_args =3D (struct fuse_args)FUSE_ARGS_INIT(3, (char **)fuse_argv); =20 - exp->fuse_session =3D fuse_session_new(&fuse_args, &fuse_ops, - sizeof(fuse_ops), exp); + /* We just create the session for mounting/unmounting, no need to set = ops */ + exp->fuse_session =3D fuse_session_new(&fuse_args, NULL, 0, NULL); g_free(mount_opts); if (!exp->fuse_session) { error_setg(errp, "Failed to set up FUSE session"); @@ -320,55 +349,94 @@ static int mount_fuse_export(FuseExport *exp, Error *= *errp) } =20 /** - * Callback to be invoked when the FUSE session FD can be read from. - * (This is basically the FUSE event loop.) + * Try to read a single request from the FUSE FD. + * If a request is available, process it, and return true. + * Otherwise, return false. */ -static void read_from_fuse_export(void *opaque) +static bool read_from_fuse_fd(void *opaque) { FuseExport *exp =3D opaque; - int ret; + int fuse_fd =3D exp->fuse_fd; + ssize_t ret; + const struct fuse_in_header *in_hdr; + + fuse_inc_in_flight(exp); =20 if (unlikely(exp->halted)) { - return; + goto no_request; } =20 - fuse_inc_in_flight(exp); + ret =3D RETRY_ON_EINTR(read(fuse_fd, exp->request_buf, + sizeof(exp->request_buf))); + if (ret < 0 && errno =3D=3D EAGAIN) { + /* No request available */ + goto no_request; + } else if (unlikely(ret < 0)) { + error_report("Failed to read from FUSE device: %s", strerror(-ret)= ); + goto no_request; + } =20 - do { - ret =3D fuse_session_receive_buf(exp->fuse_session, &exp->fuse_buf= ); - } while (ret =3D=3D -EINTR); - if (ret < 0) { - goto out; + if (unlikely(ret < sizeof(*in_hdr))) { + error_report("Incomplete read from FUSE device, expected at least = %zu " + "bytes, read %zi bytes; cannot trust subsequent " + "requests, halting the export", + sizeof(*in_hdr), ret); + fuse_export_halt(exp); + goto no_request; } =20 - /* - * Note that polling in any request-processing function can lead to a = nested - * read_from_fuse_export() call, which will overwrite the contents of - * exp->fuse_buf. Anything that takes a buffer needs to take care tha= t the - * content is copied before potentially polling. - */ - fuse_session_process_buf(exp->fuse_session, &exp->fuse_buf); + in_hdr =3D (const struct fuse_in_header *)exp->request_buf; + if (unlikely(ret !=3D in_hdr->len)) { + error_report("Number of bytes read from FUSE device does not match= " + "request size, expected %" PRIu32 " bytes, read %zi " + "bytes; cannot trust subsequent requests, halting the= " + "export", + in_hdr->len, ret); + fuse_export_halt(exp); + goto no_request; + } + + fuse_process_request(exp); + fuse_dec_in_flight(exp); + return true; =20 -out: +no_request: fuse_dec_in_flight(exp); + return false; +} + +/** + * Check the FUSE FD for whether it is readable or not. Because we cannot + * reasonably do this without reading a request at the same time, also rea= d and + * process that request if any. + * (To be used as a poll handler for the FUSE FD.) + */ +static bool poll_fuse_fd(void *opaque) +{ + return read_from_fuse_fd(opaque); +} + +/** + * Read a request from the FUSE FD. + * (To be used as a handler for when the FUSE FD becomes readable.) + */ +static void read_fuse_fd(void *opaque) +{ + read_from_fuse_fd(opaque); } =20 static void fuse_export_shutdown(BlockExport *blk_exp) { FuseExport *exp =3D container_of(blk_exp, FuseExport, common); =20 - if (exp->fuse_session) { - fuse_session_exit(exp->fuse_session); - - if (exp->fd_handler_set_up) { - fuse_detach_handlers(exp); - } + if (exp->fd_handler_set_up) { + fuse_detach_handlers(exp); } =20 if (exp->mountpoint) { /* - * Safe to drop now, because we will not handle any requests - * for this export anymore anyway. + * Safe to drop now, because we will not handle any requests for t= his + * export anymore anyway (at least not from the main thread). */ g_hash_table_remove(exports, exp->mountpoint); } @@ -386,7 +454,6 @@ static void fuse_export_delete(BlockExport *blk_exp) fuse_session_destroy(exp->fuse_session); } =20 - free(exp->fuse_buf.mem); g_free(exp->mountpoint); } =20 @@ -428,46 +495,57 @@ static bool is_regular_file(const char *path, Error *= *errp) } =20 /** - * A chance to set change some parameters supplied to FUSE_INIT. + * Process FUSE INIT. + * Return the number of bytes written to *out on success, and -errno on er= ror. */ -static void fuse_init(void *userdata, struct fuse_conn_info *conn) +static ssize_t fuse_init(FuseExport *exp, struct fuse_init_out *out, + uint32_t max_readahead, uint32_t flags) { - /* - * MIN_NON_ZERO() would not be wrong here, but what we set here - * must equal what has been passed to fuse_session_new(). - * Therefore, as long as max_read must be passed as a mount option - * (which libfuse claims will be changed at some point), we have - * to set max_read to a fixed value here. - */ - conn->max_read =3D FUSE_MAX_BOUNCE_BYTES; + const uint32_t supported_flags =3D FUSE_ASYNC_READ | FUSE_ASYNC_DIO; =20 - conn->max_write =3D MIN_NON_ZERO(BDRV_REQUEST_MAX_BYTES, conn->max_wri= te); -} + *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, =20 -/** - * Let clients look up files. Always return ENOENT because we only - * care about the mountpoint itself. - */ -static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *nam= e) -{ - fuse_reply_err(req, ENOENT); + /* libfuse maximum: 2^16 - 1 */ + .max_background =3D UINT16_MAX, + + /* libfuse default: max_background * 3 / 4 */ + .congestion_threshold =3D (int)UINT16_MAX * 3 / 4, + + /* libfuse default: 1 */ + .time_gran =3D 1, + + /* + * probably unneeded without FUSE_MAX_PAGES, but this would be the + * libfuse default + */ + .max_pages =3D DIV_ROUND_UP(FUSE_MAX_WRITE_BYTES, + qemu_real_host_page_size()), + + /* Only needed for mappings (i.e. DAX) */ + .map_alignment =3D 0, + }; + + return sizeof(*out); } =20 /** * Let clients get file attributes (i.e., stat() the file). + * Return the number of bytes written to *out on success, and -errno on er= ror. */ -static void fuse_getattr(fuse_req_t req, fuse_ino_t inode, - struct fuse_file_info *fi) +static ssize_t fuse_getattr(FuseExport *exp, struct fuse_attr_out *out) { - struct stat statbuf; int64_t length, allocated_blocks; time_t now =3D time(NULL); - FuseExport *exp =3D fuse_req_userdata(req); =20 length =3D blk_getlength(exp->common.blk); if (length < 0) { - fuse_reply_err(req, -length); - return; + return length; } =20 allocated_blocks =3D bdrv_get_allocated_file_size(blk_bs(exp->common.b= lk)); @@ -477,21 +555,24 @@ static void fuse_getattr(fuse_req_t req, fuse_ino_t i= node, allocated_blocks =3D DIV_ROUND_UP(allocated_blocks, 512); } =20 - statbuf =3D (struct stat) { - .st_ino =3D 1, - .st_mode =3D exp->st_mode, - .st_nlink =3D 1, - .st_uid =3D exp->st_uid, - .st_gid =3D exp->st_gid, - .st_size =3D length, - .st_blksize =3D blk_bs(exp->common.blk)->bl.request_alignment, - .st_blocks =3D allocated_blocks, - .st_atime =3D now, - .st_mtime =3D now, - .st_ctime =3D now, + *out =3D (struct fuse_attr_out) { + .attr_valid =3D 1, + .attr =3D { + .ino =3D 1, + .mode =3D exp->st_mode, + .nlink =3D 1, + .uid =3D exp->st_uid, + .gid =3D exp->st_gid, + .size =3D length, + .blksize =3D blk_bs(exp->common.blk)->bl.request_alignment, + .blocks =3D allocated_blocks, + .atime =3D now, + .mtime =3D now, + .ctime =3D now, + }, }; =20 - fuse_reply_attr(req, &statbuf, 1.); + return sizeof(*out); } =20 static int fuse_do_truncate(const FuseExport *exp, int64_t size, @@ -544,160 +625,149 @@ static int fuse_do_truncate(const FuseExport *exp, = int64_t size, * permit access: Read-only exports cannot be given +w, and exports * without allow_other cannot be given a different UID or GID, and * they cannot be given non-owner access. + * Return the number of bytes written to *out on success, and -errno on er= ror. */ -static void fuse_setattr(fuse_req_t req, fuse_ino_t inode, struct stat *st= atbuf, - int to_set, struct fuse_file_info *fi) +static ssize_t fuse_setattr(FuseExport *exp, struct fuse_attr_out *out, + uint32_t to_set, uint64_t size, uint32_t mode, + uint32_t uid, uint32_t gid) { - FuseExport *exp =3D fuse_req_userdata(req); int supported_attrs; int ret; =20 - supported_attrs =3D FUSE_SET_ATTR_SIZE | FUSE_SET_ATTR_MODE; + /* SIZE and MODE are actually supported, the others can be safely igno= red */ + supported_attrs =3D FATTR_SIZE | FATTR_MODE | + FATTR_FH | FATTR_LOCKOWNER | FATTR_KILL_SUIDGID; if (exp->allow_other) { - supported_attrs |=3D FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID; + supported_attrs |=3D FATTR_UID | FATTR_GID; } =20 if (to_set & ~supported_attrs) { - fuse_reply_err(req, ENOTSUP); - return; + return -ENOTSUP; } =20 /* Do some argument checks first before committing to anything */ - if (to_set & FUSE_SET_ATTR_MODE) { + if (to_set & FATTR_MODE) { /* * Without allow_other, non-owners can never access the export, so= do * not allow setting permissions for them */ - if (!exp->allow_other && - (statbuf->st_mode & (S_IRWXG | S_IRWXO)) !=3D 0) - { - fuse_reply_err(req, EPERM); - return; + if (!exp->allow_other && (mode & (S_IRWXG | S_IRWXO)) !=3D 0) { + return -EPERM; } =20 /* +w for read-only exports makes no sense, disallow it */ - if (!exp->writable && - (statbuf->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) !=3D 0) - { - fuse_reply_err(req, EROFS); - return; + if (!exp->writable && (mode & (S_IWUSR | S_IWGRP | S_IWOTH)) !=3D = 0) { + return -EROFS; } } =20 - if (to_set & FUSE_SET_ATTR_SIZE) { + if (to_set & FATTR_SIZE) { if (!exp->writable) { - fuse_reply_err(req, EACCES); - return; + return -EACCES; } =20 - ret =3D fuse_do_truncate(exp, statbuf->st_size, true, PREALLOC_MOD= E_OFF); + ret =3D fuse_do_truncate(exp, size, true, PREALLOC_MODE_OFF); if (ret < 0) { - fuse_reply_err(req, -ret); - return; + return ret; } } =20 - if (to_set & FUSE_SET_ATTR_MODE) { + if (to_set & FATTR_MODE) { /* Ignore FUSE-supplied file type, only change the mode */ - exp->st_mode =3D (statbuf->st_mode & 07777) | S_IFREG; + exp->st_mode =3D (mode & 07777) | S_IFREG; } =20 - if (to_set & FUSE_SET_ATTR_UID) { - exp->st_uid =3D statbuf->st_uid; + if (to_set & FATTR_UID) { + exp->st_uid =3D uid; } =20 - if (to_set & FUSE_SET_ATTR_GID) { - exp->st_gid =3D statbuf->st_gid; + if (to_set & FATTR_GID) { + exp->st_gid =3D gid; } =20 - fuse_getattr(req, inode, fi); + return fuse_getattr(exp, out); } =20 /** - * Let clients open a file (i.e., the exported image). + * Open an inode. We only have a single inode in our exported filesystem,= so we + * just acknowledge the request. + * Return the number of bytes written to *out on success, and -errno on er= ror. */ -static void fuse_open(fuse_req_t req, fuse_ino_t inode, - struct fuse_file_info *fi) +static ssize_t fuse_open(FuseExport *exp, struct fuse_open_out *out) { - fi->direct_io =3D true; - fi->parallel_direct_writes =3D true; - fuse_reply_open(req, fi); + *out =3D (struct fuse_open_out) { + .open_flags =3D FOPEN_DIRECT_IO | FOPEN_PARALLEL_DIRECT_WRITES, + }; + return sizeof(*out); } =20 /** - * Handle client reads from the exported image. + * Handle client reads from the exported image. Allocates *bufptr and rea= ds + * data from the block device into that buffer. + * Returns the buffer (read) size on success, and -errno on error. */ -static void fuse_read(fuse_req_t req, fuse_ino_t inode, - size_t size, off_t offset, struct fuse_file_info *fi) +static ssize_t fuse_read(FuseExport *exp, void **bufptr, + uint64_t offset, uint32_t size) { - FuseExport *exp =3D fuse_req_userdata(req); - int64_t length; + int64_t blk_len; void *buf; int ret; =20 /* Limited by max_read, should not happen */ - if (size > FUSE_MAX_BOUNCE_BYTES) { - fuse_reply_err(req, EINVAL); - return; + if (size > FUSE_MAX_READ_BYTES) { + return -EINVAL; } =20 /** * Clients will expect short reads at EOF, so we have to limit * offset+size to the image length. */ - length =3D blk_getlength(exp->common.blk); - if (length < 0) { - fuse_reply_err(req, -length); - return; + blk_len =3D blk_getlength(exp->common.blk); + if (blk_len < 0) { + return blk_len; } =20 - if (offset + size > length) { - size =3D length - offset; + if (offset + size > blk_len) { + size =3D blk_len - offset; } =20 buf =3D qemu_try_blockalign(blk_bs(exp->common.blk), size); if (!buf) { - fuse_reply_err(req, ENOMEM); - return; + return -ENOMEM; } =20 ret =3D blk_pread(exp->common.blk, offset, size, buf, 0); - if (ret >=3D 0) { - fuse_reply_buf(req, buf, size); - } else { - fuse_reply_err(req, -ret); + if (ret < 0) { + qemu_vfree(buf); + return ret; } =20 - qemu_vfree(buf); + *bufptr =3D buf; + return size; } =20 /** - * Handle client writes to the exported image. + * Handle client writes to the exported image. @buf has the data to be wr= itten + * and will be copied to a bounce buffer before polling for the first time. + * Return the number of bytes written to *out on success, and -errno on er= ror. */ -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) +static ssize_t fuse_write(FuseExport *exp, struct fuse_write_out *out, + uint64_t offset, uint32_t size, const void *buf) { - FuseExport *exp =3D fuse_req_userdata(req); void *copied; - int64_t length; + int64_t blk_len; int ret; =20 /* Limited by max_write, should not happen */ if (size > BDRV_REQUEST_MAX_BYTES) { - fuse_reply_err(req, EINVAL); - return; + return -EINVAL; } =20 if (!exp->writable) { - fuse_reply_err(req, EACCES); - return; + return -EACCES; } =20 - /* - * Heed the note on read_from_fuse_export(): If we poll (which any blk= _*() - * I/O function may do), read_from_fuse_export() may be nested, overwr= iting - * the request buffer content. Therefore, we must copy it here. - */ + /* Must copy to bounce buffer before polling (to allow nesting) */ copied =3D blk_blockalign(exp->common.blk, size); memcpy(copied, buf, size); =20 @@ -705,55 +775,57 @@ static void fuse_write(fuse_req_t req, fuse_ino_t ino= de, const char *buf, * Clients will expect short writes at EOF, so we have to limit * offset+size to the image length. */ - length =3D blk_getlength(exp->common.blk); - if (length < 0) { - fuse_reply_err(req, -length); - goto free_buffer; + blk_len =3D blk_getlength(exp->common.blk); + if (blk_len < 0) { + ret =3D blk_len; + goto fail_free_buffer; } =20 - if (offset + size > length) { + if (offset + size > blk_len) { if (exp->growable) { ret =3D fuse_do_truncate(exp, offset + size, true, PREALLOC_MO= DE_OFF); if (ret < 0) { - fuse_reply_err(req, -ret); - goto free_buffer; + goto fail_free_buffer; } } else { - size =3D length - offset; + size =3D blk_len - offset; } } =20 ret =3D blk_pwrite(exp->common.blk, offset, size, copied, 0); - if (ret >=3D 0) { - fuse_reply_write(req, size); - } else { - fuse_reply_err(req, -ret); + if (ret < 0) { + goto fail_free_buffer; } =20 -free_buffer: qemu_vfree(copied); + + *out =3D (struct fuse_write_out) { + .size =3D size, + }; + return sizeof(*out); + +fail_free_buffer: + qemu_vfree(copied); + return ret; } =20 /** * Let clients perform various fallocate() operations. + * Return 0 on success (no 'out' object), and -errno on error. */ -static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode, - off_t offset, off_t length, - struct fuse_file_info *fi) +static ssize_t fuse_fallocate(FuseExport *exp, uint64_t offset, uint64_t l= ength, + uint32_t mode) { - FuseExport *exp =3D fuse_req_userdata(req); int64_t blk_len; int ret; =20 if (!exp->writable) { - fuse_reply_err(req, EACCES); - return; + return -EACCES; } =20 blk_len =3D blk_getlength(exp->common.blk); if (blk_len < 0) { - fuse_reply_err(req, -blk_len); - return; + return blk_len; } =20 #ifdef CONFIG_FALLOCATE_PUNCH_HOLE @@ -765,16 +837,14 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t= inode, int mode, if (!mode) { /* We can only fallocate at the EOF with a truncate */ if (offset < blk_len) { - fuse_reply_err(req, EOPNOTSUPP); - return; + return -EOPNOTSUPP; } =20 if (offset > blk_len) { /* No preallocation needed here */ ret =3D fuse_do_truncate(exp, offset, true, PREALLOC_MODE_OFF); if (ret < 0) { - fuse_reply_err(req, -ret); - return; + return ret; } } =20 @@ -784,8 +854,7 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t i= node, int mode, #ifdef CONFIG_FALLOCATE_PUNCH_HOLE else if (mode & FALLOC_FL_PUNCH_HOLE) { if (!(mode & FALLOC_FL_KEEP_SIZE)) { - fuse_reply_err(req, EINVAL); - return; + return -EINVAL; } =20 do { @@ -813,8 +882,7 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t i= node, int mode, ret =3D fuse_do_truncate(exp, offset + length, false, PREALLOC_MODE_OFF); if (ret < 0) { - fuse_reply_err(req, -ret); - return; + return ret; } } =20 @@ -832,44 +900,38 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t= inode, int mode, ret =3D -EOPNOTSUPP; } =20 - fuse_reply_err(req, ret < 0 ? -ret : 0); + return ret < 0 ? ret : 0; } =20 /** * Let clients fsync the exported image. + * Return 0 on success (no 'out' object), and -errno on error. */ -static void fuse_fsync(fuse_req_t req, fuse_ino_t inode, int datasync, - struct fuse_file_info *fi) +static ssize_t fuse_fsync(FuseExport *exp) { - FuseExport *exp =3D fuse_req_userdata(req); - int ret; - - ret =3D blk_flush(exp->common.blk); - fuse_reply_err(req, ret < 0 ? -ret : 0); + return blk_flush(exp->common.blk); } =20 /** * Called before an FD to the exported image is closed. (libfuse * notes this to be a way to return last-minute errors.) + * Return 0 on success (no 'out' object), and -errno on error. */ -static void fuse_flush(fuse_req_t req, fuse_ino_t inode, - struct fuse_file_info *fi) +static ssize_t fuse_flush(FuseExport *exp) { - fuse_fsync(req, inode, 1, fi); + return blk_flush(exp->common.blk); } =20 #ifdef CONFIG_FUSE_LSEEK /** * Let clients inquire allocation status. + * Return the number of bytes written to *out on success, and -errno on er= ror. */ -static void fuse_lseek(fuse_req_t req, fuse_ino_t inode, off_t offset, - int whence, struct fuse_file_info *fi) +static ssize_t fuse_lseek(FuseExport *exp, struct fuse_lseek_out *out, + uint64_t offset, uint32_t whence) { - FuseExport *exp =3D fuse_req_userdata(req); - if (whence !=3D SEEK_HOLE && whence !=3D SEEK_DATA) { - fuse_reply_err(req, EINVAL); - return; + return -EINVAL; } =20 while (true) { @@ -879,8 +941,7 @@ static void fuse_lseek(fuse_req_t req, fuse_ino_t inode= , off_t offset, ret =3D bdrv_block_status_above(blk_bs(exp->common.blk), NULL, offset, INT64_MAX, &pnum, NULL, NULL= ); if (ret < 0) { - fuse_reply_err(req, -ret); - return; + return ret; } =20 if (!pnum && (ret & BDRV_BLOCK_EOF)) { @@ -897,34 +958,38 @@ static void fuse_lseek(fuse_req_t req, fuse_ino_t ino= de, off_t offset, =20 blk_len =3D blk_getlength(exp->common.blk); if (blk_len < 0) { - fuse_reply_err(req, -blk_len); - return; + return blk_len; } =20 if (offset > blk_len || whence =3D=3D SEEK_DATA) { - fuse_reply_err(req, ENXIO); - } else { - fuse_reply_lseek(req, offset); + return -ENXIO; } - return; + + *out =3D (struct fuse_lseek_out) { + .offset =3D offset, + }; + return sizeof(*out); } =20 if (ret & BDRV_BLOCK_DATA) { if (whence =3D=3D SEEK_DATA) { - fuse_reply_lseek(req, offset); - return; + *out =3D (struct fuse_lseek_out) { + .offset =3D offset, + }; + return sizeof(*out); } } else { if (whence =3D=3D SEEK_HOLE) { - fuse_reply_lseek(req, offset); - return; + *out =3D (struct fuse_lseek_out) { + .offset =3D offset, + }; + return sizeof(*out); } } =20 /* Safety check against infinite loops */ if (!pnum) { - fuse_reply_err(req, ENXIO); - return; + return -ENXIO; } =20 offset +=3D pnum; @@ -932,21 +997,297 @@ static void fuse_lseek(fuse_req_t req, fuse_ino_t in= ode, off_t offset, } #endif =20 -static const struct fuse_lowlevel_ops fuse_ops =3D { - .init =3D fuse_init, - .lookup =3D fuse_lookup, - .getattr =3D fuse_getattr, - .setattr =3D fuse_setattr, - .open =3D fuse_open, - .read =3D fuse_read, - .write =3D fuse_write, - .fallocate =3D fuse_fallocate, - .flush =3D fuse_flush, - .fsync =3D fuse_fsync, +/** + * Write a FUSE response to the given @fd, using a single buffer consecuti= vely + * containing both the response header and data: Initialize *out_hdr, and = write + * it plus @response_data_length consecutive bytes to @fd. + * + * @fd: FUSE file descriptor + * @req_id: Corresponding request ID + * @out_hdr: Pointer to buffer that will hold the output header, and + * additionally already contains @response_data_length data bytes + * starting at *out_hdr + 1. + * @err: Error code (-errno, or 0 in case of success) + * @response_data_length: Length of data to return (following *out_hdr) + */ +static int fuse_write_response(int fd, uint32_t req_id, + struct fuse_out_header *out_hdr, int err, + size_t response_data_length) +{ + void *write_ptr =3D out_hdr; + size_t to_write =3D sizeof(*out_hdr) + response_data_length; + ssize_t ret; + + *out_hdr =3D (struct fuse_out_header) { + .len =3D to_write, + .error =3D err, + .unique =3D req_id, + }; + + while (true) { + ret =3D RETRY_ON_EINTR(write(fd, write_ptr, to_write)); + if (ret < 0) { + ret =3D -errno; + error_report("Failed to write to FUSE device: %s", strerror(-r= et)); + return ret; + } else { + to_write -=3D ret; + if (to_write > 0) { + write_ptr +=3D ret; + } else { + return 0; /* success */ + } + } + } +} + +/** + * Write a FUSE response to the given @fd, using separate buffers for the + * response header and data: Initialize *out_hdr, and write it plus the da= ta in + * *buf to @fd. + * + * In contrast to fuse_write_response(), this function cannot return error= s, and + * will always return success (error code 0). + * + * @fd: FUSE file descriptor + * @req_id: Corresponding request ID + * @out_hdr: Pointer to buffer that will hold the output header + * @buf: Pointer to response data + * @buflen: Length of response data + */ +static int fuse_write_buf_response(int fd, uint32_t req_id, + struct fuse_out_header *out_hdr, + const void *buf, size_t buflen) +{ + struct iovec iov[2] =3D { + { out_hdr, sizeof(*out_hdr) }, + { (void *)buf, buflen }, + }; + struct iovec *iovp =3D iov; + unsigned iov_count =3D ARRAY_SIZE(iov); + size_t to_write =3D sizeof(*out_hdr) + buflen; + ssize_t ret; + + *out_hdr =3D (struct fuse_out_header) { + .len =3D to_write, + .unique =3D req_id, + }; + + while (true) { + ret =3D RETRY_ON_EINTR(writev(fd, iovp, iov_count)); + if (ret < 0) { + ret =3D -errno; + error_report("Failed to write to FUSE device: %s", strerror(-r= et)); + return ret; + } else { + to_write -=3D ret; + if (to_write > 0) { + iov_discard_front(&iovp, &iov_count, ret); + } else { + return 0; /* success */ + } + } + } +} + +/* + * For use in fuse_process_request(): + * Returns a pointer to the parameter object for the given operation (insi= de of + * exp->request_buf, which is assumed to hold a fuse_in_header first). + * Verifies that the object is complete (exp->request_buf is large enough = to + * hold it in one piece, and the request length includes the whole object). + * + * Note that exp->request_buf may be overwritten after polling, so the ret= urned + * pointer must not be used across a function that may poll! + */ +#define FUSE_IN_OP_STRUCT(op_name, export) \ + ({ \ + const struct fuse_in_header *__in_hdr =3D \ + (const struct fuse_in_header *)(export)->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((export)->request_buf) < __param_len); \ + \ + __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; \ + }) + +/* + * For use in fuse_process_request(): + * 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. + * + * (out_buf should be a char[] array.) + */ +#define FUSE_OUT_OP_STRUCT(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 polling in any request-processing function can lead to a nest= ed + * read_from_fuse_fd() call, which will overwrite the contents of + * exp->request_buf. Anything that takes a buffer needs to take care that= the + * content is copied before potentially polling. + */ +static void fuse_process_request(FuseExport *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 polling */ + { + const struct fuse_in_header *in_hdr =3D + (const struct fuse_in_header *)exp->request_buf; + + opcode =3D in_hdr->opcode; + req_id =3D in_hdr->unique; + } + + switch (opcode) { + case FUSE_INIT: { + const struct fuse_init_in *in =3D FUSE_IN_OP_STRUCT(init, exp); + ret =3D fuse_init(exp, FUSE_OUT_OP_STRUCT(init, out_buf), + in->max_readahead, in->flags); + break; + } + + case FUSE_OPEN: + ret =3D fuse_open(exp, FUSE_OUT_OP_STRUCT(open, out_buf)); + break; + + case FUSE_RELEASE: + ret =3D 0; + break; + + case FUSE_LOOKUP: + ret =3D -ENOENT; /* There is no node but the root node */ + break; + + case FUSE_GETATTR: + ret =3D fuse_getattr(exp, FUSE_OUT_OP_STRUCT(attr, out_buf)); + break; + + case FUSE_SETATTR: { + const struct fuse_setattr_in *in =3D FUSE_IN_OP_STRUCT(setattr, ex= p); + ret =3D fuse_setattr(exp, FUSE_OUT_OP_STRUCT(attr, out_buf), + 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, exp); + ret =3D fuse_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, exp); + uint32_t req_len; + + req_len =3D ((const struct fuse_in_header *)exp->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; + } + + /* + * poll_fuse_fd() has checked that in_hdr->len matches the number = of + * bytes read, which cannot exceed the max_write value we set + * (FUSE_MAX_WRITE_BYTES). So we know that FUSE_MAX_WRITE_BYTES >= =3D + * in_hdr->len >=3D in->size + X, so this assertion must hold. + */ + assert(in->size <=3D FUSE_MAX_WRITE_BYTES); + + /* + * Passing a pointer to `in` (i.e. the request buffer) is fine bec= ause + * fuse_write() takes care to copy its contents before potentially + * polling. + */ + ret =3D fuse_write(exp, FUSE_OUT_OP_STRUCT(write, out_buf), + in->offset, in->size, in + 1); + break; + } + + case FUSE_FALLOCATE: { + const struct fuse_fallocate_in *in =3D FUSE_IN_OP_STRUCT(fallocate= , exp); + ret =3D fuse_fallocate(exp, in->offset, in->length, in->mode); + break; + } + + case FUSE_FSYNC: + ret =3D fuse_fsync(exp); + break; + + case FUSE_FLUSH: + ret =3D fuse_flush(exp); + break; + #ifdef CONFIG_FUSE_LSEEK - .lseek =3D fuse_lseek, + case FUSE_LSEEK: { + const struct fuse_lseek_in *in =3D FUSE_IN_OP_STRUCT(lseek, exp); + ret =3D fuse_lseek(exp, FUSE_OUT_OP_STRUCT(lseek, out_buf), + in->offset, in->whence); + break; + } #endif -}; + + default: + ret =3D -ENOSYS; + } + + /* Ignore errors from fuse_write*(), nothing we can do anyway */ + if (out_data_buffer) { + assert(ret >=3D 0); + fuse_write_buf_response(exp->fuse_fd, req_id, out_hdr, + out_data_buffer, ret); + qemu_vfree(out_data_buffer); + } else { + fuse_write_response(exp->fuse_fd, req_id, out_hdr, + ret < 0 ? ret : 0, + ret < 0 ? 0 : ret); + } +} =20 const BlockExportDriver blk_exp_fuse =3D { .type =3D BLOCK_EXPORT_TYPE_FUSE, --=20 2.48.1 From nobody Wed Apr 2 13:15:36 2025 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=1742918913; cv=none; d=zohomail.com; s=zohoarc; b=iLQyi0147wAa2h281wifBWt9pTs0c0StlGrTc6xsxGWPofVT7D3O2Il2BsOK8iCj1hh+F9tvHBUV3HsEpepZRinVlq0uQWwdGgM+ddrLgYqE4g+beihNt9XXj4lNmplJAAD8sVk8S2Dquvcf+J9WRF1wfi2R3JkWu7py9X5eetI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742918913; 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=MnjO46yBMjBY7w7qvkXPVZdDLv00zM5re/ygX/F9v4g=; b=TqtF/lHNTADgjZC5cDOBRoJ9sowNR/eKWvFmwkyB980BTPRGIufpnx4ClC9cR8isllRJ9st4xI8OYxRBhpCT3ETcBCc4SxdTKKNYusHyn/KZVV+I0AZtBO43hzn+Kr3Kj1Kikxmb0hgAuQsSu3Yt28fPupT7rp/2CMkrgO6pmgk= 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 1742918913506847.9671627826183; Tue, 25 Mar 2025 09:08:33 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6og-0004qC-Qy; Tue, 25 Mar 2025 12:07:51 -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 1tx6oW-0004b7-QY for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:42 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tx6oQ-0007TX-GR for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:36 -0400 Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-363-GuwkQrU1P5WaN0-HW6SaOA-1; Tue, 25 Mar 2025 12:07:31 -0400 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-43ce245c5acso70113475e9.2 for ; Tue, 25 Mar 2025 09:07:31 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3997f9a325csm13976955f8f.22.2025.03.25.09.07.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:07:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918853; 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=MnjO46yBMjBY7w7qvkXPVZdDLv00zM5re/ygX/F9v4g=; b=TVA2HpEv2uX2SrHyJjuWaJznoGHpXg3T9++Qwmvo0OAhVnEpH3pcfzQyCtq1D/+hxZ/Fpw m3ZqIKu1tLD0cRaRPxCpmuCBHzE4Umn9AU3meqF9O0TmTaITVSt746KMri9mrcxzHbExkj EjqlgJWAIg23l7qlCHVNHCbuEr/aVvk= X-MC-Unique: GuwkQrU1P5WaN0-HW6SaOA-1 X-Mimecast-MFC-AGG-ID: GuwkQrU1P5WaN0-HW6SaOA_1742918850 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918850; x=1743523650; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=MnjO46yBMjBY7w7qvkXPVZdDLv00zM5re/ygX/F9v4g=; b=X3Mjq9wutcew25IYpeAN24MJxEggpswSk9PbJERItmuuwkIAGKnTrwsew9yDbvSMDa vUjo4H3j5BQTWK4Ui8f/Xh6vrBzNu/QNeyu9ThL3pmJDDv9yuZ8MkV1LSegs6lFda0vt 6iSnQRy4xGWlJaydd4TjJysr1MCKpk3rZCBjokDzcNSquaYG62xLDDetGiz+4++meEu0 pG+Hr65+JIEGRnXoqpNygiug86sjfHP0UfH9JVPP4/olM52ry503zQL3wsoL9nO6CnaE EUDzda38V4j1bDCwSw/CxT6ykWET3pbf10ZVJmaBvWFmj03BCcuO5ZlAF8EQQLIpHocM D+Og== X-Gm-Message-State: AOJu0Yz7rN1by/ibxC5Qp80yqTQR3xYHZJM3YfeTiJFplvdtmwYojgpM UeuvWIeteYvcagKqKSuJ0/VveZ+1UEOaCcwJrotS2Zr+5vu1MAoYYp+5ao9XY5j9eivMikzK5v4 oiNJp0bXz4Z++IljuGpw+KSY1OVU35LL2EvZgCq4H8/eSI7t019Tl X-Gm-Gg: ASbGncvqfungQFqVbIucquNNQUFo5mFLyQkOz1b8VD+98f9UfcxBvJqQfzZQuBTaOhW CF8Ksnzy3ouWMgZwFF3zoRz9FiHLdQ6A+QtEHSUDN+b60MD+ipI3gLMpLZHi6MdF/jL8nGTcohF LLByOtTFsxeF5PXd5q2w/H2Yoxpa9FPlIn0AznArjwNJF90FfCLGPqBEEvxqBXyL/d2q6MEw6Uq eb1wXf4sm1XIx/sj0fa2xddM1K4iPLyINq15+6MlHBolJJWdjLaRs+qC1mbjwDhJmW2/VZ/eBaE OZYgASdSxbva03J4dGaQBXg8uQyNZt06bIYiZZJflY9gItLOeGEXeFSakp56MC5J5jbxhaC55g= = X-Received: by 2002:a5d:6d88:0:b0:391:29f:4f70 with SMTP id ffacd0b85a97d-3997f8f9259mr14403716f8f.3.1742918850003; Tue, 25 Mar 2025 09:07:30 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGRKCCR7ui2hJfXVn80b2WgwZpO4zJA34xs25wUxnkWi9wEU8Ex++uETTJPfRX5Qh7/grq0uA== X-Received: by 2002:a5d:6d88:0:b0:391:29f:4f70 with SMTP id ffacd0b85a97d-3997f8f9259mr14403667f8f.3.1742918849486; Tue, 25 Mar 2025 09:07:29 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 12/15] fuse: Reduce max read size Date: Tue, 25 Mar 2025 17:06:52 +0100 Message-ID: <20250325160655.119407-11-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-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.129.124; envelope-from=hreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742918914678019000 Content-Type: text/plain; charset="utf-8" We are going to introduce parallel processing via coroutines, a maximum read size of 64 MB may be problematic, allowing users of the export to force us to allocate quite large amounts of memory with just a few requests. At least tone it down to 1 MB, which is still probably far more than enough. (Larger requests are split automatically by the FUSE kernel driver anyway.) (Yes, we inadvertently already had parallel request processing due to nested polling before. Better to fix this late than never.) Signed-off-by: Hanna Czenczek Reviewed-by: Stefan Hajnoczi --- block/export/fuse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 407b101018..1b399eeab7 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -45,7 +45,7 @@ #endif =20 /* Prevent overly long bounce buffer allocations */ -#define FUSE_MAX_READ_BYTES (MIN(BDRV_REQUEST_MAX_BYTES, 64 * 1024 * 1024)) +#define FUSE_MAX_READ_BYTES (MIN(BDRV_REQUEST_MAX_BYTES, 1 * 1024 * 1024)) /* Small enough to fit in the request buffer */ #define FUSE_MAX_WRITE_BYTES (4 * 1024) =20 --=20 2.48.1 From nobody Wed Apr 2 13:15:36 2025 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=1742918968; cv=none; d=zohomail.com; s=zohoarc; b=lit2N/IHtV3b/SyFpztbeD/zlJfIYkhGCGmFMDTG+IEu67SNaAQcjrziuPWIQ98w1mcGZKl/aBR1P99r7oNRSiey6I5yzt6Fvh1DX+3mV1d+dVzrWCaasxLFUEdiYF/0ihEJfhnx6AU0JwA95NDMcY6MkK9GkbzYVuAV2ykv3Hc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742918968; 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=wurdmr9oOnsE6I+jfIThmOAVwUsXIhIvyG/3Qd14gPA=; b=SOQssiiAl/9TSoBZxBY1oZMUpzOE2EBHyHrJ1WEwwVcOJrJJtocGa9JCGVII3e6zr30/pJpIwZ2VR2TLjKf0XvtOjre1j9pBj+8LjSQpvLIAyCmATzR0IahnMnWLuUP83srWghzUrVcHEj3VybI+O3/tZa8WLNCPg9UG7GXpM2E= 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 1742918968533701.3918335276649; Tue, 25 Mar 2025 09:09:28 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6pp-0006Gs-95; Tue, 25 Mar 2025 12:09:01 -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 1tx6oa-0004iR-Qt for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:46 -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 1tx6oW-0007Uc-HF for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:44 -0400 Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-518-XqjB4YXdMlGP_-gpUxYqcw-1; Tue, 25 Mar 2025 12:07:36 -0400 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-43ceeaf1524so31955945e9.1 for ; Tue, 25 Mar 2025 09:07:36 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-43d4fd26cecsm153836205e9.17.2025.03.25.09.07.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:07:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918858; 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-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wurdmr9oOnsE6I+jfIThmOAVwUsXIhIvyG/3Qd14gPA=; b=A7Ak0pfS4mUiuo3JSdqMMzV86sPPPiwpqqAmreF6ANPvRMe/w3I9lzVnlpzycY3U6Qzchu zsfHQmNQxbqRYgAgEBU6qGsmQ+/QjzjJYiFDjgwVXzDBqh2YxiEI4EJfE+Wn3/3PK6kxr5 sAnJoOuxs+l211SeHfb66dkMnCqtqus= X-MC-Unique: XqjB4YXdMlGP_-gpUxYqcw-1 X-Mimecast-MFC-AGG-ID: XqjB4YXdMlGP_-gpUxYqcw_1742918855 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918855; x=1743523655; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=wurdmr9oOnsE6I+jfIThmOAVwUsXIhIvyG/3Qd14gPA=; b=gVRSOcJ6q+96abwLJ6t1CYMEYfsU8E1qXYwqe0bNhyFJgilpTUB9ziPjYnd7V7K7hx CFIHoaRi80oKnOCY2Hlj1LRkL7KJ3xYppRaGwYmmx8F9keMaUaNa/6gRXfbC7n6kuLjB UEC3q9i7xt7py+yXzbdMV05AsZDqUpYRdSazp06l80oBbnpisry88htMrnza38EnfQiX v7RZhailiOoe7nRGOc/Clmxx8DEIaeK4jYDZjh8+9Bm3xalxSiWR2y1r+4wzSMG/UMIO kWjWuV9BGQE21oL5MeZQriYhsZgMxHBz6dyU5ZI4EbH+xUWAYsVy5csTIIa/vrNGW5Kz xELw== X-Gm-Message-State: AOJu0YyjLaK9+L6VcAyXR5MAxk3AZ3lZ8RnXPrQWC0OBTNvbhAMj7No0 esTGN/G4tG36HvZMRIIKTyLuU0agxRHily9xIpYuQBOgdsF1J0M5ukG2d5tGMEqpgi9EVBjovrv 0jXHt8w2WuFSka3HItMPlCtFdozm3B+r/Jbl2KxvY1A8FxakuISek X-Gm-Gg: ASbGncvX5oVEgMolivIrIOiiaaWJMqCvbQ2h4tPTzHjXMjT/yLSRDcxRLNJVbK2u+u/ FvEru3OKU6IWnb6smTAt7gw8wtd45SG5Lt456FD7upsPbLQsHAqC1O8m2RzRDq4hockvqTytpI8 dYpw6hgWua24mQjXGjYefMUugLKAtmqDJ3USaanZWREbkXe2Jl3c6O3yMWrs0+IJ6us1/5r3s5t onuWT44kstVnJtGijBs2uxOTAE41ReyQwfPfOCFSb/kcHre+fP47JxG2sJCiFfG7K7ob2CN0f0A hvzWM12QSUkDcrKf0+R6FwFnoe1ULEqsUyO/RQ31Uuvy3hrecjknD18t4CJ5hm6pWmke1Tox7Q= = X-Received: by 2002:a05:600c:2152:b0:43b:c305:3954 with SMTP id 5b1f17b1804b1-43d775be4d0mr2932255e9.8.1742918853581; Tue, 25 Mar 2025 09:07:33 -0700 (PDT) X-Google-Smtp-Source: AGHT+IH5uNRStHeZKj0ILCH3Hfl7rQOA+J8pjVjddVskHL20oOdMdqhZJodoFIyhx8iHsUIKGAMJkg== X-Received: by 2002:a05:600c:2152:b0:43b:c305:3954 with SMTP id 5b1f17b1804b1-43d775be4d0mr2931665e9.8.1742918852960; Tue, 25 Mar 2025 09:07:32 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 13/15] fuse: Process requests in coroutines Date: Tue, 25 Mar 2025 17:06:53 +0100 Message-ID: <20250325160655.119407-12-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-1-hreitz@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Type: text/plain; charset=UTF-8 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: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742918970445019100 Make fuse_process_request() a coroutine_fn (fuse_co_process_request()) and have read_from_fuse_fd() launch it inside of a newly created coroutine instead of running it synchronously. This way, we can process requests in parallel. These are the benchmark results, compared to (a) the original results with libfuse, and (b) the results after switching away from libfuse (i.e. before this patch): file: (vs. libfuse / vs. no libfuse) read: seq aio: 120.6k =C2=B11.1k (+ 53 % / + 58 %) rand aio: 113.3k =C2=B15.9k (+188 % / +325 %) seq sync: 52.4k =C2=B10.4k (+ 61 % / + 10 %) rand sync: 10.4k =C2=B10.4k (+ 6 % / + 3 %) write: seq aio: 79.8k =C2=B10.8k (+ 29 % / + 37 %) rand aio: 79.0k =C2=B10.6k (+ 29 % / + 36 %) seq sync: 41.5k =C2=B10.3k (+ 49 % / + 15 %) rand sync: 41.4k =C2=B10.2k (+ 50 % / + 15 %) null: read: seq aio: 266.1k =C2=B11.5k (+ 24 % / - 1 %) rand aio: 264.1k =C2=B12.5k (+ 24 % / =C2=B1 0 %) seq sync: 135.6k =C2=B13.2k (+ 50 % / + 1 %) rand sync: 134.7k =C2=B13.0k (+ 50 % / + 2 %) write: seq aio: 281.0k =C2=B11.8k (+ 38 % / + 2 %) rand aio: 288.1k =C2=B16.1k (+ 43 % / + 6 %) seq sync: 142.2k =C2=B13.1k (+ 65 % / + 9 %) rand sync: 141.1k =C2=B12.9k (+ 66 % / + 11 %) So for non-AIO cases (and the null driver, which does not yield), there is little change; but for file AIO, results greatly improve, resolving the performance issue we saw before (when switching away from libfuse). Signed-off-by: Hanna Czenczek Reviewed-by: Stefan Hajnoczi --- block/export/fuse.c | 209 ++++++++++++++++++++++++++------------------ 1 file changed, 126 insertions(+), 83 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 1b399eeab7..345e833171 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -27,6 +27,7 @@ #include "block/qapi.h" #include "qapi/error.h" #include "qapi/qapi-commands-block.h" +#include "qemu/coroutine.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "system/block-backend.h" @@ -86,6 +87,12 @@ typedef struct FuseExport { gid_t st_gid; } FuseExport; =20 +/* Parameters to the request processing coroutine */ +typedef struct FuseRequestCoParam { + FuseExport *exp; + int got_request; +} FuseRequestCoParam; + static GHashTable *exports; =20 static void fuse_export_shutdown(BlockExport *exp); @@ -100,7 +107,7 @@ static bool is_regular_file(const char *path, Error **e= rrp); =20 static bool poll_fuse_fd(void *opaque); static void read_fuse_fd(void *opaque); -static void fuse_process_request(FuseExport *exp); +static void coroutine_fn fuse_co_process_request(FuseExport *exp); =20 static void fuse_inc_in_flight(FuseExport *exp) { @@ -350,12 +357,20 @@ static int mount_fuse_export(FuseExport *exp, Error *= *errp) =20 /** * Try to read a single request from the FUSE FD. - * If a request is available, process it, and return true. - * Otherwise, return false. + * Takes a FuseRequestCoParam object pointer in `opaque`. + * + * If a request is available, process it, and set FuseRequestCoParam.got_r= equest + * to 1. Otherwise, set it to 0. + * (Not using a boolean allows callers to initialize it e.g. with -EINPROG= RESS.) + * + * The FuseRequestCoParam object is only accessed until yielding for the f= irst + * time, i.e. may be dropped by the caller after running the coroutine unt= il it + * yields. */ -static bool read_from_fuse_fd(void *opaque) +static void coroutine_fn co_read_from_fuse_fd(void *opaque) { - FuseExport *exp =3D opaque; + FuseRequestCoParam *co_param =3D opaque; + FuseExport *exp =3D co_param->exp; int fuse_fd =3D exp->fuse_fd; ssize_t ret; const struct fuse_in_header *in_hdr; @@ -396,13 +411,15 @@ static bool read_from_fuse_fd(void *opaque) goto no_request; } =20 - fuse_process_request(exp); + /* Must set this before yielding */ + co_param->got_request =3D 1; + fuse_co_process_request(exp); fuse_dec_in_flight(exp); - return true; + return; =20 no_request: + co_param->got_request =3D 0; fuse_dec_in_flight(exp); - return false; } =20 /** @@ -413,7 +430,17 @@ no_request: */ static bool poll_fuse_fd(void *opaque) { - return read_from_fuse_fd(opaque); + Coroutine *co; + FuseRequestCoParam co_param =3D { + .exp =3D opaque, + .got_request =3D -EINPROGRESS, + }; + + co =3D qemu_coroutine_create(co_read_from_fuse_fd, &co_param); + qemu_coroutine_enter(co); + assert(co_param.got_request !=3D -EINPROGRESS); + + return co_param.got_request; } =20 /** @@ -422,7 +449,15 @@ static bool poll_fuse_fd(void *opaque) */ static void read_fuse_fd(void *opaque) { - read_from_fuse_fd(opaque); + Coroutine *co; + FuseRequestCoParam co_param =3D { + .exp =3D opaque, + .got_request =3D -EINPROGRESS, + }; + + co =3D qemu_coroutine_create(co_read_from_fuse_fd, &co_param); + qemu_coroutine_enter(co); + assert(co_param.got_request !=3D -EINPROGRESS); } =20 static void fuse_export_shutdown(BlockExport *blk_exp) @@ -498,8 +533,9 @@ static bool is_regular_file(const char *path, Error **e= rrp) * Process FUSE INIT. * Return the number of bytes written to *out on success, and -errno on er= ror. */ -static ssize_t fuse_init(FuseExport *exp, struct fuse_init_out *out, - uint32_t max_readahead, uint32_t flags) +static ssize_t coroutine_fn +fuse_co_init(FuseExport *exp, struct fuse_init_out *out, + uint32_t max_readahead, uint32_t flags) { const uint32_t supported_flags =3D FUSE_ASYNC_READ | FUSE_ASYNC_DIO; =20 @@ -538,17 +574,18 @@ static ssize_t fuse_init(FuseExport *exp, struct fuse= _init_out *out, * Let clients get file attributes (i.e., stat() the file). * Return the number of bytes written to *out on success, and -errno on er= ror. */ -static ssize_t fuse_getattr(FuseExport *exp, struct fuse_attr_out *out) +static ssize_t coroutine_fn +fuse_co_getattr(FuseExport *exp, struct fuse_attr_out *out) { int64_t length, allocated_blocks; time_t now =3D time(NULL); =20 - length =3D blk_getlength(exp->common.blk); + length =3D blk_co_getlength(exp->common.blk); if (length < 0) { return length; } =20 - allocated_blocks =3D bdrv_get_allocated_file_size(blk_bs(exp->common.b= lk)); + allocated_blocks =3D bdrv_co_get_allocated_file_size(blk_bs(exp->commo= n.blk)); if (allocated_blocks <=3D 0) { allocated_blocks =3D DIV_ROUND_UP(length, 512); } else { @@ -575,8 +612,9 @@ static ssize_t fuse_getattr(FuseExport *exp, struct fus= e_attr_out *out) return sizeof(*out); } =20 -static int fuse_do_truncate(const FuseExport *exp, int64_t size, - bool req_zero_write, PreallocMode prealloc) +static int coroutine_fn +fuse_co_do_truncate(const FuseExport *exp, int64_t size, bool req_zero_wri= te, + PreallocMode prealloc) { uint64_t blk_perm, blk_shared_perm; BdrvRequestFlags truncate_flags =3D 0; @@ -605,8 +643,8 @@ static int fuse_do_truncate(const FuseExport *exp, int6= 4_t size, } } =20 - ret =3D blk_truncate(exp->common.blk, size, true, prealloc, - truncate_flags, NULL); + ret =3D blk_co_truncate(exp->common.blk, size, true, prealloc, + truncate_flags, NULL); =20 if (add_resize_perm) { /* Must succeed, because we are only giving up the RESIZE permissi= on */ @@ -627,9 +665,9 @@ static int fuse_do_truncate(const FuseExport *exp, int6= 4_t size, * they cannot be given non-owner access. * Return the number of bytes written to *out on success, and -errno on er= ror. */ -static ssize_t fuse_setattr(FuseExport *exp, struct fuse_attr_out *out, - uint32_t to_set, uint64_t size, uint32_t mode, - uint32_t uid, uint32_t gid) +static ssize_t coroutine_fn +fuse_co_setattr(FuseExport *exp, struct fuse_attr_out *out, uint32_t to_se= t, + uint64_t size, uint32_t mode, uint32_t uid, uint32_t gid) { int supported_attrs; int ret; @@ -666,7 +704,7 @@ static ssize_t fuse_setattr(FuseExport *exp, struct fus= e_attr_out *out, return -EACCES; } =20 - ret =3D fuse_do_truncate(exp, size, true, PREALLOC_MODE_OFF); + ret =3D fuse_co_do_truncate(exp, size, true, PREALLOC_MODE_OFF); if (ret < 0) { return ret; } @@ -685,7 +723,7 @@ static ssize_t fuse_setattr(FuseExport *exp, struct fus= e_attr_out *out, exp->st_gid =3D gid; } =20 - return fuse_getattr(exp, out); + return fuse_co_getattr(exp, out); } =20 /** @@ -693,7 +731,8 @@ static ssize_t fuse_setattr(FuseExport *exp, struct fus= e_attr_out *out, * just acknowledge the request. * Return the number of bytes written to *out on success, and -errno on er= ror. */ -static ssize_t fuse_open(FuseExport *exp, struct fuse_open_out *out) +static ssize_t coroutine_fn +fuse_co_open(FuseExport *exp, struct fuse_open_out *out) { *out =3D (struct fuse_open_out) { .open_flags =3D FOPEN_DIRECT_IO | FOPEN_PARALLEL_DIRECT_WRITES, @@ -706,8 +745,8 @@ static ssize_t fuse_open(FuseExport *exp, struct fuse_o= pen_out *out) * data from the block device into that buffer. * Returns the buffer (read) size on success, and -errno on error. */ -static ssize_t fuse_read(FuseExport *exp, void **bufptr, - uint64_t offset, uint32_t size) +static ssize_t coroutine_fn +fuse_co_read(FuseExport *exp, void **bufptr, uint64_t offset, uint32_t siz= e) { int64_t blk_len; void *buf; @@ -722,7 +761,7 @@ static ssize_t fuse_read(FuseExport *exp, void **bufptr, * Clients will expect short reads at EOF, so we have to limit * offset+size to the image length. */ - blk_len =3D blk_getlength(exp->common.blk); + blk_len =3D blk_co_getlength(exp->common.blk); if (blk_len < 0) { return blk_len; } @@ -736,7 +775,7 @@ static ssize_t fuse_read(FuseExport *exp, void **bufptr, return -ENOMEM; } =20 - ret =3D blk_pread(exp->common.blk, offset, size, buf, 0); + ret =3D blk_co_pread(exp->common.blk, offset, size, buf, 0); if (ret < 0) { qemu_vfree(buf); return ret; @@ -748,11 +787,12 @@ static ssize_t fuse_read(FuseExport *exp, void **bufp= tr, =20 /** * Handle client writes to the exported image. @buf has the data to be wr= itten - * and will be copied to a bounce buffer before polling for the first time. + * and will be copied to a bounce buffer before yielding for the first tim= e. * Return the number of bytes written to *out on success, and -errno on er= ror. */ -static ssize_t fuse_write(FuseExport *exp, struct fuse_write_out *out, - uint64_t offset, uint32_t size, const void *buf) +static ssize_t coroutine_fn +fuse_co_write(FuseExport *exp, struct fuse_write_out *out, + uint64_t offset, uint32_t size, const void *buf) { void *copied; int64_t blk_len; @@ -767,7 +807,7 @@ static ssize_t fuse_write(FuseExport *exp, struct fuse_= write_out *out, return -EACCES; } =20 - /* Must copy to bounce buffer before polling (to allow nesting) */ + /* Must copy to bounce buffer before potentially yielding */ copied =3D blk_blockalign(exp->common.blk, size); memcpy(copied, buf, size); =20 @@ -775,7 +815,7 @@ static ssize_t fuse_write(FuseExport *exp, struct fuse_= write_out *out, * Clients will expect short writes at EOF, so we have to limit * offset+size to the image length. */ - blk_len =3D blk_getlength(exp->common.blk); + blk_len =3D blk_co_getlength(exp->common.blk); if (blk_len < 0) { ret =3D blk_len; goto fail_free_buffer; @@ -783,7 +823,8 @@ static ssize_t fuse_write(FuseExport *exp, struct fuse_= write_out *out, =20 if (offset + size > blk_len) { if (exp->growable) { - ret =3D fuse_do_truncate(exp, offset + size, true, PREALLOC_MO= DE_OFF); + ret =3D fuse_co_do_truncate(exp, offset + size, true, + PREALLOC_MODE_OFF); if (ret < 0) { goto fail_free_buffer; } @@ -792,7 +833,7 @@ static ssize_t fuse_write(FuseExport *exp, struct fuse_= write_out *out, } } =20 - ret =3D blk_pwrite(exp->common.blk, offset, size, copied, 0); + ret =3D blk_co_pwrite(exp->common.blk, offset, size, copied, 0); if (ret < 0) { goto fail_free_buffer; } @@ -813,8 +854,9 @@ fail_free_buffer: * Let clients perform various fallocate() operations. * Return 0 on success (no 'out' object), and -errno on error. */ -static ssize_t fuse_fallocate(FuseExport *exp, uint64_t offset, uint64_t l= ength, - uint32_t mode) +static ssize_t coroutine_fn +fuse_co_fallocate(FuseExport *exp, + uint64_t offset, uint64_t length, uint32_t mode) { int64_t blk_len; int ret; @@ -823,7 +865,7 @@ static ssize_t fuse_fallocate(FuseExport *exp, uint64_t= offset, uint64_t length, return -EACCES; } =20 - blk_len =3D blk_getlength(exp->common.blk); + blk_len =3D blk_co_getlength(exp->common.blk); if (blk_len < 0) { return blk_len; } @@ -842,14 +884,14 @@ static ssize_t fuse_fallocate(FuseExport *exp, uint64= _t offset, uint64_t length, =20 if (offset > blk_len) { /* No preallocation needed here */ - ret =3D fuse_do_truncate(exp, offset, true, PREALLOC_MODE_OFF); + ret =3D fuse_co_do_truncate(exp, offset, true, PREALLOC_MODE_O= FF); if (ret < 0) { return ret; } } =20 - ret =3D fuse_do_truncate(exp, offset + length, true, - PREALLOC_MODE_FALLOC); + ret =3D fuse_co_do_truncate(exp, offset + length, true, + PREALLOC_MODE_FALLOC); } #ifdef CONFIG_FALLOCATE_PUNCH_HOLE else if (mode & FALLOC_FL_PUNCH_HOLE) { @@ -860,8 +902,9 @@ static ssize_t fuse_fallocate(FuseExport *exp, uint64_t= offset, uint64_t length, do { int size =3D MIN(length, BDRV_REQUEST_MAX_BYTES); =20 - ret =3D blk_pwrite_zeroes(exp->common.blk, offset, size, - BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLB= ACK); + ret =3D blk_co_pwrite_zeroes(exp->common.blk, offset, size, + BDRV_REQ_MAY_UNMAP | + BDRV_REQ_NO_FALLBACK); if (ret =3D=3D -ENOTSUP) { /* * fallocate() specifies to return EOPNOTSUPP for unsuppor= ted @@ -879,8 +922,8 @@ static ssize_t fuse_fallocate(FuseExport *exp, uint64_t= offset, uint64_t length, else if (mode & FALLOC_FL_ZERO_RANGE) { if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + length > blk_len) { /* No need for zeroes, we are going to write them ourselves */ - ret =3D fuse_do_truncate(exp, offset + length, false, - PREALLOC_MODE_OFF); + ret =3D fuse_co_do_truncate(exp, offset + length, false, + PREALLOC_MODE_OFF); if (ret < 0) { return ret; } @@ -889,8 +932,8 @@ static ssize_t fuse_fallocate(FuseExport *exp, uint64_t= offset, uint64_t length, do { int size =3D MIN(length, BDRV_REQUEST_MAX_BYTES); =20 - ret =3D blk_pwrite_zeroes(exp->common.blk, - offset, size, 0); + ret =3D blk_co_pwrite_zeroes(exp->common.blk, + offset, size, 0); offset +=3D size; length -=3D size; } while (ret =3D=3D 0 && length > 0); @@ -907,9 +950,9 @@ static ssize_t fuse_fallocate(FuseExport *exp, uint64_t= offset, uint64_t length, * Let clients fsync the exported image. * Return 0 on success (no 'out' object), and -errno on error. */ -static ssize_t fuse_fsync(FuseExport *exp) +static ssize_t coroutine_fn fuse_co_fsync(FuseExport *exp) { - return blk_flush(exp->common.blk); + return blk_co_flush(exp->common.blk); } =20 /** @@ -917,9 +960,9 @@ static ssize_t fuse_fsync(FuseExport *exp) * notes this to be a way to return last-minute errors.) * Return 0 on success (no 'out' object), and -errno on error. */ -static ssize_t fuse_flush(FuseExport *exp) +static ssize_t coroutine_fn fuse_co_flush(FuseExport *exp) { - return blk_flush(exp->common.blk); + return blk_co_flush(exp->common.blk); } =20 #ifdef CONFIG_FUSE_LSEEK @@ -927,8 +970,9 @@ static ssize_t fuse_flush(FuseExport *exp) * Let clients inquire allocation status. * Return the number of bytes written to *out on success, and -errno on er= ror. */ -static ssize_t fuse_lseek(FuseExport *exp, struct fuse_lseek_out *out, - uint64_t offset, uint32_t whence) +static ssize_t coroutine_fn +fuse_co_lseek(FuseExport *exp, struct fuse_lseek_out *out, + uint64_t offset, uint32_t whence) { if (whence !=3D SEEK_HOLE && whence !=3D SEEK_DATA) { return -EINVAL; @@ -938,8 +982,8 @@ static ssize_t fuse_lseek(FuseExport *exp, struct fuse_= lseek_out *out, int64_t pnum; int ret; =20 - ret =3D bdrv_block_status_above(blk_bs(exp->common.blk), NULL, - offset, INT64_MAX, &pnum, NULL, NULL= ); + ret =3D bdrv_co_block_status_above(blk_bs(exp->common.blk), NULL, + offset, INT64_MAX, &pnum, NULL, N= ULL); if (ret < 0) { return ret; } @@ -956,7 +1000,7 @@ static ssize_t fuse_lseek(FuseExport *exp, struct fuse= _lseek_out *out, * and @blk_len (the client-visible EOF). */ =20 - blk_len =3D blk_getlength(exp->common.blk); + blk_len =3D blk_co_getlength(exp->common.blk); if (blk_len < 0) { return blk_len; } @@ -1091,14 +1135,14 @@ static int fuse_write_buf_response(int fd, uint32_t= req_id, } =20 /* - * For use in fuse_process_request(): + * For use in fuse_co_process_request(): * Returns a pointer to the parameter object for the given operation (insi= de of * exp->request_buf, which is assumed to hold a fuse_in_header first). * Verifies that the object is complete (exp->request_buf is large enough = to * hold it in one piece, and the request length includes the whole object). * - * Note that exp->request_buf may be overwritten after polling, so the ret= urned - * pointer must not be used across a function that may poll! + * Note that exp->request_buf may be overwritten after yielding, so the re= turned + * pointer must not be used across a function that may yield! */ #define FUSE_IN_OP_STRUCT(op_name, export) \ ({ \ @@ -1122,7 +1166,7 @@ static int fuse_write_buf_response(int fd, uint32_t r= eq_id, }) =20 /* - * For use in fuse_process_request(): + * For use in fuse_co_process_request(): * 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. @@ -1145,12 +1189,11 @@ static int fuse_write_buf_response(int fd, uint32_t= req_id, /** * Process a FUSE request, incl. writing the response. * - * Note that polling in any request-processing function can lead to a nest= ed - * read_from_fuse_fd() call, which will overwrite the contents of - * exp->request_buf. Anything that takes a buffer needs to take care that= the - * content is copied before potentially polling. + * Note that yielding in any request-processing function can overwrite the + * contents of exp->request_buf. Anything that takes a buffer needs to ta= ke + * care that the content is copied before yielding. */ -static void fuse_process_request(FuseExport *exp) +static void coroutine_fn fuse_co_process_request(FuseExport *exp) { uint32_t opcode; uint64_t req_id; @@ -1171,7 +1214,7 @@ static void fuse_process_request(FuseExport *exp) void *out_data_buffer =3D NULL; ssize_t ret; =20 - /* Limit scope to ensure pointer is no longer used after polling */ + /* Limit scope to ensure pointer is no longer used after yielding */ { const struct fuse_in_header *in_hdr =3D (const struct fuse_in_header *)exp->request_buf; @@ -1183,13 +1226,13 @@ static void fuse_process_request(FuseExport *exp) switch (opcode) { case FUSE_INIT: { const struct fuse_init_in *in =3D FUSE_IN_OP_STRUCT(init, exp); - ret =3D fuse_init(exp, FUSE_OUT_OP_STRUCT(init, out_buf), - in->max_readahead, in->flags); + ret =3D fuse_co_init(exp, FUSE_OUT_OP_STRUCT(init, out_buf), + in->max_readahead, in->flags); break; } =20 case FUSE_OPEN: - ret =3D fuse_open(exp, FUSE_OUT_OP_STRUCT(open, out_buf)); + ret =3D fuse_co_open(exp, FUSE_OUT_OP_STRUCT(open, out_buf)); break; =20 case FUSE_RELEASE: @@ -1201,19 +1244,19 @@ static void fuse_process_request(FuseExport *exp) break; =20 case FUSE_GETATTR: - ret =3D fuse_getattr(exp, FUSE_OUT_OP_STRUCT(attr, out_buf)); + ret =3D fuse_co_getattr(exp, FUSE_OUT_OP_STRUCT(attr, out_buf)); break; =20 case FUSE_SETATTR: { const struct fuse_setattr_in *in =3D FUSE_IN_OP_STRUCT(setattr, ex= p); - ret =3D fuse_setattr(exp, FUSE_OUT_OP_STRUCT(attr, out_buf), - in->valid, in->size, in->mode, in->uid, in->gid= ); + ret =3D fuse_co_setattr(exp, FUSE_OUT_OP_STRUCT(attr, out_buf), + in->valid, in->size, in->mode, in->uid, in->= gid); break; } =20 case FUSE_READ: { const struct fuse_read_in *in =3D FUSE_IN_OP_STRUCT(read, exp); - ret =3D fuse_read(exp, &out_data_buffer, in->offset, in->size); + ret =3D fuse_co_read(exp, &out_data_buffer, in->offset, in->size); break; } =20 @@ -1241,33 +1284,33 @@ static void fuse_process_request(FuseExport *exp) =20 /* * Passing a pointer to `in` (i.e. the request buffer) is fine bec= ause - * fuse_write() takes care to copy its contents before potentially - * polling. + * fuse_co_write() takes care to copy its contents before potentia= lly + * yielding. */ - ret =3D fuse_write(exp, FUSE_OUT_OP_STRUCT(write, out_buf), - in->offset, in->size, in + 1); + ret =3D fuse_co_write(exp, FUSE_OUT_OP_STRUCT(write, out_buf), + in->offset, in->size, in + 1); break; } =20 case FUSE_FALLOCATE: { const struct fuse_fallocate_in *in =3D FUSE_IN_OP_STRUCT(fallocate= , exp); - ret =3D fuse_fallocate(exp, in->offset, in->length, in->mode); + ret =3D fuse_co_fallocate(exp, in->offset, in->length, in->mode); break; } =20 case FUSE_FSYNC: - ret =3D fuse_fsync(exp); + ret =3D fuse_co_fsync(exp); break; =20 case FUSE_FLUSH: - ret =3D fuse_flush(exp); + ret =3D fuse_co_flush(exp); break; =20 #ifdef CONFIG_FUSE_LSEEK case FUSE_LSEEK: { const struct fuse_lseek_in *in =3D FUSE_IN_OP_STRUCT(lseek, exp); - ret =3D fuse_lseek(exp, FUSE_OUT_OP_STRUCT(lseek, out_buf), - in->offset, in->whence); + ret =3D fuse_co_lseek(exp, FUSE_OUT_OP_STRUCT(lseek, out_buf), + in->offset, in->whence); break; } #endif --=20 2.48.1 From nobody Wed Apr 2 13:15:36 2025 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=1742918905; cv=none; d=zohomail.com; s=zohoarc; b=HMTqdVBuibn34nAKtdq/P+8fYr3tjkd0gPXuDcmrlB5tVMbYg+9GYVgU1VbkRrRTd/Ga+iJ2o5mt9LnasOwHSl7xVfgkLRPgsBUNQQ9gismaHfbqYOro9x+MfLRc/KvF4OP3TjL9Lv0K56fpOk9Y2vFG6Jb5KW5qJZQaOUzpJmE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742918905; 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=Ym6QLhcbFjPi/k/bGM7alt0zFF1729o+7dm4HNJbfwI=; b=D2bB6wt5zsjxchXnCiSVRvM9kMJ6SPkJOuokjMgaciltTb6RYBSZr7l7hQ62rPuWQ4d5IAb7G/NN4bVm/rGFbwlE0rHDjjR0XMrk1GGmacSUhET4+8Bf2kxU8xU82RURvRcU2X90l2e3eE3m7FnMGXj/tR1M5m+GH9AFa1a6JzI= 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 1742918905526642.7065614058467; Tue, 25 Mar 2025 09:08:25 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6ok-00058M-VB; Tue, 25 Mar 2025 12:07:55 -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 1tx6oe-0004lI-RC for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:49 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tx6oa-0007VK-D1 for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:47 -0400 Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-463-EuqXb2-aPBmovCvNYAZMEQ-1; Tue, 25 Mar 2025 12:07:38 -0400 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-43d22c304adso28796465e9.0 for ; Tue, 25 Mar 2025 09:07:38 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-43d4fcea65fsm159848365e9.7.2025.03.25.09.07.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:07:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918861; 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-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Ym6QLhcbFjPi/k/bGM7alt0zFF1729o+7dm4HNJbfwI=; b=N952EhL1qi51qVKCrm5fD9bMAs/fEo2a4FLDzHxkiELFDgI85Okki54Uqzmj62ZgMoJ24F XDPvfox2pWzJJa0RTbxVynXzWRMoUBHSwOVw49NSvRjbXt+3ZG2CfxfUVO4RwBzIQsyDik FQvZTHyWEKWV2khjJGFCbz6A+FD5l8E= X-MC-Unique: EuqXb2-aPBmovCvNYAZMEQ-1 X-Mimecast-MFC-AGG-ID: EuqXb2-aPBmovCvNYAZMEQ_1742918857 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918857; x=1743523657; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Ym6QLhcbFjPi/k/bGM7alt0zFF1729o+7dm4HNJbfwI=; b=Br1+vYfUIioI+8RdQFHoszPGGm7UqbmsK1mK/naICF28V/o8OXCifaKC1Yzyd/94se ylLAI6GclQvNDvok/qRR9FOdsfdErPwR18z9WZZr7oIsdLqnKrWmy/RkZ1P6kmLFPk69 bzuZ4RjdCzghq1+m8v1yb5RD8H3dS+7soKwfXkDgWckDDR7aM4PAtHDjaRZMWvHCL0jn nEko2O3EjJq2Dss8UBN2h96J8yPt9Val7vjbLy1RMqpUKBTIXJTNNb7R88cx5y17HztX DyrNCHfGiOglCOwKNBp93iGT1NwLEjpFSD/iGB455jCsoQRDN0IqDXwnndauJm+biZn0 GzGw== X-Gm-Message-State: AOJu0YxTHciaJuRoIteFdsKQEZHi28hqoUOeWJAB1oXOZwrin90yhMCA +Dse0f4WPfkmt+TxuFbmwM8YzmRdPIilwZhkcAbwNhMqYhd4j4G5r2z0yqLXQp43EHQG9NZdpfp gc7+nNYIgmZpHNz3HNMaUHe5SWmOohpU2rGLK4UpuNApeVDAqIwdQ X-Gm-Gg: ASbGncvS2ik3N91MrTN/wAnGuZDtzzM/Yyl++dy4tehoyLZrD1PM1CU/sfbyqb7vsF+ oyULo6/W71vB6lXS0IAd5YZR0ZDRwgzdUWBqFS3Ha8B7+mIRSeHPyvTyC4qEPD4bnZ8vIQBBEgn xHIbJHBLKqYMIZTOF9m/p65W/wODXeSBXfvUEHislihb22pyEYFRW/YClYNk0wW2YBlcO9rqIEU 2eLyDn8Ew2zKiyx1uAJAj13wgkhPgodhna+sByQJ758YfkNJcfHJIZ2yg2p9nvh1ELLTdvFw06i TFWYeYNjIONG1hSMjYMsCqx3fwXe0yJI2hF3dU2hp80ilPwyu41dpOhowXTubZbc7UEvDFe1eA= = X-Received: by 2002:a05:6000:4011:b0:390:df83:1f22 with SMTP id ffacd0b85a97d-39acc47723cmr331482f8f.25.1742918856808; Tue, 25 Mar 2025 09:07:36 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFQ9l9votqNSq9+kZt9ItLCyBh6/eNY6a0ouPk61sTqDTIvcGpahlQlJTb1fHhoKKA1LorqrA== X-Received: by 2002:a05:6000:4011:b0:390:df83:1f22 with SMTP id ffacd0b85a97d-39acc47723cmr331417f8f.25.1742918856179; Tue, 25 Mar 2025 09:07:36 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 14/15] fuse: Implement multi-threading Date: Tue, 25 Mar 2025 17:06:54 +0100 Message-ID: <20250325160655.119407-13-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-1-hreitz@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Type: text/plain; charset=UTF-8 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.129.124; envelope-from=hreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742918906987019000 FUSE allows creating multiple request queues by "cloning" /dev/fuse FDs (via open("/dev/fuse") + ioctl(FUSE_DEV_IOC_CLONE)). We can use this to implement multi-threading. Note that the interface presented here differs from the multi-queue interface of virtio-blk: The latter maps virtqueues to iothreads, which allows processing multiple virtqueues in a single iothread. The equivalent (processing multiple FDs in a single iothread) would not make sense for FUSE because those FDs are used in a round-robin fashion by the FUSE kernel driver. Putting two of them into a single iothread will just create a bottleneck. Therefore, all we need is an array of iothreads, and we will create one "queue" (FD) per thread. These are the benchmark results when using four threads (compared to a single thread); note that fio still only uses a single job, but performance can still be improved because of said round-robin usage for the queues. (Not in the sync case, though, in which case I guess it just adds overhead.) file: read: seq aio: 264.8k =C2=B10.8k (+120 %) rand aio: 143.8k =C2=B10.4k (+ 27 %) seq sync: 49.9k =C2=B10.5k (- 5 %) rand sync: 10.3k =C2=B10.1k (- 1 %) write: seq aio: 226.6k =C2=B12.1k (+184 %) rand aio: 225.9k =C2=B11.8k (+186 %) seq sync: 36.9k =C2=B10.6k (- 11 %) rand sync: 36.9k =C2=B10.2k (- 11 %) null: read: seq aio: 315.2k =C2=B111.0k (+18 %) rand aio: 300.5k =C2=B110.8k (+14 %) seq sync: 114.2k =C2=B1 3.6k (-16 %) rand sync: 112.5k =C2=B1 2.8k (-16 %) write: seq aio: 222.6k =C2=B16.8k (-21 %) rand aio: 220.5k =C2=B16.8k (-23 %) seq sync: 117.2k =C2=B13.7k (-18 %) rand sync: 116.3k =C2=B14.4k (-18 %) (I don't know what's going on in the null-write AIO case, sorry.) Here's results for numjobs=3D4: "Before", i.e. without multithreading in QSD/FUSE (results compared to numjobs=3D1): file: read: seq aio: 104.7k =C2=B1 0.4k (- 13 %) rand aio: 111.5k =C2=B1 0.4k (- 2 %) seq sync: 71.0k =C2=B113.8k (+ 36 %) rand sync: 41.4k =C2=B1 0.1k (+297 %) write: seq aio: 79.4k =C2=B10.1k (- 1 %) rand aio: 78.6k =C2=B10.1k (=C2=B1 0 %) seq sync: 83.3k =C2=B10.1k (+101 %) rand sync: 82.0k =C2=B10.2k (+ 98 %) null: read: seq aio: 260.5k =C2=B11.5k (- 2 %) rand aio: 260.1k =C2=B11.4k (- 2 %) seq sync: 291.8k =C2=B11.3k (+115 %) rand sync: 280.1k =C2=B11.7k (+115 %) write: seq aio: 280.1k =C2=B11.7k (=C2=B1 0 %) rand aio: 279.5k =C2=B11.4k (- 3 %) seq sync: 306.7k =C2=B12.2k (+116 %) rand sync: 305.9k =C2=B11.8k (+117 %) (As probably expected, little difference in the AIO case, but great improvements in the sync case because it kind of gives it an artificial iodepth of 4.) "After", i.e. with four threads in QSD/FUSE (now results compared to the above): file: read: seq aio: 193.3k =C2=B1 1.8k (+ 85 %) rand aio: 329.3k =C2=B1 0.3k (+195 %) seq sync: 66.2k =C2=B113.0k (- 7 %) rand sync: 40.1k =C2=B1 0.0k (- 3 %) write: seq aio: 219.7k =C2=B10.8k (+177 %) rand aio: 217.2k =C2=B11.5k (+176 %) seq sync: 92.5k =C2=B10.2k (+ 11 %) rand sync: 91.9k =C2=B10.2k (+ 12 %) null: read: seq aio: 706.7k =C2=B12.1k (+171 %) rand aio: 714.7k =C2=B13.2k (+175 %) seq sync: 431.7k =C2=B13.0k (+ 48 %) rand sync: 435.4k =C2=B12.8k (+ 50 %) write: seq aio: 746.9k =C2=B12.8k (+167 %) rand aio: 749.0k =C2=B14.9k (+168 %) seq sync: 420.7k =C2=B13.1k (+ 37 %) rand sync: 419.1k =C2=B12.5k (+ 37 %) So this helps mainly for the AIO cases, but also in the null sync cases, because null is always CPU-bound, so more threads help. Signed-off-by: Hanna Czenczek --- qapi/block-export.json | 8 +- block/export/fuse.c | 214 +++++++++++++++++++++++++++++++++-------- 2 files changed, 179 insertions(+), 43 deletions(-) diff --git a/qapi/block-export.json b/qapi/block-export.json index c783e01a53..0bdd5992eb 100644 --- a/qapi/block-export.json +++ b/qapi/block-export.json @@ -179,12 +179,18 @@ # mount the export with allow_other, and if that fails, try again # without. (since 6.1; default: auto) # +# @iothreads: Enables multi-threading: Handle requests in each of the +# given iothreads (instead of the block device's iothread, or the +# export's "main" iothread). For this, the FUSE FD is duplicated so +# there is one FD per iothread. (since 10.1) +# # Since: 6.0 ## { 'struct': 'BlockExportOptionsFuse', 'data': { 'mountpoint': 'str', '*growable': 'bool', - '*allow-other': 'FuseExportAllowOther' }, + '*allow-other': 'FuseExportAllowOther', + '*iothreads': ['str'] }, 'if': 'CONFIG_FUSE' } =20 ## diff --git a/block/export/fuse.c b/block/export/fuse.c index 345e833171..0edd994392 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -31,11 +31,14 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "system/block-backend.h" +#include "system/block-backend.h" +#include "system/iothread.h" =20 #include #include =20 #include "standard-headers/linux/fuse.h" +#include =20 #if defined(CONFIG_FALLOCATE_ZERO_RANGE) #include @@ -50,12 +53,17 @@ /* Small enough to fit in the request buffer */ #define FUSE_MAX_WRITE_BYTES (4 * 1024) =20 -typedef struct FuseExport { - BlockExport common; +typedef struct FuseExport FuseExport; =20 - struct fuse_session *fuse_session; - unsigned int in_flight; /* atomic */ - bool mounted, fd_handler_set_up; +/* + * 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 { + FuseExport *exp; + + AioContext *ctx; + int fuse_fd; =20 /* * The request buffer must be able to hold a full write, and/or at lea= st @@ -66,6 +74,14 @@ typedef struct FuseExport { FUSE_MAX_WRITE_BYTES, FUSE_MIN_READ_BUFFER )]; +} FuseQueue; + +struct FuseExport { + BlockExport common; + + struct fuse_session *fuse_session; + unsigned int in_flight; /* atomic */ + bool mounted, fd_handler_set_up; =20 /* * Set when there was an unrecoverable error and no requests should be= read @@ -74,7 +90,15 @@ typedef struct FuseExport { */ bool halted; =20 - int fuse_fd; + int num_queues; + FuseQueue *queues; + /* + * True if this export should follow the generic export's AioContext. + * Will be false if the queues' AioContexts have been explicitly set b= y the + * user, i.e. are expected to stay in those contexts. + * (I.e. is always false if there is more than one queue.) + */ + bool follow_aio_context; =20 char *mountpoint; bool writable; @@ -85,11 +109,11 @@ typedef struct FuseExport { mode_t st_mode; uid_t st_uid; gid_t st_gid; -} FuseExport; +}; =20 /* Parameters to the request processing coroutine */ typedef struct FuseRequestCoParam { - FuseExport *exp; + FuseQueue *q; int got_request; } FuseRequestCoParam; =20 @@ -102,12 +126,13 @@ static void fuse_export_halt(FuseExport *exp); static void init_exports_table(void); =20 static int mount_fuse_export(FuseExport *exp, Error **errp); +static int clone_fuse_fd(int fd, Error **errp); =20 static bool is_regular_file(const char *path, Error **errp); =20 static bool poll_fuse_fd(void *opaque); static void read_fuse_fd(void *opaque); -static void coroutine_fn fuse_co_process_request(FuseExport *exp); +static void coroutine_fn fuse_co_process_request(FuseQueue *q); =20 static void fuse_inc_in_flight(FuseExport *exp) { @@ -137,9 +162,11 @@ static void fuse_attach_handlers(FuseExport *exp) return; } =20 - aio_set_fd_handler(exp->common.ctx, exp->fuse_fd, - read_fuse_fd, NULL, poll_fuse_fd, - read_fuse_fd, exp); + for (int i =3D 0; i < exp->num_queues; i++) { + aio_set_fd_handler(exp->queues[i].ctx, exp->queues[i].fuse_fd, + read_fuse_fd, NULL, poll_fuse_fd, + read_fuse_fd, &exp->queues[i]); + } exp->fd_handler_set_up =3D true; } =20 @@ -148,8 +175,10 @@ static void fuse_attach_handlers(FuseExport *exp) */ static void fuse_detach_handlers(FuseExport *exp) { - aio_set_fd_handler(exp->common.ctx, exp->fuse_fd, - NULL, NULL, NULL, NULL, NULL); + for (int i =3D 0; i < exp->num_queues; i++) { + aio_set_fd_handler(exp->queues[i].ctx, exp->queues[i].fuse_fd, + NULL, NULL, NULL, NULL, NULL); + } exp->fd_handler_set_up =3D false; } =20 @@ -164,6 +193,11 @@ static void fuse_export_drained_end(void *opaque) =20 /* 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); + exp->queues[0].ctx =3D exp->common.ctx; + } + fuse_attach_handlers(exp); } =20 @@ -187,10 +221,52 @@ static int fuse_export_create(BlockExport *blk_exp, ERRP_GUARD(); /* ensure clean-up even with error_fatal */ FuseExport *exp =3D container_of(blk_exp, FuseExport, common); BlockExportOptionsFuse *args =3D &blk_exp_args->u.fuse; + FuseQueue *q; int ret; =20 assert(blk_exp_args->type =3D=3D BLOCK_EXPORT_TYPE_FUSE); =20 + if (args->iothreads) { + strList *e; + + exp->follow_aio_context =3D false; + exp->num_queues =3D 0; + for (e =3D args->iothreads; e; e =3D e->next) { + exp->num_queues++; + } + if (exp->num_queues < 1) { + error_setg(errp, "Need at least one queue"); + ret =3D -EINVAL; + goto fail; + } + exp->queues =3D g_new0(FuseQueue, exp->num_queues); + q =3D exp->queues; + for (e =3D args->iothreads; e; e =3D e->next) { + IOThread *iothread =3D iothread_by_id(e->value); + + if (!iothread) { + error_setg(errp, "IOThread \"%s\" does not exist", e->valu= e); + ret =3D -EINVAL; + goto fail; + } + + *(q++) =3D (FuseQueue) { + .exp =3D exp, + .ctx =3D iothread_get_aio_context(iothread), + .fuse_fd =3D -1, + }; + } + } else { + exp->follow_aio_context =3D true; + exp->num_queues =3D 1; + exp->queues =3D g_new(FuseQueue, exp->num_queues); + exp->queues[0] =3D (FuseQueue) { + .exp =3D exp, + .ctx =3D exp->common.ctx, + .fuse_fd =3D -1, + }; + } + /* For growable and writable exports, take the RESIZE permission */ if (args->growable || blk_exp_args->writable) { uint64_t blk_perm, blk_shared_perm; @@ -275,14 +351,24 @@ static int fuse_export_create(BlockExport *blk_exp, =20 g_hash_table_insert(exports, g_strdup(exp->mountpoint), NULL); =20 - exp->fuse_fd =3D fuse_session_fd(exp->fuse_session); - ret =3D fcntl(exp->fuse_fd, F_SETFL, O_NONBLOCK); + assert(exp->num_queues >=3D 1); + exp->queues[0].fuse_fd =3D fuse_session_fd(exp->fuse_session); + ret =3D fcntl(exp->queues[0].fuse_fd, F_SETFL, O_NONBLOCK); if (ret < 0) { ret =3D -errno; error_setg_errno(errp, errno, "Failed to make FUSE FD non-blocking= "); goto fail; } =20 + for (int i =3D 1; i < exp->num_queues; i++) { + int fd =3D clone_fuse_fd(exp->queues[0].fuse_fd, errp); + if (fd < 0) { + ret =3D fd; + goto fail; + } + exp->queues[i].fuse_fd =3D fd; + } + fuse_attach_handlers(exp); return 0; =20 @@ -355,6 +441,39 @@ static int mount_fuse_export(FuseExport *exp, Error **= errp) return 0; } =20 +/** + * Clone the given /dev/fuse file descriptor, yielding a second FD from wh= ich + * requests can be pulled for the associated filesystem. Returns an FD on + * success, and -errno on error. + */ +static int clone_fuse_fd(int fd, Error **errp) +{ + uint32_t src_fd =3D fd; + int new_fd; + int ret; + + /* + * The name "/dev/fuse" is fixed, see libfuse's lib/fuse_loop_mt.c + * (fuse_clone_chan()). + */ + new_fd =3D open("/dev/fuse", O_RDWR | O_CLOEXEC | O_NONBLOCK); + if (new_fd < 0) { + ret =3D -errno; + error_setg_errno(errp, errno, "Failed to open /dev/fuse"); + return ret; + } + + ret =3D ioctl(new_fd, FUSE_DEV_IOC_CLONE, &src_fd); + if (ret < 0) { + ret =3D -errno; + error_setg_errno(errp, errno, "Failed to clone FUSE FD"); + close(new_fd); + return ret; + } + + return new_fd; +} + /** * Try to read a single request from the FUSE FD. * Takes a FuseRequestCoParam object pointer in `opaque`. @@ -370,8 +489,9 @@ static int mount_fuse_export(FuseExport *exp, Error **e= rrp) static void coroutine_fn co_read_from_fuse_fd(void *opaque) { FuseRequestCoParam *co_param =3D opaque; - FuseExport *exp =3D co_param->exp; - int fuse_fd =3D exp->fuse_fd; + FuseQueue *q =3D co_param->q; + int fuse_fd =3D q->fuse_fd; + FuseExport *exp =3D q->exp; ssize_t ret; const struct fuse_in_header *in_hdr; =20 @@ -381,8 +501,7 @@ static void coroutine_fn co_read_from_fuse_fd(void *opa= que) goto no_request; } =20 - ret =3D RETRY_ON_EINTR(read(fuse_fd, exp->request_buf, - sizeof(exp->request_buf))); + ret =3D RETRY_ON_EINTR(read(fuse_fd, q->request_buf, sizeof(q->request= _buf))); if (ret < 0 && errno =3D=3D EAGAIN) { /* No request available */ goto no_request; @@ -400,7 +519,7 @@ static void coroutine_fn co_read_from_fuse_fd(void *opa= que) goto no_request; } =20 - in_hdr =3D (const struct fuse_in_header *)exp->request_buf; + in_hdr =3D (const struct fuse_in_header *)q->request_buf; if (unlikely(ret !=3D in_hdr->len)) { error_report("Number of bytes read from FUSE device does not match= " "request size, expected %" PRIu32 " bytes, read %zi " @@ -413,7 +532,7 @@ static void coroutine_fn co_read_from_fuse_fd(void *opa= que) =20 /* Must set this before yielding */ co_param->got_request =3D 1; - fuse_co_process_request(exp); + fuse_co_process_request(q); fuse_dec_in_flight(exp); return; =20 @@ -432,7 +551,7 @@ static bool poll_fuse_fd(void *opaque) { Coroutine *co; FuseRequestCoParam co_param =3D { - .exp =3D opaque, + .q =3D opaque, .got_request =3D -EINPROGRESS, }; =20 @@ -451,7 +570,7 @@ static void read_fuse_fd(void *opaque) { Coroutine *co; FuseRequestCoParam co_param =3D { - .exp =3D opaque, + .q =3D opaque, .got_request =3D -EINPROGRESS, }; =20 @@ -481,6 +600,16 @@ static void fuse_export_delete(BlockExport *blk_exp) { FuseExport *exp =3D container_of(blk_exp, FuseExport, common); =20 + for (int i =3D 0; i < exp->num_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); + } + } + g_free(exp->queues); + if (exp->fuse_session) { if (exp->mounted) { fuse_session_unmount(exp->fuse_session); @@ -1137,23 +1266,23 @@ static int fuse_write_buf_response(int fd, uint32_t= req_id, /* * For use in fuse_co_process_request(): * Returns a pointer to the parameter object for the given operation (insi= de of - * exp->request_buf, which is assumed to hold a fuse_in_header first). - * Verifies that the object is complete (exp->request_buf is large enough = to + * q->request_buf, which is assumed to hold a fuse_in_header first). + * Verifies that the object is complete (q->request_buf is large enough to * hold it in one piece, and the request length includes the whole object). * - * Note that exp->request_buf may be overwritten after yielding, so the re= turned + * Note that q->request_buf may be overwritten after yielding, so the retu= rned * pointer must not be used across a function that may yield! */ -#define FUSE_IN_OP_STRUCT(op_name, export) \ +#define FUSE_IN_OP_STRUCT(op_name, queue) \ ({ \ const struct fuse_in_header *__in_hdr =3D \ - (const struct fuse_in_header *)(export)->request_buf; \ + (const struct fuse_in_header *)(q)->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((export)->request_buf) < __param_len); \ + QEMU_BUILD_BUG_ON(sizeof((q)->request_buf) < __param_len); \ \ __req_len =3D __in_hdr->len; \ if (__req_len < __param_len) { \ @@ -1190,11 +1319,12 @@ static int fuse_write_buf_response(int fd, uint32_t= req_id, * Process a FUSE request, incl. writing the response. * * Note that yielding in any request-processing function can overwrite the - * contents of exp->request_buf. Anything that takes a buffer needs to ta= ke + * contents of q->request_buf. Anything that takes a buffer needs to take * care that the content is copied before yielding. */ -static void coroutine_fn fuse_co_process_request(FuseExport *exp) +static void coroutine_fn fuse_co_process_request(FuseQueue *q) { + FuseExport *exp =3D q->exp; uint32_t opcode; uint64_t req_id; /* @@ -1217,7 +1347,7 @@ static void coroutine_fn fuse_co_process_request(Fuse= Export *exp) /* Limit scope to ensure pointer is no longer used after yielding */ { const struct fuse_in_header *in_hdr =3D - (const struct fuse_in_header *)exp->request_buf; + (const struct fuse_in_header *)q->request_buf; =20 opcode =3D in_hdr->opcode; req_id =3D in_hdr->unique; @@ -1225,7 +1355,7 @@ static void coroutine_fn fuse_co_process_request(Fuse= Export *exp) =20 switch (opcode) { case FUSE_INIT: { - const struct fuse_init_in *in =3D FUSE_IN_OP_STRUCT(init, exp); + 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); break; @@ -1248,23 +1378,23 @@ static void coroutine_fn fuse_co_process_request(Fu= seExport *exp) break; =20 case FUSE_SETATTR: { - const struct fuse_setattr_in *in =3D FUSE_IN_OP_STRUCT(setattr, ex= p); + 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); break; } =20 case FUSE_READ: { - const struct fuse_read_in *in =3D FUSE_IN_OP_STRUCT(read, exp); + const struct fuse_read_in *in =3D FUSE_IN_OP_STRUCT(read, q); ret =3D fuse_co_read(exp, &out_data_buffer, in->offset, in->size); break; } =20 case FUSE_WRITE: { - const struct fuse_write_in *in =3D FUSE_IN_OP_STRUCT(write, exp); + const struct fuse_write_in *in =3D FUSE_IN_OP_STRUCT(write, q); uint32_t req_len; =20 - req_len =3D ((const struct fuse_in_header *)exp->request_buf)->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, @@ -1293,7 +1423,7 @@ static void coroutine_fn fuse_co_process_request(Fuse= Export *exp) } =20 case FUSE_FALLOCATE: { - const struct fuse_fallocate_in *in =3D FUSE_IN_OP_STRUCT(fallocate= , exp); + const struct fuse_fallocate_in *in =3D FUSE_IN_OP_STRUCT(fallocate= , q); ret =3D fuse_co_fallocate(exp, in->offset, in->length, in->mode); break; } @@ -1308,7 +1438,7 @@ static void coroutine_fn fuse_co_process_request(Fuse= Export *exp) =20 #ifdef CONFIG_FUSE_LSEEK case FUSE_LSEEK: { - const struct fuse_lseek_in *in =3D FUSE_IN_OP_STRUCT(lseek, exp); + 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); break; @@ -1322,11 +1452,11 @@ static void coroutine_fn fuse_co_process_request(Fu= seExport *exp) /* Ignore errors from fuse_write*(), nothing we can do anyway */ if (out_data_buffer) { assert(ret >=3D 0); - fuse_write_buf_response(exp->fuse_fd, req_id, out_hdr, + fuse_write_buf_response(q->fuse_fd, req_id, out_hdr, out_data_buffer, ret); qemu_vfree(out_data_buffer); } else { - fuse_write_response(exp->fuse_fd, req_id, out_hdr, + fuse_write_response(q->fuse_fd, req_id, out_hdr, ret < 0 ? ret : 0, ret < 0 ? 0 : ret); } --=20 2.48.1 From nobody Wed Apr 2 13:15:36 2025 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=1742919201; cv=none; d=zohomail.com; s=zohoarc; b=GvYj3ovpb39Sq/z5s4i9WaujdVeaSfFGv3KmrwFgz5ELMFVClCHEE1XDikGLklUgnAns9xLFBr9dF+3zl0L+mzpW7dDlLZGbmsigTrkpxEA2e/zczfhRf+XTzw45VY3+n9cGuAVu5QNycAhqA+nz7lt00J0asig4OoDE6HbTmUU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742919201; 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=1es1GLLwxEkCTyu3NIQVBVSJl87pq6gN18T+d/SedE4=; b=TLZv1t4rLnQGpccsq3RyvGFc2GNSAR6w1nqdy9U4E6X5SKrQ2+QSaa5Kh79pLUEWpt+oUK4F9g7OQXjC9hXwaFk3YF8wGHeyw/Gnero0azzsoc/jGM84mkNZi5NshY6UZZpieqtZeYuonzainh7wWcOh7M6epqDLwSNHqDTZOTQ= 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 1742919201252721.9703887623538; Tue, 25 Mar 2025 09:13:21 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tx6ol-00059R-6S; Tue, 25 Mar 2025 12:07:55 -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 1tx6of-0004mp-Gi for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:49 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tx6ob-0007WA-OB for qemu-devel@nongnu.org; Tue, 25 Mar 2025 12:07:49 -0400 Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-313-891WnNXJMziLvz1QEjqXrw-1; Tue, 25 Mar 2025 12:07:41 -0400 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-3912539665cso3290777f8f.1 for ; Tue, 25 Mar 2025 09:07:40 -0700 (PDT) Received: from localhost (p200300cfd74f9db6ee8035b86ef736e5.dip0.t-ipconnect.de. [2003:cf:d74f:9db6:ee80:35b8:6ef7:36e5]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3997f9f0107sm14368892f8f.99.2025.03.25.09.07.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Mar 2025 09:07:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1742918864; 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=1es1GLLwxEkCTyu3NIQVBVSJl87pq6gN18T+d/SedE4=; b=PHxQVP+SuPuIXaAR9PcXwPGqt9nzRpqvRGSYL09PH2Bp/ZLdVWrz1ZBodrnYdZQUvz2JaJ VZnT2OZdjKp7v9PywDFLytArAfkeL4/Ium0uChbQqg3LSSL24loWzHYqurapoBXF6196Wi jGM/jmY+07822Kd3dK0FNZ+p1JFRMVQ= X-MC-Unique: 891WnNXJMziLvz1QEjqXrw-1 X-Mimecast-MFC-AGG-ID: 891WnNXJMziLvz1QEjqXrw_1742918860 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742918859; x=1743523659; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=1es1GLLwxEkCTyu3NIQVBVSJl87pq6gN18T+d/SedE4=; b=WmhhhHYgCE73imEYeWDQyQdRO7KjYaMmkIOQc3xoCpR+VPgkqODo/9HbC0WzZE0keE U3bWacrBBi+0jvb6p+frWoVXP5VfPpI+FMBe3qsdPeXHF5eUTsocQYS5W6wpyLN8Qy3o pcAhkQJVkk0LzY8V5bja76BxEe9vUJKFwMSi4zXr1dTr/lJGoTLZTgeay6+fySv2b45N 3D7QR28qD/yjSC3vHTw4psE/tF9lDerMGDXVWhtCEB+hT5s8OKQlGn7IwoxKslcSqiuy ecc9/cjE0MsOXJEaMaDjsLloVMfQp3HWZ9rPwgOZedtMPBApgTD27C/aJuVmM9eso1ea Utug== X-Gm-Message-State: AOJu0YysUgXEuFRUzBdrsPBzFe51CUTG0ruJrwj07ckLhyBismNMzgad FTTVGmpAcuyki1r29Ai0lqKHt8vlnlmTqTiVzoT6reiexkCd5UbJR6bDWR1NqRRu6SL1Z7w7CTK XVqGJLSOZVBldS11PsKfqq6YHpj/SkvqDdjiW7FMMjoNpXNo+EGfifV3SykQw X-Gm-Gg: ASbGncsGGKIFurVwdJ+wFHfuzVEgmMxGCoS0FqCTORAp2RmWMRD6FdXjZ/tjSuKNbbk LxWkX50UD9BXCJx5x3bB9WW5cVWJ3gROFjFpwMT1/Ls2M4hZXQHc/BUBhHxBUaz1gJA+TLMWg5V fUI0BMUeiIA2bGxRo7X5ug/OnScvL7uxVvhId2aTm6MyU1sCtVo2Utfc36br8tiqTNzlyQhy7uH D864NDatZHITcBV4GViFEyPmbNGlnzT/D7hnqfOJiEwc1x6HgICoAKdKT0VJwLdnT0pCtSuSJbT czcokSMckY8OoiMT+kc97iww6tCZlnvUgVkO/a3cgdLPNajJ+Hq0lhh9W9vg3qi15dDY7S8HTg= = X-Received: by 2002:a05:6000:400a:b0:391:865:5a93 with SMTP id ffacd0b85a97d-39acc485440mr343121f8f.22.1742918858613; Tue, 25 Mar 2025 09:07:38 -0700 (PDT) X-Google-Smtp-Source: AGHT+IF0mqXCT2sKfdk4792VP2AiQhRN9sb7936odygOMz25SHAztB2E3RzvG45vBRs+axvhWDkqCw== X-Received: by 2002:a05:6000:400a:b0:391:865:5a93 with SMTP id ffacd0b85a97d-39acc485440mr343064f8f.22.1742918858053; Tue, 25 Mar 2025 09:07:38 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf Subject: [PATCH 15/15] fuse: Increase MAX_WRITE_SIZE with a second buffer Date: Tue, 25 Mar 2025 17:06:55 +0100 Message-ID: <20250325160655.119407-14-hreitz@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250325160529.117543-1-hreitz@redhat.com> References: <20250325160529.117543-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.129.124; envelope-from=hreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.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.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, 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: 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: 1742919202218019000 Content-Type: text/plain; charset="utf-8" We probably want to support larger write sizes than just 4k; 64k seems nice. However, we cannot read partial requests from the FUSE FD, we always have to read requests in full; so our read buffer must be large enough to accommodate potential 64k writes if we want to support that. Always allocating FuseRequest objects with 64k buffers in them seems wasteful, though. But we can get around the issue by splitting the buffer into two and using readv(): One part will hold all normal (up to 4k) write requests and all other requests, and a second part (the "spill-over buffer") will be used only for larger write requests. Each FuseQueue has its own spill-over buffer, and only if we find it used when reading a request will we move its ownership into the FuseRequest object and allocate a new spill-over buffer for the queue. This way, we get to support "large" write sizes without having to allocate big buffers when they aren't used. Also, this even reduces the size of the FuseRequest objects because the read buffer has to have at least FUSE_MIN_READ_BUFFER (8192) bytes; but the requests we support are not quite so large (except for >4k writes), so until now, we basically had to have useless padding in there. With the spill-over buffer added, the FUSE_MIN_READ_BUFFER requirement is easily met and we can decrease the size of the buffer portion that is right inside of FuseRequest. As for benchmarks, the benefit of this patch can be shown easily by writing a 4G image (with qemu-img convert) to a FUSE export: - Before this patch: Takes 25.6 s (14.4 s with -t none) - After this patch: Takes 4.5 s (5.5 s with -t none) Signed-off-by: Hanna Czenczek Reviewed-by: Stefan Hajnoczi --- block/export/fuse.c | 137 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 118 insertions(+), 19 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index 0edd994392..a24c5538b3 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -50,8 +50,17 @@ =20 /* Prevent overly long bounce buffer allocations */ #define FUSE_MAX_READ_BYTES (MIN(BDRV_REQUEST_MAX_BYTES, 1 * 1024 * 1024)) -/* Small enough to fit in the request buffer */ -#define FUSE_MAX_WRITE_BYTES (4 * 1024) +/* + * FUSE_MAX_WRITE_BYTES determines the maximum number of bytes we support = in a + * write request; FUSE_IN_PLACE_WRITE_BYTES and FUSE_SPILLOVER_BUF_SIZE + * determine the split between the size of the in-place buffer in FuseRequ= est + * and the spill-over buffer in FuseQueue. See FuseQueue.spillover_buf fo= r a + * detailed explanation. + */ +#define FUSE_IN_PLACE_WRITE_BYTES (4 * 1024) +#define FUSE_MAX_WRITE_BYTES (64 * 1024) +#define FUSE_SPILLOVER_BUF_SIZE \ + (FUSE_MAX_WRITE_BYTES - FUSE_IN_PLACE_WRITE_BYTES) =20 typedef struct FuseExport FuseExport; =20 @@ -67,15 +76,49 @@ typedef struct FuseQueue { =20 /* * The request buffer must be able to hold a full write, and/or at lea= st - * FUSE_MIN_READ_BUFFER (from linux/fuse.h) bytes + * 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. + * 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). + */ + char request_buf[sizeof(struct fuse_in_header) + + sizeof(struct fuse_write_in) + + FUSE_IN_PLACE_WRITE_BYTES]; + + /* + * When retrieving a FUSE request, the destination buffer must always = be + * sufficiently large for the whole request, i.e. with max_write=3D64k= , we + * must provide a buffer that fits the WRITE header and 64 kB of space= for + * data. + * We do want to support 64k write requests without requiring them to = be + * split up, but at the same time, do not want to do such a large allo= cation + * for every single request. + * Therefore, the FuseRequest object provides an in-line buffer that is + * enough for write requests up to 4k (and all other requests), and for + * every request that is bigger, we provide a spill-over buffer here (= for + * the remaining 64k - 4k =3D 60k). + * When poll_fuse_fd() reads a FUSE request, it passes these buffers a= s an + * I/O vector, and then checks the return value (number of bytes read)= to + * find out whether the spill-over buffer was used. If so, it will mo= ve the + * buffer to the request, and will allocate a new spill-over buffer fo= r the + * next request. + * + * Free this buffer with qemu_vfree(). */ - char request_buf[MAX_CONST( - sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + - FUSE_MAX_WRITE_BYTES, - FUSE_MIN_READ_BUFFER - )]; + void *spillover_buf; } FuseQueue; =20 +/* + * Verify that FuseQueue.request_buf plus the spill-over buffer together + * are big enough to be accepted by the FUSE kernel driver. + */ +QEMU_BUILD_BUG_ON(sizeof(((FuseQueue *)0)->request_buf) + + FUSE_SPILLOVER_BUF_SIZE < + FUSE_MIN_READ_BUFFER); + struct FuseExport { BlockExport common; =20 @@ -132,7 +175,8 @@ static bool is_regular_file(const char *path, Error **e= rrp); =20 static bool poll_fuse_fd(void *opaque); static void read_fuse_fd(void *opaque); -static void coroutine_fn fuse_co_process_request(FuseQueue *q); +static void coroutine_fn +fuse_co_process_request(FuseQueue *q, void *spillover_buf); =20 static void fuse_inc_in_flight(FuseExport *exp) { @@ -494,6 +538,8 @@ static void coroutine_fn co_read_from_fuse_fd(void *opa= que) FuseExport *exp =3D q->exp; ssize_t ret; const struct fuse_in_header *in_hdr; + struct iovec iov[2]; + void *spillover_buf =3D NULL; =20 fuse_inc_in_flight(exp); =20 @@ -501,7 +547,20 @@ static void coroutine_fn co_read_from_fuse_fd(void *op= aque) goto no_request; } =20 - ret =3D RETRY_ON_EINTR(read(fuse_fd, q->request_buf, sizeof(q->request= _buf))); + /* + * If handling the last request consumed the spill-over buffer, alloca= te a + * new one. Align it to the block device's alignment, which admittedl= y is + * only useful if FUSE_IN_PLACE_WRITE_BYTES is aligned, too. + */ + if (unlikely(!q->spillover_buf)) { + q->spillover_buf =3D blk_blockalign(exp->common.blk, + FUSE_SPILLOVER_BUF_SIZE); + } + /* Construct the I/O vector to hold the FUSE request */ + iov[0] =3D (struct iovec) { q->request_buf, sizeof(q->request_buf) }; + iov[1] =3D (struct iovec) { q->spillover_buf, FUSE_SPILLOVER_BUF_SIZE = }; + + ret =3D RETRY_ON_EINTR(readv(fuse_fd, iov, ARRAY_SIZE(iov))); if (ret < 0 && errno =3D=3D EAGAIN) { /* No request available */ goto no_request; @@ -530,9 +589,15 @@ static void coroutine_fn co_read_from_fuse_fd(void *op= aque) goto no_request; } =20 + if (unlikely(ret > sizeof(q->request_buf))) { + /* Spillover buffer used, take ownership */ + spillover_buf =3D q->spillover_buf; + q->spillover_buf =3D NULL; + } + /* Must set this before yielding */ co_param->got_request =3D 1; - fuse_co_process_request(q); + fuse_co_process_request(q, spillover_buf); fuse_dec_in_flight(exp); return; =20 @@ -607,6 +672,9 @@ static void fuse_export_delete(BlockExport *blk_exp) if (i > 0 && q->fuse_fd >=3D 0) { close(q->fuse_fd); } + if (q->spillover_buf) { + qemu_vfree(q->spillover_buf); + } } g_free(exp->queues); =20 @@ -915,17 +983,25 @@ fuse_co_read(FuseExport *exp, void **bufptr, uint64_t= offset, uint32_t size) } =20 /** - * Handle client writes to the exported image. @buf has the data to be wr= itten - * and will be copied to a bounce buffer before yielding for the first tim= e. + * Handle client writes to the exported image. @in_place_buf has the first + * FUSE_IN_PLACE_WRITE_BYTES bytes of the data to be written, @spillover_b= uf + * contains the rest (if any; NULL otherwise). + * 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. * Return the number of bytes written to *out on success, and -errno on er= ror. */ static ssize_t coroutine_fn fuse_co_write(FuseExport *exp, struct fuse_write_out *out, - uint64_t offset, uint32_t size, const void *buf) + uint64_t offset, uint32_t size, + const void *in_place_buf, const void *spillover_buf) { + size_t in_place_size; void *copied; int64_t blk_len; int ret; + struct iovec iov[2]; + QEMUIOVector qiov; =20 /* Limited by max_write, should not happen */ if (size > BDRV_REQUEST_MAX_BYTES) { @@ -937,8 +1013,9 @@ fuse_co_write(FuseExport *exp, struct fuse_write_out *= out, } =20 /* Must copy to bounce buffer before potentially yielding */ - copied =3D blk_blockalign(exp->common.blk, size); - memcpy(copied, buf, size); + 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); =20 /** * Clients will expect short writes at EOF, so we have to limit @@ -962,7 +1039,21 @@ fuse_co_write(FuseExport *exp, struct fuse_write_out = *out, } } =20 - ret =3D blk_co_pwrite(exp->common.blk, offset, size, copied, 0); + 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, + }; + qemu_iovec_init_external(&qiov, iov, 2); + } else { + 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; } @@ -1321,8 +1412,14 @@ static int fuse_write_buf_response(int fd, uint32_t = req_id, * 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). */ -static void coroutine_fn fuse_co_process_request(FuseQueue *q) +static void coroutine_fn +fuse_co_process_request(FuseQueue *q, void *spillover_buf) { FuseExport *exp =3D q->exp; uint32_t opcode; @@ -1418,7 +1515,7 @@ static void coroutine_fn fuse_co_process_request(Fuse= Queue *q) * yielding. */ ret =3D fuse_co_write(exp, FUSE_OUT_OP_STRUCT(write, out_buf), - in->offset, in->size, in + 1); + in->offset, in->size, in + 1, spillover_buf); break; } =20 @@ -1460,6 +1557,8 @@ static void coroutine_fn fuse_co_process_request(Fuse= Queue *q) ret < 0 ? ret : 0, ret < 0 ? 0 : ret); } + + qemu_vfree(spillover_buf); } =20 const BlockExportDriver blk_exp_fuse =3D { --=20 2.48.1