{"id":2222591,"url":"http://patchwork.ozlabs.org/api/1.2/patches/2222591/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-ext4/patch/20260413062500.1380307-2-diangangli@gmail.com/","project":{"id":8,"url":"http://patchwork.ozlabs.org/api/1.2/projects/8/?format=json","name":"Linux ext4 filesystem development","link_name":"linux-ext4","list_id":"linux-ext4.vger.kernel.org","list_email":"linux-ext4@vger.kernel.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260413062500.1380307-2-diangangli@gmail.com>","list_archive_url":null,"date":"2026-04-13T06:25:00","name":"[RFC,v2,1/1] ext4: fail fast on repeated buffer_head reads after IO failure","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"c5735a4845a85300c13e1779ed2d1b36d0579d17","submitter":{"id":92966,"url":"http://patchwork.ozlabs.org/api/1.2/people/92966/?format=json","name":"Diangang Li","email":"diangangli@gmail.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-ext4/patch/20260413062500.1380307-2-diangangli@gmail.com/mbox/","series":[{"id":499650,"url":"http://patchwork.ozlabs.org/api/1.2/series/499650/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-ext4/list/?series=499650","date":"2026-04-13T06:24:59","name":"ext4: fail fast on repeated buffer_head reads after IO failure","version":2,"mbox":"http://patchwork.ozlabs.org/series/499650/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2222591/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2222591/checks/","tags":{},"related":[],"headers":{"Return-Path":"\n <SRS0=fCHB=CM=vger.kernel.org=linux-ext4+bounces-15800-patchwork-incoming=ozlabs.org@ozlabs.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-ext4@vger.kernel.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","patchwork-incoming@ozlabs.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=HlSS97Zn;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=ozlabs.org\n (client-ip=2404:9400:2221:ea00::3; helo=mail.ozlabs.org;\n envelope-from=srs0=fchb=cm=vger.kernel.org=linux-ext4+bounces-15800-patchwork-incoming=ozlabs.org@ozlabs.org;\n receiver=patchwork.ozlabs.org)","gandalf.ozlabs.org;\n arc=pass smtp.remote-ip=\"2600:3c15:e001:75::12fc:5321\"\n arc.chain=subspace.kernel.org","gandalf.ozlabs.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com","gandalf.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=HlSS97Zn;\n\tdkim-atps=neutral","gandalf.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c15:e001:75::12fc:5321; helo=sin.lore.kernel.org;\n envelope-from=linux-ext4+bounces-15800-patchwork-incoming=ozlabs.org@vger.kernel.org;\n receiver=ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=\"HlSS97Zn\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.210.177","smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=gmail.com"],"Received":["from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3])\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 4fvHVL0kMvz1yDF\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 13 Apr 2026 16:26:18 +1000 (AEST)","from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3])\n\tby gandalf.ozlabs.org (Postfix) with ESMTP id 4fvHVL0BrFz4wCG\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 13 Apr 2026 16:26:18 +1000 (AEST)","by gandalf.ozlabs.org (Postfix)\n\tid 4fvHVL05M7z4wHx; Mon, 13 Apr 2026 16:26:18 +1000 (AEST)","from sin.lore.kernel.org (sin.lore.kernel.org\n [IPv6:2600:3c15:e001:75::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest\n SHA256)\n\t(No client certificate requested)\n\tby gandalf.ozlabs.org (Postfix) with ESMTPS id 4fvHVG4nR6z4wCG\n\tfor <patchwork-incoming@ozlabs.org>; Mon, 13 Apr 2026 16:26:14 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sin.lore.kernel.org (Postfix) with ESMTP id EFA4930074DC\n\tfor <patchwork-incoming@ozlabs.org>; Mon, 13 Apr 2026 06:25:53 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id BFA48391E5F;\n\tMon, 13 Apr 2026 06:25:51 +0000 (UTC)","from mail-pf1-f177.google.com (mail-pf1-f177.google.com\n [209.85.210.177])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id EB9672253FC\n\tfor <linux-ext4@vger.kernel.org>; Mon, 13 Apr 2026 06:25:49 +0000 (UTC)","by mail-pf1-f177.google.com with SMTP id\n d2e1a72fcca58-82d0b68837aso2143930b3a.2\n        for <linux-ext4@vger.kernel.org>;\n Sun, 12 Apr 2026 23:25:49 -0700 (PDT)","from n37-098-250.byted.org ([115.190.40.14])\n        by smtp.gmail.com with ESMTPSA id\n d2e1a72fcca58-82f0c20aed6sm10035640b3a.0.2026.04.12.23.25.46\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Sun, 12 Apr 2026 23:25:48 -0700 (PDT)"],"ARC-Seal":["i=2; a=rsa-sha256; d=ozlabs.org; s=201707; t=1776061578; cv=pass;\n\tb=kEVUdGGsXw+/ALRqY0yhvTfbyaw/YsLnENwnl3j8pYVviGL2vjA/WMJSMEI2TKauK0m5ZNlGcUtQ23an09AAV2/8/VAd6L/mQSvZ90zIVW2zV6CW11bbJ5j5UP1rMGdjmey0do808/iUByQYHgcACAINV4A40caDiZbc5nvozRiTHkkLBHSMnZVd180QkRv7iO8xgEuMdjg/7kp9J5h8JnDfST1RHGCTn+IdhwiI80IZ+p6FiLnN+VeEc+vkU8BwQMgMJS0MhECqsz7I1ttmdJ1EEJKpZ1xJjZHzX/Y0bEcHFy5vpyk7RGrKxL4xRgm7W+IftxBlvQT8+Yy1HDdcjA==","i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1776061551; cv=none;\n b=WhNf5FMn6fK/ueoOPG9iPjJ6eZVfVW2cMT6OLSOWddTCt19H19/t7iXENyLnbDR1U1BR0tNQWByV/7CEYABnMijN/kYFq/c5h1xPc71YxoTkhexvjEf2AZPj9XciUbXMPbG4hfkOH3XIR8Y/sueOgW5H5wPISEXUs+3Cn1IGdgM="],"ARC-Message-Signature":["i=2; a=rsa-sha256; d=ozlabs.org; s=201707;\n\tt=1776061578; c=relaxed/relaxed;\n\tbh=00cP/T9QeuySw5AlaNH1mzjkrGnGheu4JmbuNHs7ieI=;\n\th=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:\n\t MIME-Version;\n b=PJzpZijUs9QYtW/Iog3i2Y3VN/SncF0qW+MbnCEXYbPx5BTc1zRKSTZM+Y6cwaLrCdebulbeV5V99lukdBoVQGGuWGAP+LpB8Q2zVVSfO81hDjakRizi+N4z26wKB88fy8Y9HidYxvnKMMLV3398qv9OAXLtsLnuDdbaY/dSyxqD39nJO8LEIADBj9maMBcdT1ufsCPf7tW83U+A5YI+jk+Og2tIx6R7GdsNMF+/mfc6fDJbf4q+crthsu+zMTDxSTL/A5qzODN+1zAWZtpPTlwqnTBOUveQslkYOPCsyEebeUS/X3SICcYgd9frANPsubUgoADPU9GWE17RG4DXBQ==","i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1776061551; c=relaxed/simple;\n\tbh=kWUJURp+uF9u4Y1dNuO0maD9jAqb/5vkOI1EQA+2rsc=;\n\th=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:\n\t MIME-Version;\n b=HG9oKDzttpeEwUzus8pnF0bg1XLUEZRTnjFYlUdO3lQ0jf+2/3UhSujKXr8nA3qTRvWUM1b4Kc/epcd2vWwTcronzk3UmIdkLit14fOCxQKpLRIt1s7UTXrTlxi5UzfThdQup1MwKKdIpMPQpC8TTdP8yBynSxTvQExQskWI1zs="],"ARC-Authentication-Results":["i=2; gandalf.ozlabs.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com; dkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=HlSS97Zn; dkim-atps=neutral;\n spf=pass (client-ip=2600:3c15:e001:75::12fc:5321; helo=sin.lore.kernel.org;\n envelope-from=linux-ext4+bounces-15800-patchwork-incoming=ozlabs.org@vger.kernel.org;\n receiver=ozlabs.org) smtp.mailfrom=vger.kernel.org","i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com;\n spf=pass smtp.mailfrom=gmail.com;\n dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=HlSS97Zn; arc=none smtp.client-ip=209.85.210.177"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=gmail.com; s=20251104; t=1776061549; x=1776666349;\n darn=vger.kernel.org;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n         :message-id:reply-to;\n        bh=00cP/T9QeuySw5AlaNH1mzjkrGnGheu4JmbuNHs7ieI=;\n        b=HlSS97ZnKtj1356sK3AsmZzPJIfuhEzwD7PuLWedrJSgTzFvASVpTvAzuyK8W4qiex\n         POHE4f8Np9cR0UlHM8ZcaaExhKS6wIHedA03dRIM/HaeYSmvweGARpkOKMHK9XfK6WUd\n         k+uQvBhU3T9X1i1Ufb+L6Td4hHzFBdZ645f6Q5PdM10eyzi8dVmeQJKQirMnKeE4GNoB\n         LLhEVpJ0u+VrcEx+PJ9U/XSFVhk5YrKbUEiPLDkpD719s/EnRULPOsno4hasKY65+scf\n         sARU1aOMJlH4l9Xstj3PB/PG00ysgN3SMEzUkMUjkWwVilAQvJfhdvresAYS3xzOz2+8\n         w9fw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20251104; t=1776061549; x=1776666349;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n         :to:cc:subject:date:message-id:reply-to;\n        bh=00cP/T9QeuySw5AlaNH1mzjkrGnGheu4JmbuNHs7ieI=;\n        b=TDkYWsNV/0hy7lSAYO4vm7Pg5dK6tizRQHC/qro4DmQFiLPgtZK39MnuIzBaQMDTSa\n         lYQhcgIWsRptKL88ct47tGvIQXsrGcAS3/lKn3ErJ72irJUM583c2hSuR2qfAibROWtA\n         UD1dVf85JEqd7vGRuXQfpO21+41tfKGI561a5WUs3AS00/d8Zlf6rpFYY7omL9qW4cbq\n         sb1ZDaHlMtNYwZ5BzJrWDNLGZPRLB3X2B1JROU9mz4z7SZ+yELlxtpHA07XatBhPzF0F\n         CVThQgs+ld+XqBX3idVvThDXkvwFYp3QHDBKsXwsu0P5KhjaET9m8twLyB9bN5OAoIkA\n         7EzA==","X-Gm-Message-State":"AOJu0YyGEOjRScLSIBRclXx9PGg9euxrfU3KwuvIz7dlMlRi+5xsNCqn\n\tmh+IA4K/6b9P1wyZtOTCo5vQrVIm/mTRkqpueD9giAhfTYfiPQ7mFjIj","X-Gm-Gg":"AeBDieuKYsbPlY59a6nGbLC3izNLzftletFJ2RzEhZtcqbClwZ70CJWNHGqu/MPV/L2\n\tLO7FY1EHpv1+K++YA3Xj/ArcPGn7Htv1gZACYeVI45XGDAUkT9GdO3LgdQaibP12kXnx13t6RuH\n\tgv3nqg16P1TBlr5lcjOCYI+7loNJWDhYItl+gsb/3JbqsU6U1fD3OmBW0GaZR8s9wOIYNl2WjTx\n\tOV/Xdf5Gjn3tfoC6XQFNfKPgE1IBGwaHrzMcUTn+teJUW8FpkbO3dzjXJF9GnYIY73zjdnCmMUw\n\t/xrfjNBlKHDPXhmQuKpf3n836E7Qrge/qavFFnkAWlfqlqCIqP41MArRB5G/0VEdwTcSc3JxCNy\n\t+Z5yu9RFJYRqypBnWxhh8X156+va9RgOWRfgdgfkMbQL5tULOwnNGnmD5jP3Sn/R8ghpbGf2iGE\n\t06QSOzQqyIOQDxX/Zs2tPZDLDH4Hi0+Y0RvI4+","X-Received":"by 2002:a05:6a00:2e9d:b0:82f:48e:2421 with SMTP id\n d2e1a72fcca58-82f0c29c84amr12217294b3a.24.1776061549283;\n        Sun, 12 Apr 2026 23:25:49 -0700 (PDT)","From":"Diangang Li <diangangli@gmail.com>","To":"tytso@mit.edu,\n\tadilger.kernel@dilger.ca","Cc":"linux-ext4@vger.kernel.org,\n\tlinux-fsdevel@vger.kernel.org,\n\tlinux-kernel@vger.kernel.org,\n\tchangfengnan@bytedance.com,\n\tyizhang089@gmail.com,\n\twilly@infradead.org,\n\tDiangang Li <lidiangang@bytedance.com>","Subject":"[RFC v2 1/1] ext4: fail fast on repeated buffer_head reads after IO\n failure","Date":"Mon, 13 Apr 2026 14:25:00 +0800","Message-Id":"<20260413062500.1380307-2-diangangli@gmail.com>","X-Mailer":"git-send-email 2.39.5","In-Reply-To":"<20260413062500.1380307-1-diangangli@gmail.com>","References":"<20260325093349.630193-1-diangangli@gmail.com>\n <20260413062500.1380307-1-diangangli@gmail.com>","Precedence":"bulk","X-Mailing-List":"linux-ext4@vger.kernel.org","List-Id":"<linux-ext4.vger.kernel.org>","List-Subscribe":"<mailto:linux-ext4+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-ext4+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-Spam-Status":"No, score=-1.2 required=5.0 tests=ARC_SIGNED,ARC_VALID,\n\tDKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DMARC_PASS,\n\tFREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,\n\tMAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=disabled\n\tversion=4.0.1","X-Spam-Checker-Version":"SpamAssassin 4.0.1 (2024-03-25) on gandalf.ozlabs.org"},"content":"From: Diangang Li <lidiangang@bytedance.com>\n\next4 buffer_head reads serialize on BH_Lock. If a read fails, the buffer\nremains !Uptodate. With concurrent callers, each waiter may resubmit the\nsame failing read after the previous holder drops BH_Lock. This can turn\na single read error into long stalls and hung tasks.\n\nThe block layer already retries reads. After it gives up, re-submitting\nthe same buffer_head read from ext4 makes no forward progress and just\nkeeps waiters serialized on BH_Lock.\n\nRecord read failures on buffer_head (BH_Read_EIO + b_err_timestamp) and,\nwhen a retry window is configured (sysfs: err_retry_sec), fail fast for\nrepeated ext4 buffer_head reads within the window. Clear the state on\nsuccessful completion so the buffer can recover.\n\nerr_retry_sec defaults to 0, which keeps the current behavior (subsequent\ncallers may retry the same read). Set it to a non-zero value to throttle\nrepeated reads within the window.\n\nExample hung stacks:\n\n  INFO: task toutiao.infra.t:3760933 blocked for more than 327 seconds.\n  Call Trace:\n   __schedule\n   io_schedule\n   __wait_on_bit_lock\n   bh_uptodate_or_lock\n   __read_extent_tree_block\n   ext4_find_extent\n   ext4_ext_map_blocks\n   ext4_map_blocks\n   ext4_getblk\n   ext4_bread\n   __ext4_read_dirblock\n   dx_probe\n   ext4_htree_fill_tree\n   ext4_readdir\n   iterate_dir\n   ksys_getdents64\n\n  INFO: task toutiao.infra.t:2724456 blocked for more than 327 seconds.\n  Call Trace:\n   __schedule\n   io_schedule\n   __wait_on_bit_lock\n   ext4_read_bh_lock\n   ext4_bread\n   __ext4_read_dirblock\n   htree_dirblock_to_tree\n   ext4_htree_fill_tree\n   ext4_readdir\n   iterate_dir\n   ksys_getdents64\n\nSigned-off-by: Diangang Li <lidiangang@bytedance.com>\n---\n fs/buffer.c                 |  2 ++\n fs/ext4/balloc.c            |  2 +-\n fs/ext4/ext4.h              | 13 ++++++----\n fs/ext4/extents.c           |  2 +-\n fs/ext4/ialloc.c            |  3 ++-\n fs/ext4/indirect.c          |  2 +-\n fs/ext4/inode.c             | 10 ++++----\n fs/ext4/mmp.c               |  2 +-\n fs/ext4/move_extent.c       |  2 +-\n fs/ext4/resize.c            |  2 +-\n fs/ext4/super.c             | 51 +++++++++++++++++++++++++++----------\n fs/ext4/sysfs.c             |  2 ++\n include/linux/buffer_head.h | 16 ++++++++++++\n 13 files changed, 79 insertions(+), 30 deletions(-)","diff":"diff --git a/fs/buffer.c b/fs/buffer.c\nindex 22b43642ba574..10b1f60368db4 100644\n--- a/fs/buffer.c\n+++ b/fs/buffer.c\n@@ -159,6 +159,7 @@ static void __end_buffer_read_notouch(struct buffer_head *bh, int uptodate)\n void end_buffer_read_sync(struct buffer_head *bh, int uptodate)\n {\n \tput_bh(bh);\n+\tbh_update_read_io_error(bh, uptodate, jiffies);\n \t__end_buffer_read_notouch(bh, uptodate);\n }\n EXPORT_SYMBOL(end_buffer_read_sync);\n@@ -167,6 +168,7 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate)\n {\n \tif (uptodate) {\n \t\tset_buffer_uptodate(bh);\n+\t\tbh_update_read_io_error(bh, 1, jiffies);\n \t} else {\n \t\tbuffer_io_error(bh, \", lost sync page write\");\n \t\tmark_buffer_write_io_error(bh);\ndiff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c\nindex 8040c731b3e45..8d7797adbb63e 100644\n--- a/fs/ext4/balloc.c\n+++ b/fs/ext4/balloc.c\n@@ -548,7 +548,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group,\n \t */\n \tset_buffer_new(bh);\n \ttrace_ext4_read_block_bitmap_load(sb, block_group, ignore_locked);\n-\text4_read_bh_nowait(bh, REQ_META | REQ_PRIO |\n+\text4_read_bh_nowait(sb, bh, REQ_META | REQ_PRIO |\n \t\t\t    (ignore_locked ? REQ_RAHEAD : 0),\n \t\t\t    ext4_end_bitmap_read,\n \t\t\t    ext4_simulate_fail(sb, EXT4_SIM_BBITMAP_EIO));\ndiff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h\nindex 7617e2d454ea5..4b6ff26201933 100644\n--- a/fs/ext4/ext4.h\n+++ b/fs/ext4/ext4.h\n@@ -1682,6 +1682,8 @@ struct ext4_sb_info {\n \tstruct timer_list s_err_report;\n \t/* timeout in seconds for s_err_report; 0 disables the timer. */\n \tunsigned long s_err_report_sec;\n+\t/* timeout in seconds for read error retry window; 0 disables. */\n+\tunsigned long s_err_retry_sec;\n \n \t/* Lazy inode table initialization info */\n \tstruct ext4_li_request *s_li_request;\n@@ -3185,11 +3187,12 @@ extern struct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb,\n \t\t\t\t\t\t   sector_t block);\n extern struct buffer_head *ext4_sb_bread_nofail(struct super_block *sb,\n \t\t\t\t\t\tsector_t block);\n-extern void ext4_read_bh_nowait(struct buffer_head *bh, blk_opf_t op_flags,\n-\t\t\t\tbh_end_io_t *end_io, bool simu_fail);\n-extern int ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,\n-\t\t\tbh_end_io_t *end_io, bool simu_fail);\n-extern int ext4_read_bh_lock(struct buffer_head *bh, blk_opf_t op_flags, bool wait);\n+extern void ext4_read_bh_nowait(struct super_block *sb, struct buffer_head *bh,\n+\t\t\t\tblk_opf_t op_flags, bh_end_io_t *end_io, bool simu_fail);\n+extern int ext4_read_bh(struct super_block *sb, struct buffer_head *bh,\n+\t\t\tblk_opf_t op_flags, bh_end_io_t *end_io, bool simu_fail);\n+extern int ext4_read_bh_lock(struct super_block *sb, struct buffer_head *bh,\n+\t\t\tblk_opf_t op_flags, bool wait);\n extern void ext4_sb_breadahead_unmovable(struct super_block *sb, sector_t block);\n extern int ext4_seq_options_show(struct seq_file *seq, void *offset);\n extern int ext4_calculate_overhead(struct super_block *sb);\ndiff --git a/fs/ext4/extents.c b/fs/ext4/extents.c\nindex 8cce1479be6d1..b7fb195ded3e3 100644\n--- a/fs/ext4/extents.c\n+++ b/fs/ext4/extents.c\n@@ -567,7 +567,7 @@ __read_extent_tree_block(const char *function, unsigned int line,\n \n \tif (!bh_uptodate_or_lock(bh)) {\n \t\ttrace_ext4_ext_load_extent(inode, pblk, _RET_IP_);\n-\t\terr = ext4_read_bh(bh, 0, NULL, false);\n+\t\terr = ext4_read_bh(inode->i_sb, bh, 0, NULL, false);\n \t\tif (err < 0)\n \t\t\tgoto errout;\n \t}\ndiff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c\nindex b1bc1950c9f03..25a177eb89bf1 100644\n--- a/fs/ext4/ialloc.c\n+++ b/fs/ext4/ialloc.c\n@@ -72,6 +72,7 @@ void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate)\n \t\tset_buffer_uptodate(bh);\n \t\tset_bitmap_uptodate(bh);\n \t}\n+\tbh_update_read_io_error(bh, uptodate, jiffies);\n \tunlock_buffer(bh);\n \tput_bh(bh);\n }\n@@ -193,7 +194,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)\n \t * submit the buffer_head for reading\n \t */\n \ttrace_ext4_load_inode_bitmap(sb, block_group);\n-\text4_read_bh(bh, REQ_META | REQ_PRIO,\n+\text4_read_bh(sb, bh, REQ_META | REQ_PRIO,\n \t\t     ext4_end_bitmap_read,\n \t\t     ext4_simulate_fail(sb, EXT4_SIM_IBITMAP_EIO));\n \tif (!buffer_uptodate(bh)) {\ndiff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c\nindex da76353b3a575..1ff2b5872e8b0 100644\n--- a/fs/ext4/indirect.c\n+++ b/fs/ext4/indirect.c\n@@ -170,7 +170,7 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,\n \t\t}\n \n \t\tif (!bh_uptodate_or_lock(bh)) {\n-\t\t\tif (ext4_read_bh(bh, 0, NULL, false) < 0) {\n+\t\t\tif (ext4_read_bh(sb, bh, 0, NULL, false) < 0) {\n \t\t\t\tput_bh(bh);\n \t\t\t\tgoto failure;\n \t\t\t}\ndiff --git a/fs/ext4/inode.c b/fs/ext4/inode.c\nindex 1123d995494b5..49c03c485a8d5 100644\n--- a/fs/ext4/inode.c\n+++ b/fs/ext4/inode.c\n@@ -1053,7 +1053,7 @@ struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,\n \tif (!bh || ext4_buffer_uptodate(bh))\n \t\treturn bh;\n \n-\tret = ext4_read_bh_lock(bh, REQ_META | REQ_PRIO, true);\n+\tret = ext4_read_bh_lock(inode->i_sb, bh, REQ_META | REQ_PRIO, true);\n \tif (ret) {\n \t\tput_bh(bh);\n \t\treturn ERR_PTR(ret);\n@@ -1079,7 +1079,7 @@ int ext4_bread_batch(struct inode *inode, ext4_lblk_t block, int bh_count,\n \tfor (i = 0; i < bh_count; i++)\n \t\t/* Note that NULL bhs[i] is valid because of holes. */\n \t\tif (bhs[i] && !ext4_buffer_uptodate(bhs[i]))\n-\t\t\text4_read_bh_lock(bhs[i], REQ_META | REQ_PRIO, false);\n+\t\t\text4_read_bh_lock(inode->i_sb, bhs[i], REQ_META | REQ_PRIO, false);\n \n \tif (!wait)\n \t\treturn 0;\n@@ -1239,7 +1239,7 @@ int ext4_block_write_begin(handle_t *handle, struct folio *folio,\n \t\tif (!buffer_uptodate(bh) && !buffer_delay(bh) &&\n \t\t    !buffer_unwritten(bh) &&\n \t\t    (block_start < from || block_end > to)) {\n-\t\t\text4_read_bh_lock(bh, 0, false);\n+\t\t\text4_read_bh_lock(inode->i_sb, bh, 0, false);\n \t\t\twait[nr_wait++] = bh;\n \t\t}\n \t}\n@@ -4063,7 +4063,7 @@ static int __ext4_block_zero_page_range(handle_t *handle,\n \t\tset_buffer_uptodate(bh);\n \n \tif (!buffer_uptodate(bh)) {\n-\t\terr = ext4_read_bh_lock(bh, 0, true);\n+\t\terr = ext4_read_bh_lock(inode->i_sb, bh, 0, true);\n \t\tif (err)\n \t\t\tgoto unlock;\n \t\tif (fscrypt_inode_uses_fs_layer_crypto(inode)) {\n@@ -4891,7 +4891,7 @@ static int __ext4_get_inode_loc(struct super_block *sb, unsigned long ino,\n \t * Read the block from disk.\n \t */\n \ttrace_ext4_load_inode(sb, ino);\n-\text4_read_bh_nowait(bh, REQ_META | REQ_PRIO, NULL,\n+\text4_read_bh_nowait(sb, bh, REQ_META | REQ_PRIO, NULL,\n \t\t\t    ext4_simulate_fail(sb, EXT4_SIM_INODE_EIO));\n \tblk_finish_plug(&plug);\n \twait_on_buffer(bh);\ndiff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c\nindex 6f57c181ff778..6407b7fbdd3e8 100644\n--- a/fs/ext4/mmp.c\n+++ b/fs/ext4/mmp.c\n@@ -90,7 +90,7 @@ static int read_mmp_block(struct super_block *sb, struct buffer_head **bh,\n \t}\n \n \tlock_buffer(*bh);\n-\tret = ext4_read_bh(*bh, REQ_META | REQ_PRIO, NULL, false);\n+\tret = ext4_read_bh(sb, *bh, REQ_META | REQ_PRIO, NULL, false);\n \tif (ret)\n \t\tgoto warn_exit;\n \ndiff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c\nindex ce1f738dff938..a304352a0741f 100644\n--- a/fs/ext4/move_extent.c\n+++ b/fs/ext4/move_extent.c\n@@ -162,7 +162,7 @@ static int mext_folio_mkuptodate(struct folio *folio, size_t from, size_t to)\n \t\t\tunlock_buffer(bh);\n \t\t\tcontinue;\n \t\t}\n-\t\text4_read_bh_nowait(bh, 0, NULL, false);\n+\t\text4_read_bh_nowait(inode->i_sb, bh, 0, NULL, false);\n \t\tnr++;\n \t} while (block++, (bh = bh->b_this_page) != head);\n \ndiff --git a/fs/ext4/resize.c b/fs/ext4/resize.c\nindex 2c5b851c552a6..0350e85cc58fb 100644\n--- a/fs/ext4/resize.c\n+++ b/fs/ext4/resize.c\n@@ -1299,7 +1299,7 @@ static struct buffer_head *ext4_get_bitmap(struct super_block *sb, __u64 block)\n \tif (unlikely(!bh))\n \t\treturn NULL;\n \tif (!bh_uptodate_or_lock(bh)) {\n-\t\tif (ext4_read_bh(bh, 0, NULL, false) < 0) {\n+\t\tif (ext4_read_bh(sb, bh, 0, NULL, false) < 0) {\n \t\t\tbrelse(bh);\n \t\t\treturn NULL;\n \t\t}\ndiff --git a/fs/ext4/super.c b/fs/ext4/super.c\nindex a34efb44e73d7..c0e4d8106e4f3 100644\n--- a/fs/ext4/super.c\n+++ b/fs/ext4/super.c\n@@ -160,8 +160,26 @@ MODULE_ALIAS(\"ext3\");\n #define IS_EXT3_SB(sb) ((sb)->s_type == &ext3_fs_type)\n \n \n-static inline void __ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,\n-\t\t\t\t  bh_end_io_t *end_io, bool simu_fail)\n+static bool ext4_bh_throttle_read(struct super_block *sb, struct buffer_head *bh)\n+{\n+\tunsigned long retry_sec = EXT4_SB(sb)->s_err_retry_sec;\n+\n+\tif (!retry_sec || !buffer_read_io_error(bh))\n+\t\treturn false;\n+\n+\tif (bh->b_err_timestamp &&\n+\t    time_before(jiffies, bh->b_err_timestamp +\n+\t\t\tsecs_to_jiffies(retry_sec)))\n+\t\treturn true;\n+\n+\tclear_buffer_read_io_error(bh);\n+\tbh->b_err_timestamp = 0;\n+\treturn false;\n+}\n+\n+static inline void __ext4_read_bh(struct super_block *sb, struct buffer_head *bh,\n+\t\t\t\t  blk_opf_t op_flags, bh_end_io_t *end_io,\n+\t\t\t\t  bool simu_fail)\n {\n \tif (simu_fail) {\n \t\tclear_buffer_uptodate(bh);\n@@ -169,6 +187,12 @@ static inline void __ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,\n \t\treturn;\n \t}\n \n+\tif (ext4_bh_throttle_read(sb, bh)) {\n+\t\tclear_buffer_uptodate(bh);\n+\t\tunlock_buffer(bh);\n+\t\treturn;\n+\t}\n+\n \t/*\n \t * buffer's verified bit is no longer valid after reading from\n \t * disk again due to write out error, clear it to make sure we\n@@ -181,8 +205,8 @@ static inline void __ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,\n \tsubmit_bh(REQ_OP_READ | op_flags, bh);\n }\n \n-void ext4_read_bh_nowait(struct buffer_head *bh, blk_opf_t op_flags,\n-\t\t\t bh_end_io_t *end_io, bool simu_fail)\n+void ext4_read_bh_nowait(struct super_block *sb, struct buffer_head *bh,\n+\t\t\t blk_opf_t op_flags, bh_end_io_t *end_io, bool simu_fail)\n {\n \tBUG_ON(!buffer_locked(bh));\n \n@@ -190,11 +214,11 @@ void ext4_read_bh_nowait(struct buffer_head *bh, blk_opf_t op_flags,\n \t\tunlock_buffer(bh);\n \t\treturn;\n \t}\n-\t__ext4_read_bh(bh, op_flags, end_io, simu_fail);\n+\t__ext4_read_bh(sb, bh, op_flags, end_io, simu_fail);\n }\n \n-int ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,\n-\t\t bh_end_io_t *end_io, bool simu_fail)\n+int ext4_read_bh(struct super_block *sb, struct buffer_head *bh,\n+\t\t blk_opf_t op_flags, bh_end_io_t *end_io, bool simu_fail)\n {\n \tBUG_ON(!buffer_locked(bh));\n \n@@ -203,7 +227,7 @@ int ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,\n \t\treturn 0;\n \t}\n \n-\t__ext4_read_bh(bh, op_flags, end_io, simu_fail);\n+\t__ext4_read_bh(sb, bh, op_flags, end_io, simu_fail);\n \n \twait_on_buffer(bh);\n \tif (buffer_uptodate(bh))\n@@ -211,14 +235,15 @@ int ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,\n \treturn -EIO;\n }\n \n-int ext4_read_bh_lock(struct buffer_head *bh, blk_opf_t op_flags, bool wait)\n+int ext4_read_bh_lock(struct super_block *sb, struct buffer_head *bh,\n+\t\t      blk_opf_t op_flags, bool wait)\n {\n \tlock_buffer(bh);\n \tif (!wait) {\n-\t\text4_read_bh_nowait(bh, op_flags, NULL, false);\n+\t\text4_read_bh_nowait(sb, bh, op_flags, NULL, false);\n \t\treturn 0;\n \t}\n-\treturn ext4_read_bh(bh, op_flags, NULL, false);\n+\treturn ext4_read_bh(sb, bh, op_flags, NULL, false);\n }\n \n /*\n@@ -240,7 +265,7 @@ static struct buffer_head *__ext4_sb_bread_gfp(struct super_block *sb,\n \tif (ext4_buffer_uptodate(bh))\n \t\treturn bh;\n \n-\tret = ext4_read_bh_lock(bh, REQ_META | op_flags, true);\n+\tret = ext4_read_bh_lock(sb, bh, REQ_META | op_flags, true);\n \tif (ret) {\n \t\tput_bh(bh);\n \t\treturn ERR_PTR(ret);\n@@ -282,7 +307,7 @@ void ext4_sb_breadahead_unmovable(struct super_block *sb, sector_t block)\n \n \tif (likely(bh)) {\n \t\tif (trylock_buffer(bh))\n-\t\t\text4_read_bh_nowait(bh, REQ_RAHEAD, NULL, false);\n+\t\t\text4_read_bh_nowait(sb, bh, REQ_RAHEAD, NULL, false);\n \t\tbrelse(bh);\n \t}\n }\ndiff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c\nindex 923b375e017fa..21fed223c9e86 100644\n--- a/fs/ext4/sysfs.c\n+++ b/fs/ext4/sysfs.c\n@@ -249,6 +249,7 @@ EXT4_ATTR_OFFSET(mb_group_prealloc, 0644, clusters_in_group,\n EXT4_ATTR_OFFSET(mb_best_avail_max_trim_order, 0644, mb_order,\n \t\t ext4_sb_info, s_mb_best_avail_max_trim_order);\n EXT4_ATTR_OFFSET(err_report_sec, 0644, err_report_sec, ext4_sb_info, s_err_report_sec);\n+EXT4_RW_ATTR_SBI_UL(err_retry_sec, s_err_retry_sec);\n EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal);\n EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats);\n EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan);\n@@ -342,6 +343,7 @@ static struct attribute *ext4_attrs[] = {\n \tATTR_LIST(sb_update_sec),\n \tATTR_LIST(sb_update_kb),\n \tATTR_LIST(err_report_sec),\n+\tATTR_LIST(err_retry_sec),\n \tNULL,\n };\n ATTRIBUTE_GROUPS(ext4);\ndiff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h\nindex b16b88bfbc3e7..77e42e706d1e5 100644\n--- a/include/linux/buffer_head.h\n+++ b/include/linux/buffer_head.h\n@@ -29,6 +29,7 @@ enum bh_state_bits {\n \tBH_Delay,\t/* Buffer is not yet allocated on disk */\n \tBH_Boundary,\t/* Block is followed by a discontiguity */\n \tBH_Write_EIO,\t/* I/O error on write */\n+\tBH_Read_EIO,\t/* I/O error on read */\n \tBH_Unwritten,\t/* Buffer is allocated on disk but not written */\n \tBH_Quiet,\t/* Buffer Error Prinks to be quiet */\n \tBH_Meta,\t/* Buffer contains metadata */\n@@ -79,6 +80,7 @@ struct buffer_head {\n \tspinlock_t b_uptodate_lock;\t/* Used by the first bh in a page, to\n \t\t\t\t\t * serialise IO completion of other\n \t\t\t\t\t * buffers in the page */\n+\tunsigned long b_err_timestamp;\t/* timestamp of last IO error (jiffies) */\n };\n \n /*\n@@ -132,11 +134,25 @@ BUFFER_FNS(Async_Write, async_write)\n BUFFER_FNS(Delay, delay)\n BUFFER_FNS(Boundary, boundary)\n BUFFER_FNS(Write_EIO, write_io_error)\n+BUFFER_FNS(Read_EIO, read_io_error)\n BUFFER_FNS(Unwritten, unwritten)\n BUFFER_FNS(Meta, meta)\n BUFFER_FNS(Prio, prio)\n BUFFER_FNS(Defer_Completion, defer_completion)\n \n+static __always_inline void bh_update_read_io_error(struct buffer_head *bh,\n+\t\t\t\t\t\t    int uptodate,\n+\t\t\t\t\t\t    unsigned long now)\n+{\n+\tif (uptodate) {\n+\t\tclear_buffer_read_io_error(bh);\n+\t\tbh->b_err_timestamp = 0;\n+\t} else if (!buffer_read_io_error(bh)) {\n+\t\tset_buffer_read_io_error(bh);\n+\t\tbh->b_err_timestamp = now;\n+\t}\n+}\n+\n static __always_inline void set_buffer_uptodate(struct buffer_head *bh)\n {\n \t/*\n","prefixes":["RFC","v2","1/1"]}