{"id":2229575,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2229575/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-cifs-client/patch/20260428131756.922303-2-dhowells@redhat.com/","project":{"id":12,"url":"http://patchwork.ozlabs.org/api/1.1/projects/12/?format=json","name":"Linux CIFS Client","link_name":"linux-cifs-client","list_id":"linux-cifs.vger.kernel.org","list_email":"linux-cifs@vger.kernel.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260428131756.922303-2-dhowells@redhat.com>","date":"2026-04-28T13:17:31","name":"[v5,01/24] netfs: Fix cancellation of a DIO and single read subrequests","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"6c3964026dcaccc1b7d12b4efb071fb693383aba","submitter":{"id":59,"url":"http://patchwork.ozlabs.org/api/1.1/people/59/?format=json","name":"David Howells","email":"dhowells@redhat.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-cifs-client/patch/20260428131756.922303-2-dhowells@redhat.com/mbox/","series":[{"id":501852,"url":"http://patchwork.ozlabs.org/api/1.1/series/501852/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-cifs-client/list/?series=501852","date":"2026-04-28T13:17:35","name":"netfs: Miscellaneous fixes","version":5,"mbox":"http://patchwork.ozlabs.org/series/501852/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2229575/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2229575/checks/","tags":{},"headers":{"Return-Path":"\n <linux-cifs+bounces-11191-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-cifs@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=W+s95epj;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=172.232.135.74; helo=sto.lore.kernel.org;\n envelope-from=linux-cifs+bounces-11191-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com\n header.b=\"W+s95epj\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=170.10.133.124","smtp.subspace.kernel.org;\n dmarc=pass (p=quarantine dis=none) header.from=redhat.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=redhat.com"],"Received":["from sto.lore.kernel.org (sto.lore.kernel.org [172.232.135.74])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g4hQZ5hsRz1yHv\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 23:40:38 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sto.lore.kernel.org (Postfix) with ESMTP id 09EDA3147174\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 13:25:15 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id C91C045BD7A;\n\tTue, 28 Apr 2026 13:18:51 +0000 (UTC)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 99E83451062\n\tfor <linux-cifs@vger.kernel.org>; Tue, 28 Apr 2026 13:18:49 +0000 (UTC)","from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-122-4-4frwHBOLyANWMlho6SWw-1; Tue,\n 28 Apr 2026 09:18:40 -0400","from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n\t(No client certificate requested)\n\tby mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 8774E191FE8F;\n\tTue, 28 Apr 2026 13:18:07 +0000 (UTC)","from warthog.procyon.org.com (unknown [10.44.32.126])\n\tby mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 81D681800348;\n\tTue, 28 Apr 2026 13:18:04 +0000 (UTC)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777382331; cv=none;\n b=LkJjYW7k8rYHixmzaqtTd1WN/Ze6qx9Xa3yB8U/ChrNKs22b/8psOnICUC6fYfdHhVPWpiEGYyEhtN3+kgocnDYz3q0xn90HEfRHJRyGXN1XWqb3A6tVY3M1n1QP+EL6IVHzbL7t/2pJ8rsq7aBxFGmsJqRWcEoN/W/tqeG+YZk=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777382331; c=relaxed/simple;\n\tbh=PCEywMo+0ucWp3/WX+0dExm5VhO3M/QAe8pTFnnhHEE=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=Qzay3722r9gpMRuz9Owe876ShJo1v3Tk9wgA4KAQZKKMACpE09/mrMo33QpTqpIZkIpUfqDVReMqVW81QpT0PRgwzXJ5oNBnLeHlrv81ZJi91saloWPDEAa4R4b+b/Qfa0St56s+TXIReb1fKkNWAgt2lXG269sAi7pKpZm7bXM=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=quarantine dis=none) header.from=redhat.com;\n spf=pass smtp.mailfrom=redhat.com;\n dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com\n header.b=W+s95epj; arc=none smtp.client-ip=170.10.133.124","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1777382328;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\t to:to:cc:cc:mime-version:mime-version:\n\t content-transfer-encoding:content-transfer-encoding:\n\t in-reply-to:in-reply-to:references:references;\n\tbh=Uhi8kKMsF6kc+1iDdDV2ShwjmP4JKPaFHP00k+w/m/Q=;\n\tb=W+s95epjgywIAx5A4VWC3gg3KX6tYRSd2+WP7LPZdyijD+JcT4dc+6jqvo5kKzkBAlFJ4w\n\tEi2A4gsls6vfshiforl1ByyuDL7utLgei2O5Q05g7kvDJpKetxCb2iTB6hvWMKbu3CP9iy\n\ttrV9Iuo6hN3nZY71XUrFiHJM4mz9IlU=","X-MC-Unique":"4-4frwHBOLyANWMlho6SWw-1","X-Mimecast-MFC-AGG-ID":"4-4frwHBOLyANWMlho6SWw_1777382319","From":"David Howells <dhowells@redhat.com>","To":"Christian Brauner <christian@brauner.io>","Cc":"David Howells <dhowells@redhat.com>,\n\tPaulo Alcantara <pc@manguebit.org>,\n\tnetfs@lists.linux.dev,\n\tlinux-afs@lists.infradead.org,\n\tlinux-cifs@vger.kernel.org,\n\tceph-devel@vger.kernel.org,\n\tlinux-fsdevel@vger.kernel.org,\n\tlinux-kernel@vger.kernel.org","Subject":"[PATCH v5 01/24] netfs: Fix cancellation of a DIO and single read\n subrequests","Date":"Tue, 28 Apr 2026 14:17:31 +0100","Message-ID":"<20260428131756.922303-2-dhowells@redhat.com>","In-Reply-To":"<20260428131756.922303-1-dhowells@redhat.com>","References":"<20260428131756.922303-1-dhowells@redhat.com>","Precedence":"bulk","X-Mailing-List":"linux-cifs@vger.kernel.org","List-Id":"<linux-cifs.vger.kernel.org>","List-Subscribe":"<mailto:linux-cifs+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-cifs+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-Scanned-By":"MIMEDefang 3.4.1 on 10.30.177.93"},"content":"When the preparation of a new subrequest for a read fails, if the\nsubrequest has already been added to the stream->subrequests list, it can't\nsimply be put and abandoned as the collector may see it.  Also, if it\nhasn't been queued yet, it has two outstanding refs that both need to be\nput.  Both DIO read and single-read dispatch fail at this; further, both\ndiffer in the order they do things to the way buffered read works.\n\nFix cancellation of both DIO-read and single-read subrequests that failed\npreparation by the following steps:\n\n (1) Harmonise all three reads (buffered, dio, single) to queue the subreq\n     before prepping it.\n\n (2) Make all three call netfs_queue_read() to do the queuing.\n\n (3) Set NETFS_RREQ_ALL_QUEUED independently of the queuing as we don't\n     know the length of the subreq at this point.\n\n (4) In all cases, set the error and NETFS_SREQ_FAILED flag on the subreq\n     and then call netfs_read_subreq_terminated() to deal with it.  This\n     will pass responsibility off to the collector for dealing with it.\n\nFixes: e2d46f2ec332 (\"netfs: Change the read result collector to only use one work item\")\nCloses: https://sashiko.dev/#/patchset/20260425125426.3855807-1-dhowells%40redhat.com\nSigned-off-by: David Howells <dhowells@redhat.com>\ncc: Paulo Alcantara <pc@manguebit.org>\ncc: netfs@lists.linux.dev\ncc: linux-fsdevel@vger.kernel.org\n---\n fs/netfs/buffered_read.c | 33 ++++++++++++-------------------\n fs/netfs/direct_read.c   | 42 +++++++++++++---------------------------\n fs/netfs/internal.h      |  3 +++\n fs/netfs/read_collect.c  | 11 +++++++++++\n fs/netfs/read_single.c   | 23 ++++++++++------------\n 5 files changed, 49 insertions(+), 63 deletions(-)","diff":"diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c\nindex a8c0d86118c5..286c93fc681e 100644\n--- a/fs/netfs/buffered_read.c\n+++ b/fs/netfs/buffered_read.c\n@@ -156,9 +156,8 @@ static void netfs_read_cache_to_pagecache(struct netfs_io_request *rreq,\n \t\t\tnetfs_cache_read_terminated, subreq);\n }\n \n-static void netfs_queue_read(struct netfs_io_request *rreq,\n-\t\t\t     struct netfs_io_subrequest *subreq,\n-\t\t\t     bool last_subreq)\n+void netfs_queue_read(struct netfs_io_request *rreq,\n+\t\t      struct netfs_io_subrequest *subreq)\n {\n \tstruct netfs_io_stream *stream = &rreq->io_streams[0];\n \n@@ -178,11 +177,6 @@ static void netfs_queue_read(struct netfs_io_request *rreq,\n \t\t}\n \t}\n \n-\tif (last_subreq) {\n-\t\tsmp_wmb(); /* Write lists before ALL_QUEUED. */\n-\t\tset_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags);\n-\t}\n-\n \tspin_unlock(&rreq->lock);\n }\n \n@@ -233,6 +227,8 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq,\n \t\tsubreq->start\t= start;\n \t\tsubreq->len\t= size;\n \n+\t\tnetfs_queue_read(rreq, subreq);\n+\n \t\tsource = netfs_cache_prepare_read(rreq, subreq, rreq->i_size);\n \t\tsubreq->source = source;\n \t\tif (source == NETFS_DOWNLOAD_FROM_SERVER) {\n@@ -253,6 +249,7 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq,\n \t\t\t\t       rreq->debug_id, subreq->debug_index,\n \t\t\t\t       subreq->len, size,\n \t\t\t\t       subreq->start, ictx->zero_point, rreq->i_size);\n+\t\t\t\tnetfs_cancel_read(subreq, ret);\n \t\t\t\tbreak;\n \t\t\t}\n \t\t\tsubreq->len = len;\n@@ -261,12 +258,7 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq,\n \t\t\tif (rreq->netfs_ops->prepare_read) {\n \t\t\t\tret = rreq->netfs_ops->prepare_read(subreq);\n \t\t\t\tif (ret < 0) {\n-\t\t\t\t\tsubreq->error = ret;\n-\t\t\t\t\t/* Not queued - release both refs. */\n-\t\t\t\t\tnetfs_put_subrequest(subreq,\n-\t\t\t\t\t\t\t     netfs_sreq_trace_put_cancel);\n-\t\t\t\t\tnetfs_put_subrequest(subreq,\n-\t\t\t\t\t\t\t     netfs_sreq_trace_put_cancel);\n+\t\t\t\t\tnetfs_cancel_read(subreq, ret);\n \t\t\t\t\tbreak;\n \t\t\t\t}\n \t\t\t\ttrace_netfs_sreq(subreq, netfs_sreq_trace_prepare);\n@@ -295,17 +287,16 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq,\n \t\tslice = netfs_prepare_read_iterator(subreq, ractl);\n \t\tif (slice < 0) {\n \t\t\tret = slice;\n-\t\t\tsubreq->error = ret;\n-\t\t\ttrace_netfs_sreq(subreq, netfs_sreq_trace_cancel);\n-\t\t\t/* Not queued - release both refs. */\n-\t\t\tnetfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel);\n-\t\t\tnetfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel);\n+\t\t\tnetfs_cancel_read(subreq, ret);\n \t\t\tbreak;\n \t\t}\n-\t\tsize -= slice;\n \t\tstart += slice;\n+\t\tsize -= slice;\n+\t\tif (size <= 0) {\n+\t\t\tsmp_wmb(); /* Write lists before ALL_QUEUED. */\n+\t\t\tset_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags);\n+\t\t}\n \n-\t\tnetfs_queue_read(rreq, subreq, size <= 0);\n \t\tnetfs_issue_read(rreq, subreq);\n \t\tcond_resched();\n \t} while (size > 0);\ndiff --git a/fs/netfs/direct_read.c b/fs/netfs/direct_read.c\nindex f72e6da88cca..6a8fb0d55e04 100644\n--- a/fs/netfs/direct_read.c\n+++ b/fs/netfs/direct_read.c\n@@ -45,12 +45,11 @@ static void netfs_prepare_dio_read_iterator(struct netfs_io_subrequest *subreq)\n  * Perform a read to a buffer from the server, slicing up the region to be read\n  * according to the network rsize.\n  */\n-static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq)\n+static void netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq)\n {\n-\tstruct netfs_io_stream *stream = &rreq->io_streams[0];\n \tunsigned long long start = rreq->start;\n \tssize_t size = rreq->len;\n-\tint ret = 0;\n+\tint ret;\n \n \tdo {\n \t\tstruct netfs_io_subrequest *subreq;\n@@ -58,7 +57,10 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq)\n \n \t\tsubreq = netfs_alloc_subrequest(rreq);\n \t\tif (!subreq) {\n-\t\t\tret = -ENOMEM;\n+\t\t\t/* Stash the error in the request if there's not\n+\t\t\t * already an error set.\n+\t\t\t */\n+\t\t\tcmpxchg(&rreq->error, 0, -ENOMEM);\n \t\t\tbreak;\n \t\t}\n \n@@ -66,25 +68,13 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq)\n \t\tsubreq->start\t= start;\n \t\tsubreq->len\t= size;\n \n-\t\t__set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags);\n-\n-\t\tspin_lock(&rreq->lock);\n-\t\tlist_add_tail(&subreq->rreq_link, &stream->subrequests);\n-\t\tif (list_is_first(&subreq->rreq_link, &stream->subrequests)) {\n-\t\t\tif (!stream->active) {\n-\t\t\t\tstream->collected_to = subreq->start;\n-\t\t\t\t/* Store list pointers before active flag */\n-\t\t\t\tsmp_store_release(&stream->active, true);\n-\t\t\t}\n-\t\t}\n-\t\ttrace_netfs_sreq(subreq, netfs_sreq_trace_added);\n-\t\tspin_unlock(&rreq->lock);\n+\t\tnetfs_queue_read(rreq, subreq);\n \n \t\tnetfs_stat(&netfs_n_rh_download);\n \t\tif (rreq->netfs_ops->prepare_read) {\n \t\t\tret = rreq->netfs_ops->prepare_read(subreq);\n \t\t\tif (ret < 0) {\n-\t\t\t\tnetfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel);\n+\t\t\t\tnetfs_cancel_read(subreq, ret);\n \t\t\t\tbreak;\n \t\t\t}\n \t\t}\n@@ -113,8 +103,6 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq)\n \t\tset_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags);\n \t\tnetfs_wake_collector(rreq);\n \t}\n-\n-\treturn ret;\n }\n \n /*\n@@ -137,21 +125,17 @@ static ssize_t netfs_unbuffered_read(struct netfs_io_request *rreq, bool sync)\n \t// TODO: Use bounce buffer if requested\n \n \tinode_dio_begin(rreq->inode);\n+\tnetfs_dispatch_unbuffered_reads(rreq);\n \n-\tret = netfs_dispatch_unbuffered_reads(rreq);\n-\n-\tif (!rreq->submitted) {\n-\t\tnetfs_put_request(rreq, netfs_rreq_trace_put_no_submit);\n-\t\tinode_dio_end(rreq->inode);\n-\t\tret = 0;\n-\t\tgoto out;\n-\t}\n+\t/* The collector will get run, even if we don't manage to submit any\n+\t * subreqs, so we shouldn't call inode_dio_end() here.\n+\t */\n \n \tif (sync)\n \t\tret = netfs_wait_for_read(rreq);\n \telse\n \t\tret = -EIOCBQUEUED;\n-out:\n+\n \t_leave(\" = %zd\", ret);\n \treturn ret;\n }\ndiff --git a/fs/netfs/internal.h b/fs/netfs/internal.h\nindex d436e20d3418..645996ecfc80 100644\n--- a/fs/netfs/internal.h\n+++ b/fs/netfs/internal.h\n@@ -23,6 +23,8 @@\n /*\n  * buffered_read.c\n  */\n+void netfs_queue_read(struct netfs_io_request *rreq,\n+\t\t      struct netfs_io_subrequest *subreq);\n void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error);\n int netfs_prefetch_for_write(struct file *file, struct folio *folio,\n \t\t\t     size_t offset, size_t len);\n@@ -108,6 +110,7 @@ static inline void netfs_see_subrequest(struct netfs_io_subrequest *subreq,\n  */\n bool netfs_read_collection(struct netfs_io_request *rreq);\n void netfs_read_collection_worker(struct work_struct *work);\n+void netfs_cancel_read(struct netfs_io_subrequest *subreq, int error);\n void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error);\n \n /*\ndiff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c\nindex e5f6665b3341..d2d902f46627 100644\n--- a/fs/netfs/read_collect.c\n+++ b/fs/netfs/read_collect.c\n@@ -575,6 +575,17 @@ void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq)\n }\n EXPORT_SYMBOL(netfs_read_subreq_terminated);\n \n+/*\n+ * Cancel a read subrequest due to preparation failure.\n+ */\n+void netfs_cancel_read(struct netfs_io_subrequest *subreq, int error)\n+{\n+\ttrace_netfs_sreq(subreq, netfs_sreq_trace_cancel);\n+\tsubreq->error = error;\n+\t__set_bit(NETFS_SREQ_FAILED, &subreq->flags);\n+\tnetfs_read_subreq_terminated(subreq);\n+}\n+\n /*\n  * Handle termination of a read from the cache.\n  */\ndiff --git a/fs/netfs/read_single.c b/fs/netfs/read_single.c\nindex d0e23bc42445..8833550d2eb6 100644\n--- a/fs/netfs/read_single.c\n+++ b/fs/netfs/read_single.c\n@@ -89,7 +89,6 @@ static void netfs_single_read_cache(struct netfs_io_request *rreq,\n  */\n static int netfs_single_dispatch_read(struct netfs_io_request *rreq)\n {\n-\tstruct netfs_io_stream *stream = &rreq->io_streams[0];\n \tstruct netfs_io_subrequest *subreq;\n \tint ret = 0;\n \n@@ -102,14 +101,7 @@ static int netfs_single_dispatch_read(struct netfs_io_request *rreq)\n \tsubreq->len\t= rreq->len;\n \tsubreq->io_iter\t= rreq->buffer.iter;\n \n-\t__set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags);\n-\n-\tspin_lock(&rreq->lock);\n-\tlist_add_tail(&subreq->rreq_link, &stream->subrequests);\n-\ttrace_netfs_sreq(subreq, netfs_sreq_trace_added);\n-\t/* Store list pointers before active flag */\n-\tsmp_store_release(&stream->active, true);\n-\tspin_unlock(&rreq->lock);\n+\tnetfs_queue_read(rreq, subreq);\n \n \tnetfs_single_cache_prepare_read(rreq, subreq);\n \tswitch (subreq->source) {\n@@ -121,10 +113,14 @@ static int netfs_single_dispatch_read(struct netfs_io_request *rreq)\n \t\t\t\tgoto cancel;\n \t\t}\n \n+\t\tsmp_wmb(); /* Write lists before ALL_QUEUED. */\n+\t\tset_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags);\n \t\trreq->netfs_ops->issue_read(subreq);\n \t\trreq->submitted += subreq->len;\n \t\tbreak;\n \tcase NETFS_READ_FROM_CACHE:\n+\t\tsmp_wmb(); /* Write lists before ALL_QUEUED. */\n+\t\tset_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags);\n \t\ttrace_netfs_sreq(subreq, netfs_sreq_trace_submit);\n \t\tnetfs_single_read_cache(rreq, subreq);\n \t\trreq->submitted += subreq->len;\n@@ -134,14 +130,15 @@ static int netfs_single_dispatch_read(struct netfs_io_request *rreq)\n \t\tpr_warn(\"Unexpected single-read source %u\\n\", subreq->source);\n \t\tWARN_ON_ONCE(true);\n \t\tret = -EIO;\n-\t\tbreak;\n+\t\tgoto cancel;\n \t}\n \n-\tsmp_wmb(); /* Write lists before ALL_QUEUED. */\n-\tset_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags);\n \treturn ret;\n cancel:\n-\tnetfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel);\n+\tnetfs_cancel_read(subreq, ret);\n+\tsmp_wmb(); /* Write lists before ALL_QUEUED. */\n+\tset_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags);\n+\tnetfs_wake_collector(rreq);\n \treturn ret;\n }\n \n","prefixes":["v5","01/24"]}