From nobody Wed Apr 8 04:25:42 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=1773160190; cv=none; d=zohomail.com; s=zohoarc; b=OMQA3xZBUIlH7j0ED+LFgtigF7kK6kQ3JO01P3ZCC74ek0cLMOsnalfqsCw6udu7/GLXf/LFBb49aY64p+KFNI6WI1xRDB/FMcs+Y2lCDZf8B9VHuufVXWlI6br1EJJoe1qxcaxSLdVaGQ1fq8q6tNrgOJ1611ghadgkfNxe7M4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1773160190; 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=LB/woqVlxsVC7/O7ZXNLjER0uo2c8Oe6KZpAiLrH3DE=; b=GWCVJ9NbJaJxuvWv0R4PYKdyZeLH+bTEzugYrD69DRAqTQaLbPPu2GI8ua1EkC5xfFxkSwz9d+dLDMmkCvWs743B0LbxeJbvWPzqBdy6jnKlOrzISCQAe6FMxMYWcXYojBcmcQzooZMgKfNyzw/ujgOY62na31uOYPSIKsVoe24= 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 1773160190429978.5167614331153; Tue, 10 Mar 2026 09:29:50 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vzzvO-0003S9-Sz; Tue, 10 Mar 2026 12:27:15 -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 1vzzvH-0003PW-Fp for qemu-devel@nongnu.org; Tue, 10 Mar 2026 12:27:08 -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 1vzzvE-0000wH-VT for qemu-devel@nongnu.org; Tue, 10 Mar 2026 12:27:07 -0400 Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-68-76i2CL3_PfmVr6-IARLzwg-1; Tue, 10 Mar 2026 12:27:02 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 648AC18005B8; Tue, 10 Mar 2026 16:27:01 +0000 (UTC) Received: from merkur.fritz.box (unknown [10.45.224.112]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3FC4619560A6; Tue, 10 Mar 2026 16:27:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1773160023; 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=LB/woqVlxsVC7/O7ZXNLjER0uo2c8Oe6KZpAiLrH3DE=; b=QLaypyQR0uLEqh1He7/j/fu27TJWNikiXH9p9ZCus5ArKoNvJtcFCOWUkGFvISC5UiL65j DTASLMspCrS4sazwCu7wc9zc1bzv4E9yUZmWo2rNchgKAH20MOYp8C21p26b4w1HcUxvLr rkmsg4ZsFKTv0k8teOGQMOsUESYo3ZA= X-MC-Unique: 76i2CL3_PfmVr6-IARLzwg-1 X-Mimecast-MFC-AGG-ID: 76i2CL3_PfmVr6-IARLzwg_1773160021 From: Kevin Wolf To: qemu-block@nongnu.org Cc: kwolf@redhat.com, qemu-devel@nongnu.org Subject: [PULL 19/28] fuse: Process requests in coroutines Date: Tue, 10 Mar 2026 17:26:13 +0100 Message-ID: <20260310162622.333137-20-kwolf@redhat.com> In-Reply-To: <20260310162622.333137-1-kwolf@redhat.com> References: <20260310162622.333137-1-kwolf@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=kwolf@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: 1773160192708154100 From: Hanna Czenczek 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 Message-ID: <20260309150856.26800-20-hreitz@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- 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 f32e74f39dd..7c072409d83 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