From: Sasha Levin Date: Sat, 23 Sep 2023 12:16:17 +0000 (-0400) Subject: Fixes for 5.4 X-Git-Tag: v6.5.6~111 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=df9dc26fedcec31eb9a7aa447dde400378b65792;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.4 Signed-off-by: Sasha Levin --- diff --git a/queue-5.4/ata-libahci-clear-pending-interrupt-status.patch b/queue-5.4/ata-libahci-clear-pending-interrupt-status.patch new file mode 100644 index 00000000000..9acb5ce1257 --- /dev/null +++ b/queue-5.4/ata-libahci-clear-pending-interrupt-status.patch @@ -0,0 +1,101 @@ +From fe1e257c1f458f5eace878a81ac558452b3dd73b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 Sep 2023 16:17:10 +0800 +Subject: ata: libahci: clear pending interrupt status + +From: Szuying Chen + +[ 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 +Fixes: e0bfd149973d ("[PATCH] ahci: stop engine during hard reset") +Cc: stable@vger.kernel.org +Reviewed-by: Niklas Cassel +Signed-off-by: Damien Le Moal +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.4/ext4-add-new-helper-interface-ext4_try_to_trim_range.patch b/queue-5.4/ext4-add-new-helper-interface-ext4_try_to_trim_range.patch new file mode 100644 index 00000000000..aa35085fdcd --- /dev/null +++ b/queue-5.4/ext4-add-new-helper-interface-ext4_try_to_trim_range.patch @@ -0,0 +1,165 @@ +From c007fb7d5b2bde9e8aee464d9e2c8ce61956e8c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jul 2021 15:41:21 +0800 +Subject: ext4: add new helper interface ext4_try_to_trim_range() + +From: Wang Jianchao + +[ 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 +Signed-off-by: Wang Jianchao +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20210724074124.25731-3-jianchao.wan9@gmail.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.4/ext4-change-s_last_trim_minblks-type-to-unsigned-lon.patch b/queue-5.4/ext4-change-s_last_trim_minblks-type-to-unsigned-lon.patch new file mode 100644 index 00000000000..aeb39faa967 --- /dev/null +++ b/queue-5.4/ext4-change-s_last_trim_minblks-type-to-unsigned-lon.patch @@ -0,0 +1,64 @@ +From f61c0f0a239f3676490560e670a2bf4846bc5fb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Nov 2021 15:51:21 +0100 +Subject: ext4: change s_last_trim_minblks type to unsigned long + +From: Lukas Czerner + +[ 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 +Suggested-by: Andreas Dilger +Reviewed-by: Andreas Dilger +Link: https://lore.kernel.org/r/20211103145122.17338-1-lczerner@redhat.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.4/ext4-do-not-let-fstrim-block-system-suspend.patch b/queue-5.4/ext4-do-not-let-fstrim-block-system-suspend.patch new file mode 100644 index 00000000000..b7aca95f696 --- /dev/null +++ b/queue-5.4/ext4-do-not-let-fstrim-block-system-suspend.patch @@ -0,0 +1,76 @@ +From fe47badddc6ccda13c9071181111aa36fe67cf06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Sep 2023 17:04:55 +0200 +Subject: ext4: do not let fstrim block system suspend + +From: Jan Kara + +[ 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 +Suggested-by: Dave Chinner +References: https://bugzilla.kernel.org/show_bug.cgi?id=216322 +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20230913150504.9054-2-jack@suse.cz +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + + #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 + diff --git a/queue-5.4/ext4-mark-group-as-trimmed-only-if-it-was-fully-scan.patch b/queue-5.4/ext4-mark-group-as-trimmed-only-if-it-was-fully-scan.patch new file mode 100644 index 00000000000..ecbce385305 --- /dev/null +++ b/queue-5.4/ext4-mark-group-as-trimmed-only-if-it-was-fully-scan.patch @@ -0,0 +1,107 @@ +From e8cd80fe901e4991c8fdd9fdc9d391c8c5ca1dc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 17 Apr 2022 20:03:15 +0300 +Subject: ext4: mark group as trimmed only if it was fully scanned + +From: Dmitry Monakhov + +[ 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 +Link: https://lore.kernel.org/r/1650214995-860245-1-git-send-email-dmtrmonakhov@yandex-team.ru +Signed-off-by: Theodore Ts'o +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 +--- + 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 + diff --git a/queue-5.4/ext4-move-setting-of-trimmed-bit-into-ext4_try_to_tr.patch b/queue-5.4/ext4-move-setting-of-trimmed-bit-into-ext4_try_to_tr.patch new file mode 100644 index 00000000000..470803df705 --- /dev/null +++ b/queue-5.4/ext4-move-setting-of-trimmed-bit-into-ext4_try_to_tr.patch @@ -0,0 +1,168 @@ +From 87672535684374a902d65f7e8a760afd359acdd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://lore.kernel.org/r/20230913150504.9054-1-jack@suse.cz +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.4/ext4-remove-the-group-parameter-of-ext4_trim_extent.patch b/queue-5.4/ext4-remove-the-group-parameter-of-ext4_trim_extent.patch new file mode 100644 index 00000000000..efb5453d2ff --- /dev/null +++ b/queue-5.4/ext4-remove-the-group-parameter-of-ext4_trim_extent.patch @@ -0,0 +1,63 @@ +From 9a6ffc589a28a4d7cc6ffb628919f3d59b6b1e0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jul 2021 15:41:20 +0800 +Subject: ext4: remove the 'group' parameter of ext4_trim_extent + +From: Wang Jianchao + +[ 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 +Signed-off-by: Wang Jianchao +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20210724074124.25731-2-jianchao.wan9@gmail.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.4/ext4-replace-the-traditional-ternary-conditional-ope.patch b/queue-5.4/ext4-replace-the-traditional-ternary-conditional-ope.patch new file mode 100644 index 00000000000..8c93a0a04b4 --- /dev/null +++ b/queue-5.4/ext4-replace-the-traditional-ternary-conditional-ope.patch @@ -0,0 +1,49 @@ +From 974f7ca85f3405647006812a63ba661df14aef59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Aug 2023 22:32:00 +0800 +Subject: ext4: replace the traditional ternary conditional operator with with + max()/min() + +From: Kemeng Shi + +[ Upstream commit de8bf0e5ee7482585450357c6d4eddec8efc5cb7 ] + +Replace the traditional ternary conditional operator with with max()/min() + +Signed-off-by: Kemeng Shi +Reviewed-by: Ritesh Harjani (IBM) +Link: https://lore.kernel.org/r/20230801143204.2284343-7-shikemeng@huaweicloud.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.4/ext4-scope-ret-locally-in-ext4_try_to_trim_range.patch b/queue-5.4/ext4-scope-ret-locally-in-ext4_try_to_trim_range.patch new file mode 100644 index 00000000000..0b728c0a428 --- /dev/null +++ b/queue-5.4/ext4-scope-ret-locally-in-ext4_try_to_trim_range.patch @@ -0,0 +1,55 @@ +From 01557b3c84e54b7a3e68e98c39913cb475c04d37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Aug 2021 14:08:53 +0200 +Subject: ext4: scope ret locally in ext4_try_to_trim_range() + +From: Lukas Bulwahn + +[ 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 +Link: https://lore.kernel.org/r/20210820120853.23134-1-lukas.bulwahn@gmail.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.4/nfs-pnfs-report-einval-errors-from-connect-to-the-se.patch b/queue-5.4/nfs-pnfs-report-einval-errors-from-connect-to-the-se.patch new file mode 100644 index 00000000000..e026cf1f824 --- /dev/null +++ b/queue-5.4/nfs-pnfs-report-einval-errors-from-connect-to-the-se.patch @@ -0,0 +1,36 @@ +From 58eff839f8cdafbff1c3a87ab311b27d99c986d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 Sep 2023 12:43:58 -0400 +Subject: NFS/pNFS: Report EINVAL errors from connect() to the server + +From: Trond Myklebust + +[ 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 +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.4/series b/queue-5.4/series new file mode 100644 index 00000000000..e3d15ae88c5 --- /dev/null +++ b/queue-5.4/series @@ -0,0 +1,12 @@ +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 diff --git a/queue-5.4/sunrpc-mark-the-cred-for-revalidation-if-the-server-.patch b/queue-5.4/sunrpc-mark-the-cred-for-revalidation-if-the-server-.patch new file mode 100644 index 00000000000..6f36bc524ef --- /dev/null +++ b/queue-5.4/sunrpc-mark-the-cred-for-revalidation-if-the-server-.patch @@ -0,0 +1,35 @@ +From 8c7bb8773cc79f8707c23dc44d355d5b88380489 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 Sep 2023 12:50:09 -0400 +Subject: SUNRPC: Mark the cred for revalidation if the server rejects it + +From: Trond Myklebust + +[ 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 +Signed-off-by: Anna Schumaker +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.4/tracing-increase-trace-array-ref-count-on-enable-and.patch b/queue-5.4/tracing-increase-trace-array-ref-count-on-enable-and.patch new file mode 100644 index 00000000000..6c5b86d2b5c --- /dev/null +++ b/queue-5.4/tracing-increase-trace-array-ref-count-on-enable-and.patch @@ -0,0 +1,115 @@ +From 66f424e3596f3f04a6f7939dc01261bfd5c6401f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) + +[ 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 +Cc: Mark Rutland +Cc: Andrew Morton +Fixes: 8530dec63e7b4 ("tracing: Add tracing_check_open_get_tr()") +Tested-by: Linux Kernel Functional Testing +Tested-by: Naresh Kamboju +Reported-by: Zheng Yejian +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + 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 +