From nobody Sat Apr 11 23:03:17 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1773069034; cv=none; d=zohomail.com; s=zohoarc; b=T8nidFCv8PqmshgqSU7+41iwWx+RFpdmJFIM1br0p3A4AIidQo0b3lh2Lq6mNz/D4UeC/vTVmuYzkMFO8t4ir6Lu7G/cNIvRyPr4IdVAzTjCldFkkQLIC48QOFti94GgIrtnPzX+CQmvlrEFs+Yr/bu62a4QWunDyvqYERblffc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1773069034; 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=bG2Vty+xjS126Z+XVEPqFO6PRk72dSZBpYi3U/L8/2g=; b=i2ga10poXJGIHge2dYvTIpfTdCEW2WKHdS6A+OWRXr3B+gJY8JTs/pr/24M3YRL1L673IyYH1Ri/oN2xChw+Rq0A73DQyN58Xb691HubhVC1PwPkSnMQEVOYlFvSV6pJaaTt7ov7Nwg6BmWC5PpzLgMXE0dlqJryWieJr2cxF2E= 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 1773069034921207.81970328597595; Mon, 9 Mar 2026 08:10:34 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vzcFB-0001Ou-4U; Mon, 09 Mar 2026 11:10:05 -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 1vzcF4-0001H7-T5 for qemu-devel@nongnu.org; Mon, 09 Mar 2026 11:09:59 -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 1vzcF2-0008Rq-8l for qemu-devel@nongnu.org; Mon, 09 Mar 2026 11:09:58 -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-296-O0HDllVuNe6BNFnztsldfQ-1; Mon, 09 Mar 2026 11:09:54 -0400 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-4853b5b0fafso12243035e9.3 for ; Mon, 09 Mar 2026 08:09:54 -0700 (PDT) Received: from localhost (p200300cfd737d0cf29d515fbd6051d53.dip0.t-ipconnect.de. [2003:cf:d737:d0cf:29d5:15fb:d605:1d53]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4853a946978sm112564855e9.1.2026.03.09.08.09.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Mar 2026 08:09:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1773068995; 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=bG2Vty+xjS126Z+XVEPqFO6PRk72dSZBpYi3U/L8/2g=; b=ASNMRl9i4coVWpmbsHnm5Ry9BWnOOJVvIJaRN+K8Dt+78rtdWRSkRWdDG3LPdF0s1XwZPX iZQQDUWzd2yvVPau/GIg4jvdssdcpPvWVFQALO7ICk7jh7SgSrBbXbEkeA5Tjo4agcP8Tc zZZNEgfW3QU89zuzQQ+Yggd5GNs8QK8= X-MC-Unique: O0HDllVuNe6BNFnztsldfQ-1 X-Mimecast-MFC-AGG-ID: O0HDllVuNe6BNFnztsldfQ_1773068993 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1773068992; x=1773673792; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=bG2Vty+xjS126Z+XVEPqFO6PRk72dSZBpYi3U/L8/2g=; b=A8ypyr58bygB8qbMbC+ANkxQR4+xHodkfXElhyPMTCWriejKBhipey4wTa93YWagSG hLoDVgXo7kpII4HP5Y9ctSttLMhu3xk4rnlEnJGZOvKJsLqOJMw3fLPxTKXiaKQgaJq+ jH+C/jxHVCg8wupCMEZOjZtRWJisyLLon09vNIBfUGTn5X45NQ1X0w9PMhi3am6mTKAA 673dY0GxcqZK/mh3fwE2KSgJVQtJeflV/mvVgNXEana2aPdBr/ugD8n3Ft+JdNHTKeQZ OtrwoYtSehnGBm2z6VjgpxOb4tepntZCKq+LNOCr/CWqNEJo65T+5pbQaD1aHg/sigdM PQFQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773068992; x=1773673792; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=bG2Vty+xjS126Z+XVEPqFO6PRk72dSZBpYi3U/L8/2g=; b=i6iYFAG3K6yyWevI7lEfdjX1Gk2j4kuGf+YNLdRT8pz/dJ02eFGL1TdaHAUmBBtQ3T 72ibgjFr5T6befa9KvhVx4c9VTCumlaPGjTzMO27m8zHOOiyjtPyNBC5+bDdMLJcAB3O D+2ATD69ybsfVlvkBPAsu6umtS0cEcDsIwDRxfuub70wTV4xkGCFJu11nD4Ejc69ixpN elB/VgH6/OXsm1chT5FYksHYAAwrlweWXvH3PHKKGaNJDSBu+we2mfK5Xpk2BWxZFPK9 Ij+b+BMMVoox4xKdr2UbP32EZS2g3qBqqfHyxxYKBsn8ZdqeucKydeD+tQQL9C+kGfer mvJw== X-Gm-Message-State: AOJu0Yw6LI0fjPykXwefAzLlnaeGvhxEi4R8ZPby1OSi1hjvFAX8CrnV arfLsJB7cPtqqaujrxPo6bMtw19sVO/Zp+Z5onQE4zK0urMmhdpQ5yXhgn9o7GbuJOWVP9boGdT zqXFx7hiYMYnMidrNEJN3vpWRFfwcStjod1AARaY0n9n//PUvi3Fmva9yuCM2P/H2 X-Gm-Gg: ATEYQzw6tgam/9gWstbSn1XrLd3Gpzkz20ws/TKfvdImFCStTP/nA2sdefcN3jiaIMI sL71MuWF2xFWhd9D34WxxiQRFx9vaIqexh00KvBElwxvv0viqVa2va8MFN8EBh69Sb7vMcGTCcn x1R7KZ36Ftvk+UXdpMMCZJ2bvmn37N7C4/B3Q0kBn8HjWjvrolmb6mTtHOZbsFhG+nbZenuSZ3I FdjdUtYndpd0gyoN4UgBMHdftu2YVRjqBVXCGaYoqRYThXbOmyQh2Q2qM5c6DRObjEHtwgBEHR/ KXFtkxTF7q24FuubSTpj0Zh3KO4GTPSR6a7Tii0LC5JsYiDeOlnXg1UeiPSFC/uMizxkdnP41Zi 9SNZpvqUOdplM3rSUZYchBedOF+wVTzYJDKzowrydmDBcJUNamptp+3v1tZZbljg7hO2dlf7ax9 J1zFxc X-Received: by 2002:a05:600c:4447:b0:485:34b3:8585 with SMTP id 5b1f17b1804b1-48534b38936mr100401765e9.8.1773068992090; Mon, 09 Mar 2026 08:09:52 -0700 (PDT) X-Received: by 2002:a05:600c:4447:b0:485:34b3:8585 with SMTP id 5b1f17b1804b1-48534b38936mr100401115e9.8.1773068991503; Mon, 09 Mar 2026 08:09:51 -0700 (PDT) From: Hanna Czenczek To: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org, Hanna Czenczek , Kevin Wolf , Brian Song Subject: [PATCH v5 19/25] fuse: Process requests in coroutines Date: Mon, 9 Mar 2026 16:08:50 +0100 Message-ID: <20260309150856.26800-20-hreitz@redhat.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260309150856.26800-1-hreitz@redhat.com> References: <20260309150856.26800-1-hreitz@redhat.com> MIME-Version: 1.0 Content-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: -3 X-Spam_score: -0.4 X-Spam_bar: / X-Spam_report: (-0.4 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.819, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.903, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1773069037510154100 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: 97.8k =C2=B11.5k (-2% / -8%) rand aio: 95.8k =C2=B13.4k (+90% / +98%) seq sync: 34.5k =C2=B11.0k (-4% / -3%) rand sync: 9.9k =C2=B10.1k (-1% / -1%) write: seq aio: 68.7k =C2=B11.3k (-5% / -10%) rand aio: 68.9k =C2=B11.1k (-2% / -10%) seq sync: 30.6k =C2=B10.9k (=C2=B10% / -3%) rand sync: 30.6k =C2=B10.6k (+1% / -1%) null: read: seq aio: 174.5k =C2=B16.8k (+11% / +8%) rand aio: 170.9k =C2=B15.7k (+8% / +3%) seq sync: 82.0k =C2=B13.3k (+2% / +2%) rand sync: 78.0k =C2=B14.0k (+1% / -1%) write: seq aio: 196.0k =C2=B12.8k (+27% / +6%) rand aio: 191.2k =C2=B17.9k (+24% / +2%) seq sync: 83.3k =C2=B14.4k (+9% / +1%) rand sync: 79.5k =C2=B14.4k (+9% / +1%) So there is not much difference, especially when compared to how it was with libfuse, except for the randread AIO case with an actual file. That improves greatly. Signed-off-by: Hanna Czenczek --- block/export/fuse.c | 176 ++++++++++++++++++++++++++------------------ 1 file changed, 104 insertions(+), 72 deletions(-) diff --git a/block/export/fuse.c b/block/export/fuse.c index f32e74f39d..7c072409d8 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" @@ -181,9 +182,9 @@ static int mount_fuse_export(FuseExport *exp, Error **e= rrp); static bool is_regular_file(const char *path, Error **errp); =20 static void read_from_fuse_fd(void *opaque); -static void fuse_process_request(FuseExport *exp, - const FuseRequestInHeader *in_hdr, - const void *data_buffer); +static void coroutine_fn +fuse_co_process_request(FuseExport *exp, const FuseRequestInHeader *in_hdr, + const void *data_buffer); static int fuse_write_err(int fd, const struct fuse_in_header *in_hdr, int= err); =20 static void fuse_inc_in_flight(FuseExport *exp) @@ -518,9 +519,14 @@ static ssize_t req_op_hdr_len(const FuseRequestInHeade= r *in_hdr) } =20 /** - * Try to read and process a single request from the FUSE FD. + * Try to read a single request from the FUSE FD. + * Takes a FuseExport pointer in `opaque`. + * + * Assumes the export's in-flight counter has already been incremented. + * + * If a request is available, process it. */ -static void read_from_fuse_fd(void *opaque) +static void coroutine_fn co_read_from_fuse_fd(void *opaque) { FuseExport *exp =3D opaque; int fuse_fd =3D exp->fuse_fd; @@ -531,8 +537,6 @@ static void read_from_fuse_fd(void *opaque) struct iovec iov[2]; ssize_t op_hdr_len; =20 - fuse_inc_in_flight(exp); - if (unlikely(qatomic_read(&exp->halted))) { goto no_request; } @@ -601,13 +605,29 @@ static void read_from_fuse_fd(void *opaque) release_write_data_buffer(exp, &data_buffer); } =20 - fuse_process_request(exp, in_hdr, data_buffer); + fuse_co_process_request(exp, in_hdr, data_buffer); =20 no_request: release_write_data_buffer(exp, &data_buffer); fuse_dec_in_flight(exp); } =20 +/** + * Try to read and process a single request from the FUSE FD. + * (To be used as a handler for when the FUSE FD becomes readable.) + * Takes a FuseExport pointer in `opaque`. + */ +static void read_from_fuse_fd(void *opaque) +{ + FuseExport *exp =3D opaque; + Coroutine *co; + + co =3D qemu_coroutine_create(co_read_from_fuse_fd, exp); + /* Decremented by co_read_from_fuse_fd() */ + fuse_inc_in_flight(exp); + qemu_coroutine_enter(co); +} + static void fuse_export_shutdown(BlockExport *blk_exp) { FuseExport *exp =3D container_of(blk_exp, FuseExport, common); @@ -682,8 +702,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, - const struct fuse_init_in_compat *in) +static ssize_t coroutine_fn GRAPH_RDLOCK +fuse_co_init(FuseExport *exp, struct fuse_init_out *out, + const struct fuse_init_in_compat *in) { const uint32_t supported_flags =3D FUSE_ASYNC_READ | FUSE_ASYNC_DIO; =20 @@ -738,7 +759,8 @@ static ssize_t fuse_init(FuseExport *exp, struct fuse_i= nit_out *out, /** * Return some filesystem information, just to not break e.g. `df`. */ -static ssize_t fuse_statfs(FuseExport *exp, struct fuse_statfs_out *out) +static ssize_t coroutine_fn GRAPH_RDLOCK +fuse_co_statfs(FuseExport *exp, struct fuse_statfs_out *out) { BlockDriverState *root_bs; uint32_t opt_transfer =3D 512; @@ -766,17 +788,18 @@ static ssize_t fuse_statfs(FuseExport *exp, struct fu= se_statfs_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 GRAPH_RDLOCK +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 { @@ -803,8 +826,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 GRAPH_RDLOCK +fuse_co_do_truncate(const FuseExport *exp, int64_t size, bool req_zero_wri= te, + PreallocMode prealloc) { BdrvRequestFlags truncate_flags =3D 0; =20 @@ -812,8 +836,8 @@ static int fuse_do_truncate(const FuseExport *exp, int6= 4_t size, truncate_flags |=3D BDRV_REQ_ZERO_WRITE; } =20 - return blk_truncate(exp->common.blk, size, true, prealloc, - truncate_flags, NULL); + return blk_co_truncate(exp->common.blk, size, true, prealloc, + truncate_flags, NULL); } =20 /** @@ -825,9 +849,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 GRAPH_RDLOCK +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; @@ -864,7 +888,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; } @@ -883,7 +907,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 /** @@ -891,7 +915,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 GRAPH_RDLOCK +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, @@ -906,8 +931,8 @@ static ssize_t fuse_open(FuseExport *exp, struct fuse_o= pen_out *out) * Note: If the returned size is 0, *bufptr will be set to NULL. * After use, *bufptr must be freed via qemu_vfree(). */ -static ssize_t fuse_read(FuseExport *exp, void **bufptr, - uint64_t offset, uint32_t size) +static ssize_t coroutine_fn GRAPH_RDLOCK +fuse_co_read(FuseExport *exp, void **bufptr, uint64_t offset, uint32_t siz= e) { int64_t blk_len; void *buf; @@ -922,7 +947,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; } @@ -942,7 +967,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; @@ -956,8 +981,9 @@ static ssize_t fuse_read(FuseExport *exp, void **bufptr, * Handle client writes to the exported image. @buf has the data to be wr= itten. * 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 GRAPH_RDLOCK +fuse_co_write(FuseExport *exp, struct fuse_write_out *out, + uint64_t offset, uint32_t size, const void *buf) { int64_t blk_len; int ret; @@ -976,7 +1002,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) { return blk_len; } @@ -992,7 +1018,8 @@ static ssize_t fuse_write(FuseExport *exp, struct fuse= _write_out *out, return -EINVAL; } else 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) { return ret; } @@ -1001,7 +1028,7 @@ static ssize_t fuse_write(FuseExport *exp, struct fus= e_write_out *out, } } =20 - ret =3D blk_pwrite(exp->common.blk, offset, size, buf, 0); + ret =3D blk_co_pwrite(exp->common.blk, offset, size, buf, 0); if (ret < 0) { return ret; } @@ -1016,8 +1043,9 @@ static ssize_t fuse_write(FuseExport *exp, struct fus= e_write_out *out, * 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 GRAPH_RDLOCK +fuse_co_fallocate(FuseExport *exp, + uint64_t offset, uint64_t length, uint32_t mode) { int64_t blk_len; int ret; @@ -1026,7 +1054,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; } @@ -1045,14 +1073,14 @@ static ssize_t fuse_fallocate(FuseExport *exp, uint= 64_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) { @@ -1063,8 +1091,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 @@ -1082,8 +1111,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; } @@ -1092,8 +1121,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); @@ -1110,9 +1139,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 GRAPH_RDLOCK fuse_co_fsync(FuseExport *exp) { - return blk_flush(exp->common.blk); + return blk_co_flush(exp->common.blk); } =20 /** @@ -1120,9 +1149,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 GRAPH_RDLOCK fuse_co_flush(FuseExport *exp) { - return blk_flush(exp->common.blk); + return blk_co_flush(exp->common.blk); } =20 #ifdef CONFIG_FUSE_LSEEK @@ -1130,8 +1159,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 GRAPH_RDLOCK +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; @@ -1141,8 +1171,8 @@ static ssize_t fuse_lseek(FuseExport *exp, struct fus= e_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; } @@ -1159,7 +1189,7 @@ static ssize_t fuse_lseek(FuseExport *exp, struct fus= e_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; } @@ -1303,18 +1333,20 @@ static int fuse_write_buf_response(int fd, /** * Process a FUSE request, incl. writing the response. */ -static void fuse_process_request(FuseExport *exp, - const FuseRequestInHeader *in_hdr, - const void *data_buffer) +static void coroutine_fn +fuse_co_process_request(FuseExport *exp, const FuseRequestInHeader *in_hdr, + const void *data_buffer) { FuseRequestOutHeader out_hdr; /* For read requests: Data to be returned */ void *out_data_buffer =3D NULL; ssize_t ret; =20 + GRAPH_RDLOCK_GUARD(); + switch (in_hdr->common.opcode) { case FUSE_INIT: - ret =3D fuse_init(exp, &out_hdr.init, &in_hdr->init); + ret =3D fuse_co_init(exp, &out_hdr.init, &in_hdr->init); break; =20 case FUSE_DESTROY: @@ -1322,11 +1354,11 @@ static void fuse_process_request(FuseExport *exp, break; =20 case FUSE_STATFS: - ret =3D fuse_statfs(exp, &out_hdr.statfs); + ret =3D fuse_co_statfs(exp, &out_hdr.statfs); break; =20 case FUSE_OPEN: - ret =3D fuse_open(exp, &out_hdr.open); + ret =3D fuse_co_open(exp, &out_hdr.open); break; =20 case FUSE_RELEASE: @@ -1343,19 +1375,19 @@ static void fuse_process_request(FuseExport *exp, return; =20 case FUSE_GETATTR: - ret =3D fuse_getattr(exp, &out_hdr.attr); + ret =3D fuse_co_getattr(exp, &out_hdr.attr); break; =20 case FUSE_SETATTR: { const struct fuse_setattr_in *in =3D &in_hdr->setattr; - ret =3D fuse_setattr(exp, &out_hdr.attr, - in->valid, in->size, in->mode, in->uid, in->gid= ); + ret =3D fuse_co_setattr(exp, &out_hdr.attr, + in->valid, in->size, in->mode, in->uid, in->= gid); break; } =20 case FUSE_READ: { const struct fuse_read_in *in =3D &in_hdr->read; - 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 @@ -1373,36 +1405,36 @@ static void fuse_process_request(FuseExport *exp, } =20 /* - * read_from_fuse_fd() has checked that in_hdr->len matches the nu= mber - * of bytes read, which cannot exceed the max_write value we set + * co_read_from_fuse_fd() has checked that in_hdr->len matches the + * number of bytes read, which cannot exceed the max_write value w= e 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); =20 - ret =3D fuse_write(exp, &out_hdr.write, - in->offset, in->size, data_buffer); + ret =3D fuse_co_write(exp, &out_hdr.write, + in->offset, in->size, data_buffer); break; } =20 case FUSE_FALLOCATE: { const struct fuse_fallocate_in *in =3D &in_hdr->fallocate; - 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 &in_hdr->lseek; - ret =3D fuse_lseek(exp, &out_hdr.lseek, in->offset, in->whence); + ret =3D fuse_co_lseek(exp, &out_hdr.lseek, in->offset, in->whence); break; } #endif --=20 2.53.0