{"id":2228976,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2228976/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-cifs-client/patch/20260427152953.180038-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":"<20260427152953.180038-2-dhowells@redhat.com>","date":"2026-04-27T15:29:28","name":"[v4,01/22] netfs: Fix cancellation of a DIO and single read subrequests","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"aef691ef154585af8d59d894b2ce4f225bc361ad","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/20260427152953.180038-2-dhowells@redhat.com/mbox/","series":[{"id":501677,"url":"http://patchwork.ozlabs.org/api/1.1/series/501677/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-cifs-client/list/?series=501677","date":"2026-04-27T15:29:27","name":"netfs: Miscellaneous fixes","version":4,"mbox":"http://patchwork.ozlabs.org/series/501677/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2228976/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2228976/checks/","tags":{},"headers":{"Return-Path":"\n <linux-cifs+bounces-11144-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=K4nBF6jr;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c09:e001:a7::12fc:5321; helo=sto.lore.kernel.org;\n envelope-from=linux-cifs+bounces-11144-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=\"K4nBF6jr\"","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\n [IPv6:2600:3c09:e001:a7::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g474z6DFLz1xvV\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 01:38:27 +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 D435F3062E3E\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 27 Apr 2026 15:33:34 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id E3D633DA7E7;\n\tMon, 27 Apr 2026 15:30:17 +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 1F5233D904F\n\tfor <linux-cifs@vger.kernel.org>; Mon, 27 Apr 2026 15:30:14 +0000 (UTC)","from mx-prod-mc-03.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-512-_v_s7o-ROVKIWTNtF46DGw-1; Mon,\n 27 Apr 2026 11:30:08 -0400","from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111])\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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 896451956065;\n\tMon, 27 Apr 2026 15:30:06 +0000 (UTC)","from warthog.procyon.org.com (unknown [10.44.32.126])\n\tby mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 3767B180047F;\n\tMon, 27 Apr 2026 15:30:02 +0000 (UTC)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777303817; cv=none;\n b=E3NP0XGtUHQPV2s01T2U/HebePrvDZi8jQKoNI2s6ZTL2u3E9rhXYA2bNYbXzxaOOwC8aJ5kF2w138/Vp8M0vYM6eYf3A/oNFQ2kmLG11HDgi94/9cmnDwMWkIvyoRKd8IU1UnCp2jTpcwJLv7TKKefmVPfV1QZ8CbI6ASmtiqI=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777303817; c=relaxed/simple;\n\tbh=MBV+gcvxIoEEQ+AAmirehOHfdTWrL3EvsI56zQBg4Ak=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=krC447C2kKET2TJZ60JsMAetgzVhneXBMnd7krTbjNwK4eukgjIQWn4lCOdhDHugPKvTr6IlmYJGNZ7ap4T8iUR+qcInoGfXwF/oxXdWojDGka+8LwUJduJk71tG/Mxrab7Cdd4N8Fy1leN1NtQrVWhnbgsPPrJ90v5zLVvjJAY=","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=K4nBF6jr; 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=1777303814;\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=u9RMsSgh/DXZPAvKktBs27mDcdJgglZsfz7/ceNESHA=;\n\tb=K4nBF6jrDIArwpSltYqkfwOCKjQ+eFvQ1iOZvdmefQ45cp4oJ8gLP6GHy2wyQb1jP/5hmQ\n\tN8pZ0FLJJwToAvbBDEAbT/cchraZrmQEKmwRNqi/qjnwSDZrNEwb+lk6mZDVjIwkxnFVdI\n\tHOfGXE8AovLzn0b6RHCRB+2RgJYOGQw=","X-MC-Unique":"_v_s7o-ROVKIWTNtF46DGw-1","X-Mimecast-MFC-AGG-ID":"_v_s7o-ROVKIWTNtF46DGw_1777303807","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 v4 01/22] netfs: Fix cancellation of a DIO and single read\n subrequests","Date":"Mon, 27 Apr 2026 16:29:28 +0100","Message-ID":"<20260427152953.180038-2-dhowells@redhat.com>","In-Reply-To":"<20260427152953.180038-1-dhowells@redhat.com>","References":"<20260427152953.180038-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.111"},"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 | 26 +++++++++++---------------\n fs/netfs/direct_read.c   | 19 ++++---------------\n fs/netfs/internal.h      |  2 ++\n fs/netfs/read_single.c   | 20 ++++++++------------\n 4 files changed, 25 insertions(+), 42 deletions(-)","diff":"diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c\nindex a8c0d86118c5..2c51c55a9b15 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@@ -262,11 +258,8 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq,\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\t__set_bit(NETFS_SREQ_FAILED, &subreq->flags);\n+\t\t\t\t\tnetfs_read_subreq_terminated(subreq);\n \t\t\t\t\tbreak;\n \t\t\t\t}\n \t\t\t\ttrace_netfs_sreq(subreq, netfs_sreq_trace_prepare);\n@@ -302,10 +295,13 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq,\n \t\t\tnetfs_put_subrequest(subreq, netfs_sreq_trace_put_cancel);\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..4fd5cfa690cf 100644\n--- a/fs/netfs/direct_read.c\n+++ b/fs/netfs/direct_read.c\n@@ -47,7 +47,6 @@ static void netfs_prepare_dio_read_iterator(struct netfs_io_subrequest *subreq)\n  */\n static int 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@@ -66,25 +65,15 @@ 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\t__set_bit(NETFS_SREQ_FAILED, &subreq->flags);\n+\t\t\t\tsubreq->error = ret;\n+\t\t\t\tnetfs_read_subreq_terminated(subreq);\n \t\t\t\tbreak;\n \t\t\t}\n \t\t}\ndiff --git a/fs/netfs/internal.h b/fs/netfs/internal.h\nindex d436e20d3418..24fefa1b179d 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);\ndiff --git a/fs/netfs/read_single.c b/fs/netfs/read_single.c\nindex d0e23bc42445..432c7456a1b6 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@@ -137,11 +133,11 @@ static int netfs_single_dispatch_read(struct netfs_io_request *rreq)\n \t\tbreak;\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+\t__set_bit(NETFS_SREQ_FAILED, &subreq->flags);\n+\tsubreq->error = ret;\n+\tnetfs_read_subreq_terminated(subreq);\n \treturn ret;\n }\n \n","prefixes":["v4","01/22"]}