--- /dev/null
+From fe1e257c1f458f5eace878a81ac558452b3dd73b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 7 Sep 2023 16:17:10 +0800
+Subject: ata: libahci: clear pending interrupt status
+
+From: Szuying Chen <chensiying21@gmail.com>
+
+[ Upstream commit 737dd811a3dbfd7edd4ad2ba5152e93d99074f83 ]
+
+When a CRC error occurs, the HBA asserts an interrupt to indicate an
+interface fatal error (PxIS.IFS). The ISR clears PxIE and PxIS, then
+does error recovery. If the adapter receives another SDB FIS
+with an error (PxIS.TFES) from the device before the start of the EH
+recovery process, the interrupt signaling the new SDB cannot be
+serviced as PxIE was cleared already. This in turn results in the HBA
+inability to issue any command during the error recovery process after
+setting PxCMD.ST to 1 because PxIS.TFES is still set.
+
+According to AHCI 1.3.1 specifications section 6.2.2, fatal errors
+notified by setting PxIS.HBFS, PxIS.HBDS, PxIS.IFS or PxIS.TFES will
+cause the HBA to enter the ERR:Fatal state. In this state, the HBA
+shall not issue any new commands.
+
+To avoid this situation, introduce the function
+ahci_port_clear_pending_irq() to clear pending interrupts before
+executing a COMRESET. This follows the AHCI 1.3.1 - section 6.2.2.2
+specification.
+
+Signed-off-by: Szuying Chen <Chloe_Chen@asmedia.com.tw>
+Fixes: e0bfd149973d ("[PATCH] ahci: stop engine during hard reset")
+Cc: stable@vger.kernel.org
+Reviewed-by: Niklas Cassel <niklas.cassel@wdc.com>
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ata/libahci.c | 35 +++++++++++++++++++++++------------
+ 1 file changed, 23 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
+index fec2e9754aed2..61b5ba8dc1d21 100644
+--- a/drivers/ata/libahci.c
++++ b/drivers/ata/libahci.c
+@@ -1199,6 +1199,26 @@ static ssize_t ahci_activity_show(struct ata_device *dev, char *buf)
+ return sprintf(buf, "%d\n", emp->blink_policy);
+ }
+
++static void ahci_port_clear_pending_irq(struct ata_port *ap)
++{
++ struct ahci_host_priv *hpriv = ap->host->private_data;
++ void __iomem *port_mmio = ahci_port_base(ap);
++ u32 tmp;
++
++ /* clear SError */
++ tmp = readl(port_mmio + PORT_SCR_ERR);
++ dev_dbg(ap->host->dev, "PORT_SCR_ERR 0x%x\n", tmp);
++ writel(tmp, port_mmio + PORT_SCR_ERR);
++
++ /* clear port IRQ */
++ tmp = readl(port_mmio + PORT_IRQ_STAT);
++ dev_dbg(ap->host->dev, "PORT_IRQ_STAT 0x%x\n", tmp);
++ if (tmp)
++ writel(tmp, port_mmio + PORT_IRQ_STAT);
++
++ writel(1 << ap->port_no, hpriv->mmio + HOST_IRQ_STAT);
++}
++
+ static void ahci_port_init(struct device *dev, struct ata_port *ap,
+ int port_no, void __iomem *mmio,
+ void __iomem *port_mmio)
+@@ -1213,18 +1233,7 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap,
+ if (rc)
+ dev_warn(dev, "%s (%d)\n", emsg, rc);
+
+- /* clear SError */
+- tmp = readl(port_mmio + PORT_SCR_ERR);
+- VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
+- writel(tmp, port_mmio + PORT_SCR_ERR);
+-
+- /* clear port IRQ */
+- tmp = readl(port_mmio + PORT_IRQ_STAT);
+- VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
+- if (tmp)
+- writel(tmp, port_mmio + PORT_IRQ_STAT);
+-
+- writel(1 << port_no, mmio + HOST_IRQ_STAT);
++ ahci_port_clear_pending_irq(ap);
+
+ /* mark esata ports */
+ tmp = readl(port_mmio + PORT_CMD);
+@@ -1554,6 +1563,8 @@ int ahci_do_hardreset(struct ata_link *link, unsigned int *class,
+ tf.command = ATA_BUSY;
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+
++ ahci_port_clear_pending_irq(ap);
++
+ rc = sata_link_hardreset(link, timing, deadline, online,
+ ahci_check_ready);
+
+--
+2.40.1
+
--- /dev/null
+From c007fb7d5b2bde9e8aee464d9e2c8ce61956e8c1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 24 Jul 2021 15:41:21 +0800
+Subject: ext4: add new helper interface ext4_try_to_trim_range()
+
+From: Wang Jianchao <wangjianchao@kuaishou.com>
+
+[ Upstream commit 6920b3913235f517728bb69abe9b39047a987113 ]
+
+There is no functional change in this patch but just split the
+codes, which serachs free block and does trim, into a new function
+ext4_try_to_trim_range. This is preparing for the following async
+backgroup discard.
+
+Reviewed-by: Andreas Dilger <adilger@dilger.ca>
+Signed-off-by: Wang Jianchao <wangjianchao@kuaishou.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20210724074124.25731-3-jianchao.wan9@gmail.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/mballoc.c | 102 ++++++++++++++++++++++++++--------------------
+ 1 file changed, 57 insertions(+), 45 deletions(-)
+
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index 9b4af51c99da4..5a7fe5aa0fc38 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -5194,6 +5194,54 @@ __acquires(bitlock)
+ return ret;
+ }
+
++static int ext4_try_to_trim_range(struct super_block *sb,
++ struct ext4_buddy *e4b, ext4_grpblk_t start,
++ ext4_grpblk_t max, ext4_grpblk_t minblocks)
++{
++ ext4_grpblk_t next, count, free_count;
++ void *bitmap;
++ int ret = 0;
++
++ bitmap = e4b->bd_bitmap;
++ start = (e4b->bd_info->bb_first_free > start) ?
++ e4b->bd_info->bb_first_free : start;
++ count = 0;
++ free_count = 0;
++
++ while (start <= max) {
++ start = mb_find_next_zero_bit(bitmap, max + 1, start);
++ if (start > max)
++ break;
++ next = mb_find_next_bit(bitmap, max + 1, start);
++
++ if ((next - start) >= minblocks) {
++ ret = ext4_trim_extent(sb, start, next - start, e4b);
++ if (ret && ret != -EOPNOTSUPP)
++ break;
++ ret = 0;
++ count += next - start;
++ }
++ free_count += next - start;
++ start = next + 1;
++
++ if (fatal_signal_pending(current)) {
++ count = -ERESTARTSYS;
++ break;
++ }
++
++ if (need_resched()) {
++ ext4_unlock_group(sb, e4b->bd_group);
++ cond_resched();
++ ext4_lock_group(sb, e4b->bd_group);
++ }
++
++ if ((e4b->bd_info->bb_free - free_count) < minblocks)
++ break;
++ }
++
++ return count;
++}
++
+ /**
+ * ext4_trim_all_free -- function to trim all free space in alloc. group
+ * @sb: super block for file system
+@@ -5217,10 +5265,8 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+ ext4_grpblk_t start, ext4_grpblk_t max,
+ ext4_grpblk_t minblocks)
+ {
+- void *bitmap;
+- ext4_grpblk_t next, count = 0, free_count = 0;
+ struct ext4_buddy e4b;
+- int ret = 0;
++ int ret;
+
+ trace_ext4_trim_all_free(sb, group, start, max);
+
+@@ -5230,57 +5276,23 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+ ret, group);
+ return ret;
+ }
+- bitmap = e4b.bd_bitmap;
+
+ ext4_lock_group(sb, group);
+- if (EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) &&
+- minblocks >= atomic_read(&EXT4_SB(sb)->s_last_trim_minblks))
+- goto out;
+-
+- start = (e4b.bd_info->bb_first_free > start) ?
+- e4b.bd_info->bb_first_free : start;
+-
+- while (start <= max) {
+- start = mb_find_next_zero_bit(bitmap, max + 1, start);
+- if (start > max)
+- break;
+- next = mb_find_next_bit(bitmap, max + 1, start);
+-
+- if ((next - start) >= minblocks) {
+- ret = ext4_trim_extent(sb, start, next - start, &e4b);
+- if (ret && ret != -EOPNOTSUPP)
+- break;
+- ret = 0;
+- count += next - start;
+- }
+- free_count += next - start;
+- start = next + 1;
+-
+- if (fatal_signal_pending(current)) {
+- count = -ERESTARTSYS;
+- break;
+- }
+-
+- if (need_resched()) {
+- ext4_unlock_group(sb, group);
+- cond_resched();
+- ext4_lock_group(sb, group);
+- }
+
+- if ((e4b.bd_info->bb_free - free_count) < minblocks)
+- break;
++ if (!EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) ||
++ minblocks < atomic_read(&EXT4_SB(sb)->s_last_trim_minblks)) {
++ ret = ext4_try_to_trim_range(sb, &e4b, start, max, minblocks);
++ if (ret >= 0)
++ EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info);
++ } else {
++ ret = 0;
+ }
+
+- if (!ret) {
+- ret = count;
+- EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info);
+- }
+-out:
+ ext4_unlock_group(sb, group);
+ ext4_mb_unload_buddy(&e4b);
+
+ ext4_debug("trimmed %d blocks in the group %d\n",
+- count, group);
++ ret, group);
+
+ return ret;
+ }
+--
+2.40.1
+
--- /dev/null
+From f61c0f0a239f3676490560e670a2bf4846bc5fb4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 3 Nov 2021 15:51:21 +0100
+Subject: ext4: change s_last_trim_minblks type to unsigned long
+
+From: Lukas Czerner <lczerner@redhat.com>
+
+[ Upstream commit 2327fb2e23416cfb2795ccca2f77d4d65925be99 ]
+
+There is no good reason for the s_last_trim_minblks to be atomic. There is
+no data integrity needed and there is no real danger in setting and
+reading it in a racy manner. Change it to be unsigned long, the same type
+as s_clusters_per_group which is the maximum that's allowed.
+
+Signed-off-by: Lukas Czerner <lczerner@redhat.com>
+Suggested-by: Andreas Dilger <adilger@dilger.ca>
+Reviewed-by: Andreas Dilger <adilger@dilger.ca>
+Link: https://lore.kernel.org/r/20211103145122.17338-1-lczerner@redhat.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/ext4.h | 2 +-
+ fs/ext4/mballoc.c | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index 604fef3b2ddf4..4d02116193de8 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -1529,7 +1529,7 @@ struct ext4_sb_info {
+ struct task_struct *s_mmp_tsk;
+
+ /* record the last minlen when FITRIM is called. */
+- atomic_t s_last_trim_minblks;
++ unsigned long s_last_trim_minblks;
+
+ /* Reference to checksum algorithm driver via cryptoapi */
+ struct crypto_shash *s_chksum_driver;
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index e1b487acb843b..db6bc24936479 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -5279,7 +5279,7 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+ ext4_lock_group(sb, group);
+
+ if (!EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) ||
+- minblocks < atomic_read(&EXT4_SB(sb)->s_last_trim_minblks)) {
++ minblocks < EXT4_SB(sb)->s_last_trim_minblks) {
+ ret = ext4_try_to_trim_range(sb, &e4b, start, max, minblocks);
+ if (ret >= 0)
+ EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info);
+@@ -5388,7 +5388,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+ }
+
+ if (!ret)
+- atomic_set(&EXT4_SB(sb)->s_last_trim_minblks, minlen);
++ EXT4_SB(sb)->s_last_trim_minblks = minlen;
+
+ out:
+ range->len = EXT4_C2B(EXT4_SB(sb), trimmed) << sb->s_blocksize_bits;
+--
+2.40.1
+
--- /dev/null
+From fe47badddc6ccda13c9071181111aa36fe67cf06 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Sep 2023 17:04:55 +0200
+Subject: ext4: do not let fstrim block system suspend
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 5229a658f6453362fbb9da6bf96872ef25a7097e ]
+
+Len Brown has reported that system suspend sometimes fail due to
+inability to freeze a task working in ext4_trim_fs() for one minute.
+Trimming a large filesystem on a disk that slowly processes discard
+requests can indeed take a long time. Since discard is just an advisory
+call, it is perfectly fine to interrupt it at any time and the return
+number of discarded blocks until that moment. Do that when we detect the
+task is being frozen.
+
+Cc: stable@kernel.org
+Reported-by: Len Brown <lenb@kernel.org>
+Suggested-by: Dave Chinner <david@fromorbit.com>
+References: https://bugzilla.kernel.org/show_bug.cgi?id=216322
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230913150504.9054-2-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/mballoc.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index 3632c7258e61a..9099e112fda5f 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -16,6 +16,7 @@
+ #include <linux/slab.h>
+ #include <linux/nospec.h>
+ #include <linux/backing-dev.h>
++#include <linux/freezer.h>
+ #include <trace/events/ext4.h>
+
+ #ifdef CONFIG_EXT4_DEBUG
+@@ -5204,6 +5205,11 @@ static ext4_grpblk_t ext4_last_grp_cluster(struct super_block *sb,
+ EXT4_CLUSTER_BITS(sb);
+ }
+
++static bool ext4_trim_interrupted(void)
++{
++ return fatal_signal_pending(current) || freezing(current);
++}
++
+ static int ext4_try_to_trim_range(struct super_block *sb,
+ struct ext4_buddy *e4b, ext4_grpblk_t start,
+ ext4_grpblk_t max, ext4_grpblk_t minblocks)
+@@ -5235,8 +5241,8 @@ static int ext4_try_to_trim_range(struct super_block *sb,
+ free_count += next - start;
+ start = next + 1;
+
+- if (fatal_signal_pending(current))
+- return -ERESTARTSYS;
++ if (ext4_trim_interrupted())
++ return count;
+
+ if (need_resched()) {
+ ext4_unlock_group(sb, e4b->bd_group);
+@@ -5363,6 +5369,8 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+ end = EXT4_CLUSTERS_PER_GROUP(sb) - 1;
+
+ for (group = first_group; group <= last_group; group++) {
++ if (ext4_trim_interrupted())
++ break;
+ grp = ext4_get_group_info(sb, group);
+ /* We only do this if the grp has never been initialized */
+ if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
+--
+2.40.1
+
--- /dev/null
+From e8cd80fe901e4991c8fdd9fdc9d391c8c5ca1dc9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 17 Apr 2022 20:03:15 +0300
+Subject: ext4: mark group as trimmed only if it was fully scanned
+
+From: Dmitry Monakhov <dmtrmonakhov@yandex-team.ru>
+
+[ Upstream commit d63c00ea435a5352f486c259665a4ced60399421 ]
+
+Otherwise nonaligned fstrim calls will works inconveniently for iterative
+scanners, for example:
+
+// trim [0,16MB] for group-1, but mark full group as trimmed
+fstrim -o $((1024*1024*128)) -l $((1024*1024*16)) ./m
+// handle [16MB,16MB] for group-1, do nothing because group already has the flag.
+fstrim -o $((1024*1024*144)) -l $((1024*1024*16)) ./m
+
+[ Update function documentation for ext4_trim_all_free -- TYT ]
+
+Signed-off-by: Dmitry Monakhov <dmtrmonakhov@yandex-team.ru>
+Link: https://lore.kernel.org/r/1650214995-860245-1-git-send-email-dmtrmonakhov@yandex-team.ru
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/mballoc.c | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index db6bc24936479..7cd2f2c07858f 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -5248,6 +5248,7 @@ static int ext4_try_to_trim_range(struct super_block *sb,
+ * @start: first group block to examine
+ * @max: last group block to examine
+ * @minblocks: minimum extent block count
++ * @set_trimmed: set the trimmed flag if at least one block is trimmed
+ *
+ * ext4_trim_all_free walks through group's buddy bitmap searching for free
+ * extents. When the free block is found, ext4_trim_extent is called to TRIM
+@@ -5262,7 +5263,7 @@ static int ext4_try_to_trim_range(struct super_block *sb,
+ static ext4_grpblk_t
+ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+ ext4_grpblk_t start, ext4_grpblk_t max,
+- ext4_grpblk_t minblocks)
++ ext4_grpblk_t minblocks, bool set_trimmed)
+ {
+ struct ext4_buddy e4b;
+ int ret;
+@@ -5281,7 +5282,7 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+ if (!EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) ||
+ minblocks < EXT4_SB(sb)->s_last_trim_minblks) {
+ ret = ext4_try_to_trim_range(sb, &e4b, start, max, minblocks);
+- if (ret >= 0)
++ if (ret >= 0 && set_trimmed)
+ EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info);
+ } else {
+ ret = 0;
+@@ -5318,6 +5319,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+ ext4_fsblk_t first_data_blk =
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
+ ext4_fsblk_t max_blks = ext4_blocks_count(EXT4_SB(sb)->s_es);
++ bool whole_group, eof = false;
+ int ret = 0;
+
+ start = range->start >> sb->s_blocksize_bits;
+@@ -5336,8 +5338,10 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+ if (minlen > EXT4_CLUSTERS_PER_GROUP(sb))
+ goto out;
+ }
+- if (end >= max_blks)
++ if (end >= max_blks - 1) {
+ end = max_blks - 1;
++ eof = true;
++ }
+ if (end <= first_data_blk)
+ goto out;
+ if (start < first_data_blk)
+@@ -5351,6 +5355,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+
+ /* end now represents the last cluster to discard in this group */
+ end = EXT4_CLUSTERS_PER_GROUP(sb) - 1;
++ whole_group = true;
+
+ for (group = first_group; group <= last_group; group++) {
+ grp = ext4_get_group_info(sb, group);
+@@ -5367,12 +5372,13 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+ * change it for the last group, note that last_cluster is
+ * already computed earlier by ext4_get_group_no_and_offset()
+ */
+- if (group == last_group)
++ if (group == last_group) {
+ end = last_cluster;
+-
++ whole_group = eof ? true : end == EXT4_CLUSTERS_PER_GROUP(sb) - 1;
++ }
+ if (grp->bb_free >= minlen) {
+ cnt = ext4_trim_all_free(sb, group, first_cluster,
+- end, minlen);
++ end, minlen, whole_group);
+ if (cnt < 0) {
+ ret = cnt;
+ break;
+--
+2.40.1
+
--- /dev/null
+From 87672535684374a902d65f7e8a760afd359acdd2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Sep 2023 17:04:54 +0200
+Subject: ext4: move setting of trimmed bit into ext4_try_to_trim_range()
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 45e4ab320c9b5fa67b1fc3b6a9b381cfcc0c8488 ]
+
+Currently we set the group's trimmed bit in ext4_trim_all_free() based
+on return value of ext4_try_to_trim_range(). However when we will want
+to abort trimming because of suspend attempt, we want to return success
+from ext4_try_to_trim_range() but not set the trimmed bit. Instead
+implementing awkward propagation of this information, just move setting
+of trimmed bit into ext4_try_to_trim_range() when the whole group is
+trimmed.
+
+Cc: stable@kernel.org
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230913150504.9054-1-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/mballoc.c | 46 +++++++++++++++++++++++++---------------------
+ 1 file changed, 25 insertions(+), 21 deletions(-)
+
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index 412d2f6a0b91c..3632c7258e61a 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -5194,14 +5194,27 @@ __acquires(bitlock)
+ return ret;
+ }
+
++static ext4_grpblk_t ext4_last_grp_cluster(struct super_block *sb,
++ ext4_group_t grp)
++{
++ if (grp < ext4_get_groups_count(sb))
++ return EXT4_CLUSTERS_PER_GROUP(sb) - 1;
++ return (ext4_blocks_count(EXT4_SB(sb)->s_es) -
++ ext4_group_first_block_no(sb, grp) - 1) >>
++ EXT4_CLUSTER_BITS(sb);
++}
++
+ static int ext4_try_to_trim_range(struct super_block *sb,
+ struct ext4_buddy *e4b, ext4_grpblk_t start,
+ ext4_grpblk_t max, ext4_grpblk_t minblocks)
+ {
+ ext4_grpblk_t next, count, free_count;
++ bool set_trimmed = false;
+ void *bitmap;
+
+ bitmap = e4b->bd_bitmap;
++ if (start == 0 && max >= ext4_last_grp_cluster(sb, e4b->bd_group))
++ set_trimmed = true;
+ start = max(e4b->bd_info->bb_first_free, start);
+ count = 0;
+ free_count = 0;
+@@ -5216,16 +5229,14 @@ static int ext4_try_to_trim_range(struct super_block *sb,
+ int ret = ext4_trim_extent(sb, start, next - start, e4b);
+
+ if (ret && ret != -EOPNOTSUPP)
+- break;
++ return count;
+ count += next - start;
+ }
+ free_count += next - start;
+ start = next + 1;
+
+- if (fatal_signal_pending(current)) {
+- count = -ERESTARTSYS;
+- break;
+- }
++ if (fatal_signal_pending(current))
++ return -ERESTARTSYS;
+
+ if (need_resched()) {
+ ext4_unlock_group(sb, e4b->bd_group);
+@@ -5237,6 +5248,9 @@ static int ext4_try_to_trim_range(struct super_block *sb,
+ break;
+ }
+
++ if (set_trimmed)
++ EXT4_MB_GRP_SET_TRIMMED(e4b->bd_info);
++
+ return count;
+ }
+
+@@ -5247,7 +5261,6 @@ static int ext4_try_to_trim_range(struct super_block *sb,
+ * @start: first group block to examine
+ * @max: last group block to examine
+ * @minblocks: minimum extent block count
+- * @set_trimmed: set the trimmed flag if at least one block is trimmed
+ *
+ * ext4_trim_all_free walks through group's buddy bitmap searching for free
+ * extents. When the free block is found, ext4_trim_extent is called to TRIM
+@@ -5262,7 +5275,7 @@ static int ext4_try_to_trim_range(struct super_block *sb,
+ static ext4_grpblk_t
+ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+ ext4_grpblk_t start, ext4_grpblk_t max,
+- ext4_grpblk_t minblocks, bool set_trimmed)
++ ext4_grpblk_t minblocks)
+ {
+ struct ext4_buddy e4b;
+ int ret;
+@@ -5279,13 +5292,10 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+ ext4_lock_group(sb, group);
+
+ if (!EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) ||
+- minblocks < EXT4_SB(sb)->s_last_trim_minblks) {
++ minblocks < EXT4_SB(sb)->s_last_trim_minblks)
+ ret = ext4_try_to_trim_range(sb, &e4b, start, max, minblocks);
+- if (ret >= 0 && set_trimmed)
+- EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info);
+- } else {
++ else
+ ret = 0;
+- }
+
+ ext4_unlock_group(sb, group);
+ ext4_mb_unload_buddy(&e4b);
+@@ -5318,7 +5328,6 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+ ext4_fsblk_t first_data_blk =
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
+ ext4_fsblk_t max_blks = ext4_blocks_count(EXT4_SB(sb)->s_es);
+- bool whole_group, eof = false;
+ int ret = 0;
+
+ start = range->start >> sb->s_blocksize_bits;
+@@ -5337,10 +5346,8 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+ if (minlen > EXT4_CLUSTERS_PER_GROUP(sb))
+ goto out;
+ }
+- if (end >= max_blks - 1) {
++ if (end >= max_blks - 1)
+ end = max_blks - 1;
+- eof = true;
+- }
+ if (end <= first_data_blk)
+ goto out;
+ if (start < first_data_blk)
+@@ -5354,7 +5361,6 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+
+ /* end now represents the last cluster to discard in this group */
+ end = EXT4_CLUSTERS_PER_GROUP(sb) - 1;
+- whole_group = true;
+
+ for (group = first_group; group <= last_group; group++) {
+ grp = ext4_get_group_info(sb, group);
+@@ -5371,13 +5377,11 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
+ * change it for the last group, note that last_cluster is
+ * already computed earlier by ext4_get_group_no_and_offset()
+ */
+- if (group == last_group) {
++ if (group == last_group)
+ end = last_cluster;
+- whole_group = eof ? true : end == EXT4_CLUSTERS_PER_GROUP(sb) - 1;
+- }
+ if (grp->bb_free >= minlen) {
+ cnt = ext4_trim_all_free(sb, group, first_cluster,
+- end, minlen, whole_group);
++ end, minlen);
+ if (cnt < 0) {
+ ret = cnt;
+ break;
+--
+2.40.1
+
--- /dev/null
+From 9a6ffc589a28a4d7cc6ffb628919f3d59b6b1e0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 24 Jul 2021 15:41:20 +0800
+Subject: ext4: remove the 'group' parameter of ext4_trim_extent
+
+From: Wang Jianchao <wangjianchao@kuaishou.com>
+
+[ Upstream commit bd2eea8d0a6b6a9aca22f20bf74f73b71d8808af ]
+
+Get rid of the 'group' parameter of ext4_trim_extent as we can get
+it from the 'e4b'.
+
+Reviewed-by: Andreas Dilger <adilger@dilger.ca>
+Signed-off-by: Wang Jianchao <wangjianchao@kuaishou.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20210724074124.25731-2-jianchao.wan9@gmail.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/mballoc.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index be5c2e53b636e..9b4af51c99da4 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -5159,19 +5159,19 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
+ * @sb: super block for the file system
+ * @start: starting block of the free extent in the alloc. group
+ * @count: number of blocks to TRIM
+- * @group: alloc. group we are working with
+ * @e4b: ext4 buddy for the group
+ *
+ * Trim "count" blocks starting at "start" in the "group". To assure that no
+ * one will allocate those blocks, mark it as used in buddy bitmap. This must
+ * be called with under the group lock.
+ */
+-static int ext4_trim_extent(struct super_block *sb, int start, int count,
+- ext4_group_t group, struct ext4_buddy *e4b)
++static int ext4_trim_extent(struct super_block *sb,
++ int start, int count, struct ext4_buddy *e4b)
+ __releases(bitlock)
+ __acquires(bitlock)
+ {
+ struct ext4_free_extent ex;
++ ext4_group_t group = e4b->bd_group;
+ int ret = 0;
+
+ trace_ext4_trim_extent(sb, group, start, count);
+@@ -5247,8 +5247,7 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
+ next = mb_find_next_bit(bitmap, max + 1, start);
+
+ if ((next - start) >= minblocks) {
+- ret = ext4_trim_extent(sb, start,
+- next - start, group, &e4b);
++ ret = ext4_trim_extent(sb, start, next - start, &e4b);
+ if (ret && ret != -EOPNOTSUPP)
+ break;
+ ret = 0;
+--
+2.40.1
+
--- /dev/null
+From 974f7ca85f3405647006812a63ba661df14aef59 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 1 Aug 2023 22:32:00 +0800
+Subject: ext4: replace the traditional ternary conditional operator with with
+ max()/min()
+
+From: Kemeng Shi <shikemeng@huaweicloud.com>
+
+[ Upstream commit de8bf0e5ee7482585450357c6d4eddec8efc5cb7 ]
+
+Replace the traditional ternary conditional operator with with max()/min()
+
+Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
+Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
+Link: https://lore.kernel.org/r/20230801143204.2284343-7-shikemeng@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/mballoc.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index 7cd2f2c07858f..412d2f6a0b91c 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -5202,8 +5202,7 @@ static int ext4_try_to_trim_range(struct super_block *sb,
+ void *bitmap;
+
+ bitmap = e4b->bd_bitmap;
+- start = (e4b->bd_info->bb_first_free > start) ?
+- e4b->bd_info->bb_first_free : start;
++ start = max(e4b->bd_info->bb_first_free, start);
+ count = 0;
+ free_count = 0;
+
+@@ -5423,8 +5422,7 @@ ext4_mballoc_query_range(
+
+ ext4_lock_group(sb, group);
+
+- start = (e4b.bd_info->bb_first_free > start) ?
+- e4b.bd_info->bb_first_free : start;
++ start = max(e4b.bd_info->bb_first_free, start);
+ if (end >= EXT4_CLUSTERS_PER_GROUP(sb))
+ end = EXT4_CLUSTERS_PER_GROUP(sb) - 1;
+
+--
+2.40.1
+
--- /dev/null
+From 01557b3c84e54b7a3e68e98c39913cb475c04d37 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Aug 2021 14:08:53 +0200
+Subject: ext4: scope ret locally in ext4_try_to_trim_range()
+
+From: Lukas Bulwahn <lukas.bulwahn@gmail.com>
+
+[ Upstream commit afcc4e32f606dbfb47aa7309172c89174b86e74c ]
+
+As commit 6920b3913235 ("ext4: add new helper interface
+ext4_try_to_trim_range()") moves some code into the separate function
+ext4_try_to_trim_range(), the use of the variable ret within that
+function is more limited and can be adjusted as well.
+
+Scope the use of the variable ret locally and drop dead assignments.
+
+No functional change.
+
+Signed-off-by: Lukas Bulwahn <lukas.bulwahn@gmail.com>
+Link: https://lore.kernel.org/r/20210820120853.23134-1-lukas.bulwahn@gmail.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/mballoc.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index 5a7fe5aa0fc38..e1b487acb843b 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -5200,7 +5200,6 @@ static int ext4_try_to_trim_range(struct super_block *sb,
+ {
+ ext4_grpblk_t next, count, free_count;
+ void *bitmap;
+- int ret = 0;
+
+ bitmap = e4b->bd_bitmap;
+ start = (e4b->bd_info->bb_first_free > start) ?
+@@ -5215,10 +5214,10 @@ static int ext4_try_to_trim_range(struct super_block *sb,
+ next = mb_find_next_bit(bitmap, max + 1, start);
+
+ if ((next - start) >= minblocks) {
+- ret = ext4_trim_extent(sb, start, next - start, e4b);
++ int ret = ext4_trim_extent(sb, start, next - start, e4b);
++
+ if (ret && ret != -EOPNOTSUPP)
+ break;
+- ret = 0;
+ count += next - start;
+ }
+ free_count += next - start;
+--
+2.40.1
+
--- /dev/null
+From 58eff839f8cdafbff1c3a87ab311b27d99c986d4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Sep 2023 12:43:58 -0400
+Subject: NFS/pNFS: Report EINVAL errors from connect() to the server
+
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+
+[ Upstream commit dd7d7ee3ba2a70d12d02defb478790cf57d5b87b ]
+
+With IPv6, connect() can occasionally return EINVAL if a route is
+unavailable. If this happens during I/O to a data server, we want to
+report it using LAYOUTERROR as an inability to connect.
+
+Fixes: dd52128afdde ("NFSv4.1/pnfs Ensure flexfiles reports all connection related errors")
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/flexfilelayout/flexfilelayout.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
+index fa1c920afb494..1b88b78f40bea 100644
+--- a/fs/nfs/flexfilelayout/flexfilelayout.c
++++ b/fs/nfs/flexfilelayout/flexfilelayout.c
+@@ -1280,6 +1280,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
+ case -EPFNOSUPPORT:
+ case -EPROTONOSUPPORT:
+ case -EOPNOTSUPP:
++ case -EINVAL:
+ case -ECONNREFUSED:
+ case -ECONNRESET:
+ case -EHOSTDOWN:
+--
+2.40.1
+
--- /dev/null
+nfs-pnfs-report-einval-errors-from-connect-to-the-se.patch
+sunrpc-mark-the-cred-for-revalidation-if-the-server-.patch
+tracing-increase-trace-array-ref-count-on-enable-and.patch
+ata-libahci-clear-pending-interrupt-status.patch
+ext4-remove-the-group-parameter-of-ext4_trim_extent.patch
+ext4-add-new-helper-interface-ext4_try_to_trim_range.patch
+ext4-scope-ret-locally-in-ext4_try_to_trim_range.patch
+ext4-change-s_last_trim_minblks-type-to-unsigned-lon.patch
+ext4-mark-group-as-trimmed-only-if-it-was-fully-scan.patch
+ext4-replace-the-traditional-ternary-conditional-ope.patch
+ext4-move-setting-of-trimmed-bit-into-ext4_try_to_tr.patch
+ext4-do-not-let-fstrim-block-system-suspend.patch
--- /dev/null
+From 8c7bb8773cc79f8707c23dc44d355d5b88380489 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Sep 2023 12:50:09 -0400
+Subject: SUNRPC: Mark the cred for revalidation if the server rejects it
+
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+
+[ Upstream commit 611fa42dfa9d2f3918ac5f4dd5705dfad81b323d ]
+
+If the server rejects the credential as being stale, or bad, then we
+should mark it for revalidation before retransmitting.
+
+Fixes: 7f5667a5f8c4 ("SUNRPC: Clean up rpc_verify_header()")
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sunrpc/clnt.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
+index 629c05ff1f3e6..9071dc6928ac2 100644
+--- a/net/sunrpc/clnt.c
++++ b/net/sunrpc/clnt.c
+@@ -2684,6 +2684,7 @@ rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr)
+ case rpc_autherr_rejectedverf:
+ case rpcsec_gsserr_credproblem:
+ case rpcsec_gsserr_ctxproblem:
++ rpcauth_invalcred(task);
+ if (!task->tk_cred_retry)
+ break;
+ task->tk_cred_retry--;
+--
+2.40.1
+
--- /dev/null
+From 66f424e3596f3f04a6f7939dc01261bfd5c6401f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 6 Sep 2023 22:47:12 -0400
+Subject: tracing: Increase trace array ref count on enable and filter files
+
+From: Steven Rostedt (Google) <rostedt@goodmis.org>
+
+[ Upstream commit f5ca233e2e66dc1c249bf07eefa37e34a6c9346a ]
+
+When the trace event enable and filter files are opened, increment the
+trace array ref counter, otherwise they can be accessed when the trace
+array is being deleted. The ref counter keeps the trace array from being
+deleted while those files are opened.
+
+Link: https://lkml.kernel.org/r/20230907024803.456187066@goodmis.org
+Link: https://lore.kernel.org/all/1cb3aee2-19af-c472-e265-05176fe9bd84@huawei.com/
+
+Cc: stable@vger.kernel.org
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Fixes: 8530dec63e7b4 ("tracing: Add tracing_check_open_get_tr()")
+Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
+Tested-by: Naresh Kamboju <naresh.kamboju@linaro.org>
+Reported-by: Zheng Yejian <zhengyejian1@huawei.com>
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace.c | 27 +++++++++++++++++++++++++++
+ kernel/trace/trace.h | 2 ++
+ kernel/trace/trace_events.c | 6 ++++--
+ 3 files changed, 33 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
+index f9c64329ec154..85ad403006a20 100644
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -4244,6 +4244,33 @@ int tracing_open_generic_tr(struct inode *inode, struct file *filp)
+ return 0;
+ }
+
++/*
++ * The private pointer of the inode is the trace_event_file.
++ * Update the tr ref count associated to it.
++ */
++int tracing_open_file_tr(struct inode *inode, struct file *filp)
++{
++ struct trace_event_file *file = inode->i_private;
++ int ret;
++
++ ret = tracing_check_open_get_tr(file->tr);
++ if (ret)
++ return ret;
++
++ filp->private_data = inode->i_private;
++
++ return 0;
++}
++
++int tracing_release_file_tr(struct inode *inode, struct file *filp)
++{
++ struct trace_event_file *file = inode->i_private;
++
++ trace_array_put(file->tr);
++
++ return 0;
++}
++
+ static int tracing_release(struct inode *inode, struct file *file)
+ {
+ struct trace_array *tr = inode->i_private;
+diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
+index 21f85c0bd66ec..f1f54111b8561 100644
+--- a/kernel/trace/trace.h
++++ b/kernel/trace/trace.h
+@@ -680,6 +680,8 @@ void tracing_reset_all_online_cpus(void);
+ void tracing_reset_all_online_cpus_unlocked(void);
+ int tracing_open_generic(struct inode *inode, struct file *filp);
+ int tracing_open_generic_tr(struct inode *inode, struct file *filp);
++int tracing_open_file_tr(struct inode *inode, struct file *filp);
++int tracing_release_file_tr(struct inode *inode, struct file *filp);
+ bool tracing_is_disabled(void);
+ bool tracer_tracing_is_on(struct trace_array *tr);
+ void tracer_tracing_on(struct trace_array *tr);
+diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
+index 0c21da12b650c..51adf0817ef3a 100644
+--- a/kernel/trace/trace_events.c
++++ b/kernel/trace/trace_events.c
+@@ -1699,9 +1699,10 @@ static const struct file_operations ftrace_set_event_pid_fops = {
+ };
+
+ static const struct file_operations ftrace_enable_fops = {
+- .open = tracing_open_generic,
++ .open = tracing_open_file_tr,
+ .read = event_enable_read,
+ .write = event_enable_write,
++ .release = tracing_release_file_tr,
+ .llseek = default_llseek,
+ };
+
+@@ -1718,9 +1719,10 @@ static const struct file_operations ftrace_event_id_fops = {
+ };
+
+ static const struct file_operations ftrace_event_filter_fops = {
+- .open = tracing_open_generic,
++ .open = tracing_open_file_tr,
+ .read = event_filter_read,
+ .write = event_filter_write,
++ .release = tracing_release_file_tr,
+ .llseek = default_llseek,
+ };
+
+--
+2.40.1
+