+++ /dev/null
-From b756a018ae344b7a50133eec86185342030b7e89 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 6 Jun 2023 21:59:27 +0800
-Subject: jbd2: fix a race when checking checkpoint buffer busy
-
-From: Zhang Yi <yi.zhang@huawei.com>
-
-[ Upstream commit 46f881b5b1758dc4a35fba4a643c10717d0cf427 ]
-
-Before removing checkpoint buffer from the t_checkpoint_list, we have to
-check both BH_Dirty and BH_Lock bits together to distinguish buffers
-have not been or were being written back. But __cp_buffer_busy() checks
-them separately, it first check lock state and then check dirty, the
-window between these two checks could be raced by writing back
-procedure, which locks buffer and clears buffer dirty before I/O
-completes. So it cannot guarantee checkpointing buffers been written
-back to disk if some error happens later. Finally, it may clean
-checkpoint transactions and lead to inconsistent filesystem.
-
-jbd2_journal_forget() and __journal_try_to_free_buffer() also have the
-same problem (journal_unmap_buffer() escape from this issue since it's
-running under the buffer lock), so fix them through introducing a new
-helper to try holding the buffer lock and remove really clean buffer.
-
-Link: https://bugzilla.kernel.org/show_bug.cgi?id=217490
-Cc: stable@vger.kernel.org
-Suggested-by: Jan Kara <jack@suse.cz>
-Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Link: https://lore.kernel.org/r/20230606135928.434610-6-yi.zhang@huaweicloud.com
-Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/jbd2/checkpoint.c | 38 +++++++++++++++++++++++++++++++++++---
- fs/jbd2/transaction.c | 17 +++++------------
- include/linux/jbd2.h | 1 +
- 3 files changed, 41 insertions(+), 15 deletions(-)
-
-diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
-index ab72aeb766a74..fc6989e7a8c51 100644
---- a/fs/jbd2/checkpoint.c
-+++ b/fs/jbd2/checkpoint.c
-@@ -376,11 +376,15 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
- jh = next_jh;
- next_jh = jh->b_cpnext;
-
-- if (!destroy && __cp_buffer_busy(jh))
-- continue;
-+ if (destroy) {
-+ ret = __jbd2_journal_remove_checkpoint(jh);
-+ } else {
-+ ret = jbd2_journal_try_remove_checkpoint(jh);
-+ if (ret < 0)
-+ continue;
-+ }
-
- nr_freed++;
-- ret = __jbd2_journal_remove_checkpoint(jh);
- if (ret) {
- *released = true;
- break;
-@@ -616,6 +620,34 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
- return 1;
- }
-
-+/*
-+ * Check the checkpoint buffer and try to remove it from the checkpoint
-+ * list if it's clean. Returns -EBUSY if it is not clean, returns 1 if
-+ * it frees the transaction, 0 otherwise.
-+ *
-+ * This function is called with j_list_lock held.
-+ */
-+int jbd2_journal_try_remove_checkpoint(struct journal_head *jh)
-+{
-+ struct buffer_head *bh = jh2bh(jh);
-+
-+ if (!trylock_buffer(bh))
-+ return -EBUSY;
-+ if (buffer_dirty(bh)) {
-+ unlock_buffer(bh);
-+ return -EBUSY;
-+ }
-+ unlock_buffer(bh);
-+
-+ /*
-+ * Buffer is clean and the IO has finished (we held the buffer
-+ * lock) so the checkpoint is done. We can safely remove the
-+ * buffer from this transaction.
-+ */
-+ JBUFFER_TRACE(jh, "remove from checkpoint list");
-+ return __jbd2_journal_remove_checkpoint(jh);
-+}
-+
- /*
- * journal_insert_checkpoint: put a committed buffer onto a checkpoint
- * list so that we know when it is safe to clean the transaction out of
-diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
-index ce4a5ccadeff4..62e68c5b8ec3d 100644
---- a/fs/jbd2/transaction.c
-+++ b/fs/jbd2/transaction.c
-@@ -1775,8 +1775,7 @@ int jbd2_journal_forget(handle_t *handle, struct buffer_head *bh)
- * Otherwise, if the buffer has been written to disk,
- * it is safe to remove the checkpoint and drop it.
- */
-- if (!buffer_dirty(bh)) {
-- __jbd2_journal_remove_checkpoint(jh);
-+ if (jbd2_journal_try_remove_checkpoint(jh) >= 0) {
- spin_unlock(&journal->j_list_lock);
- goto drop;
- }
-@@ -2103,20 +2102,14 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
-
- jh = bh2jh(bh);
-
-- if (buffer_locked(bh) || buffer_dirty(bh))
-- goto out;
--
- if (jh->b_next_transaction != NULL || jh->b_transaction != NULL)
-- goto out;
-+ return;
-
- spin_lock(&journal->j_list_lock);
-- if (jh->b_cp_transaction != NULL) {
-- /* written-back checkpointed metadata buffer */
-- JBUFFER_TRACE(jh, "remove from checkpoint list");
-- __jbd2_journal_remove_checkpoint(jh);
-- }
-+ /* Remove written-back checkpointed metadata buffer */
-+ if (jh->b_cp_transaction != NULL)
-+ jbd2_journal_try_remove_checkpoint(jh);
- spin_unlock(&journal->j_list_lock);
--out:
- return;
- }
-
-diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
-index e6cfbcde96f29..ade8a6d7acff9 100644
---- a/include/linux/jbd2.h
-+++ b/include/linux/jbd2.h
-@@ -1441,6 +1441,7 @@ extern void jbd2_journal_commit_transaction(journal_t *);
- void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy);
- unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal, unsigned long *nr_to_scan);
- int __jbd2_journal_remove_checkpoint(struct journal_head *);
-+int jbd2_journal_try_remove_checkpoint(struct journal_head *jh);
- void jbd2_journal_destroy_checkpoint(journal_t *journal);
- void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *);
-
---
-2.39.2
-
+++ /dev/null
-From aecb975234f28cd552c2716b840cb4df901d3027 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 6 Jun 2023 21:59:25 +0800
-Subject: jbd2: remove journal_clean_one_cp_list()
-
-From: Zhang Yi <yi.zhang@huawei.com>
-
-[ Upstream commit b98dba273a0e47dbfade89c9af73c5b012a4eabb ]
-
-journal_clean_one_cp_list() and journal_shrink_one_cp_list() are almost
-the same, so merge them into journal_shrink_one_cp_list(), remove the
-nr_to_scan parameter, always scan and try to free the whole checkpoint
-list.
-
-Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Link: https://lore.kernel.org/r/20230606135928.434610-4-yi.zhang@huaweicloud.com
-Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-Stable-dep-of: 46f881b5b175 ("jbd2: fix a race when checking checkpoint buffer busy")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/jbd2/checkpoint.c | 75 +++++++++----------------------------
- include/trace/events/jbd2.h | 12 ++----
- 2 files changed, 21 insertions(+), 66 deletions(-)
-
-diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
-index c1f543e86170a..ab72aeb766a74 100644
---- a/fs/jbd2/checkpoint.c
-+++ b/fs/jbd2/checkpoint.c
-@@ -349,50 +349,10 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
-
- /* Checkpoint list management */
-
--/*
-- * journal_clean_one_cp_list
-- *
-- * Find all the written-back checkpoint buffers in the given list and
-- * release them. If 'destroy' is set, clean all buffers unconditionally.
-- *
-- * Called with j_list_lock held.
-- * Returns 1 if we freed the transaction, 0 otherwise.
-- */
--static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
--{
-- struct journal_head *last_jh;
-- struct journal_head *next_jh = jh;
--
-- if (!jh)
-- return 0;
--
-- last_jh = jh->b_cpprev;
-- do {
-- jh = next_jh;
-- next_jh = jh->b_cpnext;
--
-- if (!destroy && __cp_buffer_busy(jh))
-- return 0;
--
-- if (__jbd2_journal_remove_checkpoint(jh))
-- return 1;
-- /*
-- * This function only frees up some memory
-- * if possible so we dont have an obligation
-- * to finish processing. Bail out if preemption
-- * requested:
-- */
-- if (need_resched())
-- return 0;
-- } while (jh != last_jh);
--
-- return 0;
--}
--
- /*
- * journal_shrink_one_cp_list
- *
-- * Find 'nr_to_scan' written-back checkpoint buffers in the given list
-+ * Find all the written-back checkpoint buffers in the given list
- * and try to release them. If the whole transaction is released, set
- * the 'released' parameter. Return the number of released checkpointed
- * buffers.
-@@ -400,15 +360,15 @@ static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
- * Called with j_list_lock held.
- */
- static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
-- unsigned long *nr_to_scan,
-- bool *released)
-+ bool destroy, bool *released)
- {
- struct journal_head *last_jh;
- struct journal_head *next_jh = jh;
- unsigned long nr_freed = 0;
- int ret;
-
-- if (!jh || *nr_to_scan == 0)
-+ *released = false;
-+ if (!jh)
- return 0;
-
- last_jh = jh->b_cpprev;
-@@ -416,8 +376,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
- jh = next_jh;
- next_jh = jh->b_cpnext;
-
-- (*nr_to_scan)--;
-- if (__cp_buffer_busy(jh))
-+ if (!destroy && __cp_buffer_busy(jh))
- continue;
-
- nr_freed++;
-@@ -429,7 +388,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
-
- if (need_resched())
- break;
-- } while (jh != last_jh && *nr_to_scan);
-+ } while (jh != last_jh);
-
- return nr_freed;
- }
-@@ -447,11 +406,11 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- unsigned long *nr_to_scan)
- {
- transaction_t *transaction, *last_transaction, *next_transaction;
-- bool released;
-+ bool __maybe_unused released;
- tid_t first_tid = 0, last_tid = 0, next_tid = 0;
- tid_t tid = 0;
- unsigned long nr_freed = 0;
-- unsigned long nr_scanned = *nr_to_scan;
-+ unsigned long freed;
-
- again:
- spin_lock(&journal->j_list_lock);
-@@ -480,10 +439,11 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- transaction = next_transaction;
- next_transaction = transaction->t_cpnext;
- tid = transaction->t_tid;
-- released = false;
-
-- nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_list,
-- nr_to_scan, &released);
-+ freed = journal_shrink_one_cp_list(transaction->t_checkpoint_list,
-+ false, &released);
-+ nr_freed += freed;
-+ (*nr_to_scan) -= min(*nr_to_scan, freed);
- if (*nr_to_scan == 0)
- break;
- if (need_resched() || spin_needbreak(&journal->j_list_lock))
-@@ -504,9 +464,8 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- if (*nr_to_scan && next_tid)
- goto again;
- out:
-- nr_scanned -= *nr_to_scan;
- trace_jbd2_shrink_checkpoint_list(journal, first_tid, tid, last_tid,
-- nr_freed, nr_scanned, next_tid);
-+ nr_freed, next_tid);
-
- return nr_freed;
- }
-@@ -522,7 +481,7 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
- {
- transaction_t *transaction, *last_transaction, *next_transaction;
-- int ret;
-+ bool released;
-
- transaction = journal->j_checkpoint_transactions;
- if (!transaction)
-@@ -533,8 +492,8 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
- do {
- transaction = next_transaction;
- next_transaction = transaction->t_cpnext;
-- ret = journal_clean_one_cp_list(transaction->t_checkpoint_list,
-- destroy);
-+ journal_shrink_one_cp_list(transaction->t_checkpoint_list,
-+ destroy, &released);
- /*
- * This function only frees up some memory if possible so we
- * dont have an obligation to finish processing. Bail out if
-@@ -547,7 +506,7 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
- * avoids pointless scanning of transactions which still
- * weren't checkpointed.
- */
-- if (!ret)
-+ if (!released)
- return;
- } while (transaction != last_transaction);
- }
-diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h
-index 29414288ea3e0..34ce197bd76e0 100644
---- a/include/trace/events/jbd2.h
-+++ b/include/trace/events/jbd2.h
-@@ -462,11 +462,9 @@ TRACE_EVENT(jbd2_shrink_scan_exit,
- TRACE_EVENT(jbd2_shrink_checkpoint_list,
-
- TP_PROTO(journal_t *journal, tid_t first_tid, tid_t tid, tid_t last_tid,
-- unsigned long nr_freed, unsigned long nr_scanned,
-- tid_t next_tid),
-+ unsigned long nr_freed, tid_t next_tid),
-
-- TP_ARGS(journal, first_tid, tid, last_tid, nr_freed,
-- nr_scanned, next_tid),
-+ TP_ARGS(journal, first_tid, tid, last_tid, nr_freed, next_tid),
-
- TP_STRUCT__entry(
- __field(dev_t, dev)
-@@ -474,7 +472,6 @@ TRACE_EVENT(jbd2_shrink_checkpoint_list,
- __field(tid_t, tid)
- __field(tid_t, last_tid)
- __field(unsigned long, nr_freed)
-- __field(unsigned long, nr_scanned)
- __field(tid_t, next_tid)
- ),
-
-@@ -484,15 +481,14 @@ TRACE_EVENT(jbd2_shrink_checkpoint_list,
- __entry->tid = tid;
- __entry->last_tid = last_tid;
- __entry->nr_freed = nr_freed;
-- __entry->nr_scanned = nr_scanned;
- __entry->next_tid = next_tid;
- ),
-
- TP_printk("dev %d,%d shrink transaction %u-%u(%u) freed %lu "
-- "scanned %lu next transaction %u",
-+ "next transaction %u",
- MAJOR(__entry->dev), MINOR(__entry->dev),
- __entry->first_tid, __entry->tid, __entry->last_tid,
-- __entry->nr_freed, __entry->nr_scanned, __entry->next_tid)
-+ __entry->nr_freed, __entry->next_tid)
- );
-
- #endif /* _TRACE_JBD2_H */
---
-2.39.2
-
+++ /dev/null
-From 92d4d5454f0734d09f34beaae5f86cf3dcc3087f Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 6 Jun 2023 21:59:24 +0800
-Subject: jbd2: remove t_checkpoint_io_list
-
-From: Zhang Yi <yi.zhang@huawei.com>
-
-[ Upstream commit be22255360f80d3af789daad00025171a65424a5 ]
-
-Since t_checkpoint_io_list was stop using in jbd2_log_do_checkpoint()
-now, it's time to remove the whole t_checkpoint_io_list logic.
-
-Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Link: https://lore.kernel.org/r/20230606135928.434610-3-yi.zhang@huaweicloud.com
-Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-Stable-dep-of: 46f881b5b175 ("jbd2: fix a race when checking checkpoint buffer busy")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/jbd2/checkpoint.c | 42 ++----------------------------------------
- fs/jbd2/commit.c | 3 +--
- include/linux/jbd2.h | 6 ------
- 3 files changed, 3 insertions(+), 48 deletions(-)
-
-diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
-index d2aba55833f92..c1f543e86170a 100644
---- a/fs/jbd2/checkpoint.c
-+++ b/fs/jbd2/checkpoint.c
-@@ -27,7 +27,7 @@
- *
- * Called with j_list_lock held.
- */
--static inline void __buffer_unlink_first(struct journal_head *jh)
-+static inline void __buffer_unlink(struct journal_head *jh)
- {
- transaction_t *transaction = jh->b_cp_transaction;
-
-@@ -40,23 +40,6 @@ static inline void __buffer_unlink_first(struct journal_head *jh)
- }
- }
-
--/*
-- * Unlink a buffer from a transaction checkpoint(io) list.
-- *
-- * Called with j_list_lock held.
-- */
--static inline void __buffer_unlink(struct journal_head *jh)
--{
-- transaction_t *transaction = jh->b_cp_transaction;
--
-- __buffer_unlink_first(jh);
-- if (transaction->t_checkpoint_io_list == jh) {
-- transaction->t_checkpoint_io_list = jh->b_cpnext;
-- if (transaction->t_checkpoint_io_list == jh)
-- transaction->t_checkpoint_io_list = NULL;
-- }
--}
--
- /*
- * Check a checkpoint buffer could be release or not.
- *
-@@ -505,15 +488,6 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- break;
- if (need_resched() || spin_needbreak(&journal->j_list_lock))
- break;
-- if (released)
-- continue;
--
-- nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_io_list,
-- nr_to_scan, &released);
-- if (*nr_to_scan == 0)
-- break;
-- if (need_resched() || spin_needbreak(&journal->j_list_lock))
-- break;
- } while (transaction != last_transaction);
-
- if (transaction != last_transaction) {
-@@ -568,17 +542,6 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
- */
- if (need_resched())
- return;
-- if (ret)
-- continue;
-- /*
-- * It is essential that we are as careful as in the case of
-- * t_checkpoint_list with removing the buffer from the list as
-- * we can possibly see not yet submitted buffers on io_list
-- */
-- ret = journal_clean_one_cp_list(transaction->
-- t_checkpoint_io_list, destroy);
-- if (need_resched())
-- return;
- /*
- * Stop scanning if we couldn't free the transaction. This
- * avoids pointless scanning of transactions which still
-@@ -663,7 +626,7 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
- jbd2_journal_put_journal_head(jh);
-
- /* Is this transaction empty? */
-- if (transaction->t_checkpoint_list || transaction->t_checkpoint_io_list)
-+ if (transaction->t_checkpoint_list)
- return 0;
-
- /*
-@@ -755,7 +718,6 @@ void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transact
- J_ASSERT(transaction->t_forget == NULL);
- J_ASSERT(transaction->t_shadow_list == NULL);
- J_ASSERT(transaction->t_checkpoint_list == NULL);
-- J_ASSERT(transaction->t_checkpoint_io_list == NULL);
- J_ASSERT(atomic_read(&transaction->t_updates) == 0);
- J_ASSERT(journal->j_committing_transaction != transaction);
- J_ASSERT(journal->j_running_transaction != transaction);
-diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
-index ac328e3321242..20294c1bbeab7 100644
---- a/fs/jbd2/commit.c
-+++ b/fs/jbd2/commit.c
-@@ -1184,8 +1184,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
- spin_lock(&journal->j_list_lock);
- commit_transaction->t_state = T_FINISHED;
- /* Check if the transaction can be dropped now that we are finished */
-- if (commit_transaction->t_checkpoint_list == NULL &&
-- commit_transaction->t_checkpoint_io_list == NULL) {
-+ if (commit_transaction->t_checkpoint_list == NULL) {
- __jbd2_journal_drop_transaction(journal, commit_transaction);
- jbd2_journal_free_transaction(commit_transaction);
- }
-diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
-index d63b8106796e2..e6cfbcde96f29 100644
---- a/include/linux/jbd2.h
-+++ b/include/linux/jbd2.h
-@@ -626,12 +626,6 @@ struct transaction_s
- */
- struct journal_head *t_checkpoint_list;
-
-- /*
-- * Doubly-linked circular list of all buffers submitted for IO while
-- * checkpointing. [j_list_lock]
-- */
-- struct journal_head *t_checkpoint_io_list;
--
- /*
- * Doubly-linked circular list of metadata buffers being
- * shadowed by log IO. The IO buffers on the iobuf list and
---
-2.39.2
-
scsi-qla2xxx-fix-hang-in-task-management.patch
drm-amdgpu-fix-vkms-crtc-settings.patch
drm-amdgpu-vkms-relax-timer-deactivation-by-hrtimer_.patch
-jbd2-remove-t_checkpoint_io_list.patch
-jbd2-remove-journal_clean_one_cp_list.patch
-jbd2-fix-a-race-when-checking-checkpoint-buffer-busy.patch
phy-qcom-snps-use-dev_err_probe-to-simplify-code.patch
phy-qcom-snps-correct-struct-qcom_snps_hsphy-kerneld.patch
phy-qcom-snps-femto-v2-keep-cfg_ahb_clk-enabled-duri.patch
+++ /dev/null
-From 4925d566f7e303289ee5d4aabcf8e2f24544331b Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 6 Jun 2023 21:59:27 +0800
-Subject: jbd2: fix a race when checking checkpoint buffer busy
-
-From: Zhang Yi <yi.zhang@huawei.com>
-
-[ Upstream commit 46f881b5b1758dc4a35fba4a643c10717d0cf427 ]
-
-Before removing checkpoint buffer from the t_checkpoint_list, we have to
-check both BH_Dirty and BH_Lock bits together to distinguish buffers
-have not been or were being written back. But __cp_buffer_busy() checks
-them separately, it first check lock state and then check dirty, the
-window between these two checks could be raced by writing back
-procedure, which locks buffer and clears buffer dirty before I/O
-completes. So it cannot guarantee checkpointing buffers been written
-back to disk if some error happens later. Finally, it may clean
-checkpoint transactions and lead to inconsistent filesystem.
-
-jbd2_journal_forget() and __journal_try_to_free_buffer() also have the
-same problem (journal_unmap_buffer() escape from this issue since it's
-running under the buffer lock), so fix them through introducing a new
-helper to try holding the buffer lock and remove really clean buffer.
-
-Link: https://bugzilla.kernel.org/show_bug.cgi?id=217490
-Cc: stable@vger.kernel.org
-Suggested-by: Jan Kara <jack@suse.cz>
-Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Link: https://lore.kernel.org/r/20230606135928.434610-6-yi.zhang@huaweicloud.com
-Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/jbd2/checkpoint.c | 38 +++++++++++++++++++++++++++++++++++---
- fs/jbd2/transaction.c | 17 +++++------------
- include/linux/jbd2.h | 1 +
- 3 files changed, 41 insertions(+), 15 deletions(-)
-
-diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
-index 42b34cab64fbd..9ec91017a7f3c 100644
---- a/fs/jbd2/checkpoint.c
-+++ b/fs/jbd2/checkpoint.c
-@@ -376,11 +376,15 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
- jh = next_jh;
- next_jh = jh->b_cpnext;
-
-- if (!destroy && __cp_buffer_busy(jh))
-- continue;
-+ if (destroy) {
-+ ret = __jbd2_journal_remove_checkpoint(jh);
-+ } else {
-+ ret = jbd2_journal_try_remove_checkpoint(jh);
-+ if (ret < 0)
-+ continue;
-+ }
-
- nr_freed++;
-- ret = __jbd2_journal_remove_checkpoint(jh);
- if (ret) {
- *released = true;
- break;
-@@ -616,6 +620,34 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
- return 1;
- }
-
-+/*
-+ * Check the checkpoint buffer and try to remove it from the checkpoint
-+ * list if it's clean. Returns -EBUSY if it is not clean, returns 1 if
-+ * it frees the transaction, 0 otherwise.
-+ *
-+ * This function is called with j_list_lock held.
-+ */
-+int jbd2_journal_try_remove_checkpoint(struct journal_head *jh)
-+{
-+ struct buffer_head *bh = jh2bh(jh);
-+
-+ if (!trylock_buffer(bh))
-+ return -EBUSY;
-+ if (buffer_dirty(bh)) {
-+ unlock_buffer(bh);
-+ return -EBUSY;
-+ }
-+ unlock_buffer(bh);
-+
-+ /*
-+ * Buffer is clean and the IO has finished (we held the buffer
-+ * lock) so the checkpoint is done. We can safely remove the
-+ * buffer from this transaction.
-+ */
-+ JBUFFER_TRACE(jh, "remove from checkpoint list");
-+ return __jbd2_journal_remove_checkpoint(jh);
-+}
-+
- /*
- * journal_insert_checkpoint: put a committed buffer onto a checkpoint
- * list so that we know when it is safe to clean the transaction out of
-diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
-index 18611241f4513..6ef5022949c46 100644
---- a/fs/jbd2/transaction.c
-+++ b/fs/jbd2/transaction.c
-@@ -1784,8 +1784,7 @@ int jbd2_journal_forget(handle_t *handle, struct buffer_head *bh)
- * Otherwise, if the buffer has been written to disk,
- * it is safe to remove the checkpoint and drop it.
- */
-- if (!buffer_dirty(bh)) {
-- __jbd2_journal_remove_checkpoint(jh);
-+ if (jbd2_journal_try_remove_checkpoint(jh) >= 0) {
- spin_unlock(&journal->j_list_lock);
- goto drop;
- }
-@@ -2112,20 +2111,14 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
-
- jh = bh2jh(bh);
-
-- if (buffer_locked(bh) || buffer_dirty(bh))
-- goto out;
--
- if (jh->b_next_transaction != NULL || jh->b_transaction != NULL)
-- goto out;
-+ return;
-
- spin_lock(&journal->j_list_lock);
-- if (jh->b_cp_transaction != NULL) {
-- /* written-back checkpointed metadata buffer */
-- JBUFFER_TRACE(jh, "remove from checkpoint list");
-- __jbd2_journal_remove_checkpoint(jh);
-- }
-+ /* Remove written-back checkpointed metadata buffer */
-+ if (jh->b_cp_transaction != NULL)
-+ jbd2_journal_try_remove_checkpoint(jh);
- spin_unlock(&journal->j_list_lock);
--out:
- return;
- }
-
-diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
-index 67912fe08fbbd..ebb1608d9dcd2 100644
---- a/include/linux/jbd2.h
-+++ b/include/linux/jbd2.h
-@@ -1435,6 +1435,7 @@ extern void jbd2_journal_commit_transaction(journal_t *);
- void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy);
- unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal, unsigned long *nr_to_scan);
- int __jbd2_journal_remove_checkpoint(struct journal_head *);
-+int jbd2_journal_try_remove_checkpoint(struct journal_head *jh);
- void jbd2_journal_destroy_checkpoint(journal_t *journal);
- void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *);
-
---
-2.39.2
-
+++ /dev/null
-From 7f2e7e3be85c2c0af0b6cd4c8b69de00ec06408c Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 6 Jun 2023 21:59:25 +0800
-Subject: jbd2: remove journal_clean_one_cp_list()
-
-From: Zhang Yi <yi.zhang@huawei.com>
-
-[ Upstream commit b98dba273a0e47dbfade89c9af73c5b012a4eabb ]
-
-journal_clean_one_cp_list() and journal_shrink_one_cp_list() are almost
-the same, so merge them into journal_shrink_one_cp_list(), remove the
-nr_to_scan parameter, always scan and try to free the whole checkpoint
-list.
-
-Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Link: https://lore.kernel.org/r/20230606135928.434610-4-yi.zhang@huaweicloud.com
-Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-Stable-dep-of: 46f881b5b175 ("jbd2: fix a race when checking checkpoint buffer busy")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/jbd2/checkpoint.c | 75 +++++++++----------------------------
- include/trace/events/jbd2.h | 12 ++----
- 2 files changed, 21 insertions(+), 66 deletions(-)
-
-diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
-index 723b4eb112828..42b34cab64fbd 100644
---- a/fs/jbd2/checkpoint.c
-+++ b/fs/jbd2/checkpoint.c
-@@ -349,50 +349,10 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
-
- /* Checkpoint list management */
-
--/*
-- * journal_clean_one_cp_list
-- *
-- * Find all the written-back checkpoint buffers in the given list and
-- * release them. If 'destroy' is set, clean all buffers unconditionally.
-- *
-- * Called with j_list_lock held.
-- * Returns 1 if we freed the transaction, 0 otherwise.
-- */
--static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
--{
-- struct journal_head *last_jh;
-- struct journal_head *next_jh = jh;
--
-- if (!jh)
-- return 0;
--
-- last_jh = jh->b_cpprev;
-- do {
-- jh = next_jh;
-- next_jh = jh->b_cpnext;
--
-- if (!destroy && __cp_buffer_busy(jh))
-- return 0;
--
-- if (__jbd2_journal_remove_checkpoint(jh))
-- return 1;
-- /*
-- * This function only frees up some memory
-- * if possible so we dont have an obligation
-- * to finish processing. Bail out if preemption
-- * requested:
-- */
-- if (need_resched())
-- return 0;
-- } while (jh != last_jh);
--
-- return 0;
--}
--
- /*
- * journal_shrink_one_cp_list
- *
-- * Find 'nr_to_scan' written-back checkpoint buffers in the given list
-+ * Find all the written-back checkpoint buffers in the given list
- * and try to release them. If the whole transaction is released, set
- * the 'released' parameter. Return the number of released checkpointed
- * buffers.
-@@ -400,15 +360,15 @@ static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
- * Called with j_list_lock held.
- */
- static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
-- unsigned long *nr_to_scan,
-- bool *released)
-+ bool destroy, bool *released)
- {
- struct journal_head *last_jh;
- struct journal_head *next_jh = jh;
- unsigned long nr_freed = 0;
- int ret;
-
-- if (!jh || *nr_to_scan == 0)
-+ *released = false;
-+ if (!jh)
- return 0;
-
- last_jh = jh->b_cpprev;
-@@ -416,8 +376,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
- jh = next_jh;
- next_jh = jh->b_cpnext;
-
-- (*nr_to_scan)--;
-- if (__cp_buffer_busy(jh))
-+ if (!destroy && __cp_buffer_busy(jh))
- continue;
-
- nr_freed++;
-@@ -429,7 +388,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
-
- if (need_resched())
- break;
-- } while (jh != last_jh && *nr_to_scan);
-+ } while (jh != last_jh);
-
- return nr_freed;
- }
-@@ -447,11 +406,11 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- unsigned long *nr_to_scan)
- {
- transaction_t *transaction, *last_transaction, *next_transaction;
-- bool released;
-+ bool __maybe_unused released;
- tid_t first_tid = 0, last_tid = 0, next_tid = 0;
- tid_t tid = 0;
- unsigned long nr_freed = 0;
-- unsigned long nr_scanned = *nr_to_scan;
-+ unsigned long freed;
-
- again:
- spin_lock(&journal->j_list_lock);
-@@ -480,10 +439,11 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- transaction = next_transaction;
- next_transaction = transaction->t_cpnext;
- tid = transaction->t_tid;
-- released = false;
-
-- nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_list,
-- nr_to_scan, &released);
-+ freed = journal_shrink_one_cp_list(transaction->t_checkpoint_list,
-+ false, &released);
-+ nr_freed += freed;
-+ (*nr_to_scan) -= min(*nr_to_scan, freed);
- if (*nr_to_scan == 0)
- break;
- if (need_resched() || spin_needbreak(&journal->j_list_lock))
-@@ -504,9 +464,8 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- if (*nr_to_scan && next_tid)
- goto again;
- out:
-- nr_scanned -= *nr_to_scan;
- trace_jbd2_shrink_checkpoint_list(journal, first_tid, tid, last_tid,
-- nr_freed, nr_scanned, next_tid);
-+ nr_freed, next_tid);
-
- return nr_freed;
- }
-@@ -522,7 +481,7 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
- {
- transaction_t *transaction, *last_transaction, *next_transaction;
-- int ret;
-+ bool released;
-
- transaction = journal->j_checkpoint_transactions;
- if (!transaction)
-@@ -533,8 +492,8 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
- do {
- transaction = next_transaction;
- next_transaction = transaction->t_cpnext;
-- ret = journal_clean_one_cp_list(transaction->t_checkpoint_list,
-- destroy);
-+ journal_shrink_one_cp_list(transaction->t_checkpoint_list,
-+ destroy, &released);
- /*
- * This function only frees up some memory if possible so we
- * dont have an obligation to finish processing. Bail out if
-@@ -547,7 +506,7 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
- * avoids pointless scanning of transactions which still
- * weren't checkpointed.
- */
-- if (!ret)
-+ if (!released)
- return;
- } while (transaction != last_transaction);
- }
-diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h
-index 8f5ee380d3093..5646ae15a957a 100644
---- a/include/trace/events/jbd2.h
-+++ b/include/trace/events/jbd2.h
-@@ -462,11 +462,9 @@ TRACE_EVENT(jbd2_shrink_scan_exit,
- TRACE_EVENT(jbd2_shrink_checkpoint_list,
-
- TP_PROTO(journal_t *journal, tid_t first_tid, tid_t tid, tid_t last_tid,
-- unsigned long nr_freed, unsigned long nr_scanned,
-- tid_t next_tid),
-+ unsigned long nr_freed, tid_t next_tid),
-
-- TP_ARGS(journal, first_tid, tid, last_tid, nr_freed,
-- nr_scanned, next_tid),
-+ TP_ARGS(journal, first_tid, tid, last_tid, nr_freed, next_tid),
-
- TP_STRUCT__entry(
- __field(dev_t, dev)
-@@ -474,7 +472,6 @@ TRACE_EVENT(jbd2_shrink_checkpoint_list,
- __field(tid_t, tid)
- __field(tid_t, last_tid)
- __field(unsigned long, nr_freed)
-- __field(unsigned long, nr_scanned)
- __field(tid_t, next_tid)
- ),
-
-@@ -484,15 +481,14 @@ TRACE_EVENT(jbd2_shrink_checkpoint_list,
- __entry->tid = tid;
- __entry->last_tid = last_tid;
- __entry->nr_freed = nr_freed;
-- __entry->nr_scanned = nr_scanned;
- __entry->next_tid = next_tid;
- ),
-
- TP_printk("dev %d,%d shrink transaction %u-%u(%u) freed %lu "
-- "scanned %lu next transaction %u",
-+ "next transaction %u",
- MAJOR(__entry->dev), MINOR(__entry->dev),
- __entry->first_tid, __entry->tid, __entry->last_tid,
-- __entry->nr_freed, __entry->nr_scanned, __entry->next_tid)
-+ __entry->nr_freed, __entry->next_tid)
- );
-
- #endif /* _TRACE_JBD2_H */
---
-2.39.2
-
+++ /dev/null
-From 0c9838fba04567f1905865f0b3a659724945c8a8 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 6 Jun 2023 21:59:24 +0800
-Subject: jbd2: remove t_checkpoint_io_list
-
-From: Zhang Yi <yi.zhang@huawei.com>
-
-[ Upstream commit be22255360f80d3af789daad00025171a65424a5 ]
-
-Since t_checkpoint_io_list was stop using in jbd2_log_do_checkpoint()
-now, it's time to remove the whole t_checkpoint_io_list logic.
-
-Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Link: https://lore.kernel.org/r/20230606135928.434610-3-yi.zhang@huaweicloud.com
-Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-Stable-dep-of: 46f881b5b175 ("jbd2: fix a race when checking checkpoint buffer busy")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/jbd2/checkpoint.c | 42 ++----------------------------------------
- fs/jbd2/commit.c | 3 +--
- include/linux/jbd2.h | 6 ------
- 3 files changed, 3 insertions(+), 48 deletions(-)
-
-diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
-index c4e0da6db7195..723b4eb112828 100644
---- a/fs/jbd2/checkpoint.c
-+++ b/fs/jbd2/checkpoint.c
-@@ -27,7 +27,7 @@
- *
- * Called with j_list_lock held.
- */
--static inline void __buffer_unlink_first(struct journal_head *jh)
-+static inline void __buffer_unlink(struct journal_head *jh)
- {
- transaction_t *transaction = jh->b_cp_transaction;
-
-@@ -40,23 +40,6 @@ static inline void __buffer_unlink_first(struct journal_head *jh)
- }
- }
-
--/*
-- * Unlink a buffer from a transaction checkpoint(io) list.
-- *
-- * Called with j_list_lock held.
-- */
--static inline void __buffer_unlink(struct journal_head *jh)
--{
-- transaction_t *transaction = jh->b_cp_transaction;
--
-- __buffer_unlink_first(jh);
-- if (transaction->t_checkpoint_io_list == jh) {
-- transaction->t_checkpoint_io_list = jh->b_cpnext;
-- if (transaction->t_checkpoint_io_list == jh)
-- transaction->t_checkpoint_io_list = NULL;
-- }
--}
--
- /*
- * Check a checkpoint buffer could be release or not.
- *
-@@ -505,15 +488,6 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- break;
- if (need_resched() || spin_needbreak(&journal->j_list_lock))
- break;
-- if (released)
-- continue;
--
-- nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_io_list,
-- nr_to_scan, &released);
-- if (*nr_to_scan == 0)
-- break;
-- if (need_resched() || spin_needbreak(&journal->j_list_lock))
-- break;
- } while (transaction != last_transaction);
-
- if (transaction != last_transaction) {
-@@ -568,17 +542,6 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
- */
- if (need_resched())
- return;
-- if (ret)
-- continue;
-- /*
-- * It is essential that we are as careful as in the case of
-- * t_checkpoint_list with removing the buffer from the list as
-- * we can possibly see not yet submitted buffers on io_list
-- */
-- ret = journal_clean_one_cp_list(transaction->
-- t_checkpoint_io_list, destroy);
-- if (need_resched())
-- return;
- /*
- * Stop scanning if we couldn't free the transaction. This
- * avoids pointless scanning of transactions which still
-@@ -663,7 +626,7 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
- jbd2_journal_put_journal_head(jh);
-
- /* Is this transaction empty? */
-- if (transaction->t_checkpoint_list || transaction->t_checkpoint_io_list)
-+ if (transaction->t_checkpoint_list)
- return 0;
-
- /*
-@@ -755,7 +718,6 @@ void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transact
- J_ASSERT(transaction->t_forget == NULL);
- J_ASSERT(transaction->t_shadow_list == NULL);
- J_ASSERT(transaction->t_checkpoint_list == NULL);
-- J_ASSERT(transaction->t_checkpoint_io_list == NULL);
- J_ASSERT(atomic_read(&transaction->t_updates) == 0);
- J_ASSERT(journal->j_committing_transaction != transaction);
- J_ASSERT(journal->j_running_transaction != transaction);
-diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
-index 885a7a6cc53e6..f1d9db6686e31 100644
---- a/fs/jbd2/commit.c
-+++ b/fs/jbd2/commit.c
-@@ -1171,8 +1171,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
- spin_lock(&journal->j_list_lock);
- commit_transaction->t_state = T_FINISHED;
- /* Check if the transaction can be dropped now that we are finished */
-- if (commit_transaction->t_checkpoint_list == NULL &&
-- commit_transaction->t_checkpoint_io_list == NULL) {
-+ if (commit_transaction->t_checkpoint_list == NULL) {
- __jbd2_journal_drop_transaction(journal, commit_transaction);
- jbd2_journal_free_transaction(commit_transaction);
- }
-diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
-index 0b7242370b567..67912fe08fbbd 100644
---- a/include/linux/jbd2.h
-+++ b/include/linux/jbd2.h
-@@ -622,12 +622,6 @@ struct transaction_s
- */
- struct journal_head *t_checkpoint_list;
-
-- /*
-- * Doubly-linked circular list of all buffers submitted for IO while
-- * checkpointing. [j_list_lock]
-- */
-- struct journal_head *t_checkpoint_io_list;
--
- /*
- * Doubly-linked circular list of metadata buffers being
- * shadowed by log IO. The IO buffers on the iobuf list and
---
-2.39.2
-
drm-amd-display-update-extended-blank-for-dcn314-onw.patch
drm-amd-display-fix-possible-underflow-for-displays-.patch
drm-amd-display-prevent-vtotal-from-being-set-to-0.patch
-jbd2-remove-t_checkpoint_io_list.patch
-jbd2-remove-journal_clean_one_cp_list.patch
-jbd2-fix-a-race-when-checking-checkpoint-buffer-busy.patch
phy-phy-mtk-dp-fix-an-error-code-in-probe.patch
phy-qcom-snps-correct-struct-qcom_snps_hsphy-kerneld.patch
phy-qcom-snps-femto-v2-keep-cfg_ahb_clk-enabled-duri.patch
+++ /dev/null
-From 091939319a56dbd39ddf118c5e9ffa2d348df215 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 6 Jun 2023 21:59:27 +0800
-Subject: jbd2: fix a race when checking checkpoint buffer busy
-
-From: Zhang Yi <yi.zhang@huawei.com>
-
-[ Upstream commit 46f881b5b1758dc4a35fba4a643c10717d0cf427 ]
-
-Before removing checkpoint buffer from the t_checkpoint_list, we have to
-check both BH_Dirty and BH_Lock bits together to distinguish buffers
-have not been or were being written back. But __cp_buffer_busy() checks
-them separately, it first check lock state and then check dirty, the
-window between these two checks could be raced by writing back
-procedure, which locks buffer and clears buffer dirty before I/O
-completes. So it cannot guarantee checkpointing buffers been written
-back to disk if some error happens later. Finally, it may clean
-checkpoint transactions and lead to inconsistent filesystem.
-
-jbd2_journal_forget() and __journal_try_to_free_buffer() also have the
-same problem (journal_unmap_buffer() escape from this issue since it's
-running under the buffer lock), so fix them through introducing a new
-helper to try holding the buffer lock and remove really clean buffer.
-
-Link: https://bugzilla.kernel.org/show_bug.cgi?id=217490
-Cc: stable@vger.kernel.org
-Suggested-by: Jan Kara <jack@suse.cz>
-Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Link: https://lore.kernel.org/r/20230606135928.434610-6-yi.zhang@huaweicloud.com
-Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/jbd2/checkpoint.c | 38 +++++++++++++++++++++++++++++++++++---
- fs/jbd2/transaction.c | 17 +++++------------
- include/linux/jbd2.h | 1 +
- 3 files changed, 41 insertions(+), 15 deletions(-)
-
-diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
-index 42b34cab64fbd..9ec91017a7f3c 100644
---- a/fs/jbd2/checkpoint.c
-+++ b/fs/jbd2/checkpoint.c
-@@ -376,11 +376,15 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
- jh = next_jh;
- next_jh = jh->b_cpnext;
-
-- if (!destroy && __cp_buffer_busy(jh))
-- continue;
-+ if (destroy) {
-+ ret = __jbd2_journal_remove_checkpoint(jh);
-+ } else {
-+ ret = jbd2_journal_try_remove_checkpoint(jh);
-+ if (ret < 0)
-+ continue;
-+ }
-
- nr_freed++;
-- ret = __jbd2_journal_remove_checkpoint(jh);
- if (ret) {
- *released = true;
- break;
-@@ -616,6 +620,34 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
- return 1;
- }
-
-+/*
-+ * Check the checkpoint buffer and try to remove it from the checkpoint
-+ * list if it's clean. Returns -EBUSY if it is not clean, returns 1 if
-+ * it frees the transaction, 0 otherwise.
-+ *
-+ * This function is called with j_list_lock held.
-+ */
-+int jbd2_journal_try_remove_checkpoint(struct journal_head *jh)
-+{
-+ struct buffer_head *bh = jh2bh(jh);
-+
-+ if (!trylock_buffer(bh))
-+ return -EBUSY;
-+ if (buffer_dirty(bh)) {
-+ unlock_buffer(bh);
-+ return -EBUSY;
-+ }
-+ unlock_buffer(bh);
-+
-+ /*
-+ * Buffer is clean and the IO has finished (we held the buffer
-+ * lock) so the checkpoint is done. We can safely remove the
-+ * buffer from this transaction.
-+ */
-+ JBUFFER_TRACE(jh, "remove from checkpoint list");
-+ return __jbd2_journal_remove_checkpoint(jh);
-+}
-+
- /*
- * journal_insert_checkpoint: put a committed buffer onto a checkpoint
- * list so that we know when it is safe to clean the transaction out of
-diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
-index 18611241f4513..6ef5022949c46 100644
---- a/fs/jbd2/transaction.c
-+++ b/fs/jbd2/transaction.c
-@@ -1784,8 +1784,7 @@ int jbd2_journal_forget(handle_t *handle, struct buffer_head *bh)
- * Otherwise, if the buffer has been written to disk,
- * it is safe to remove the checkpoint and drop it.
- */
-- if (!buffer_dirty(bh)) {
-- __jbd2_journal_remove_checkpoint(jh);
-+ if (jbd2_journal_try_remove_checkpoint(jh) >= 0) {
- spin_unlock(&journal->j_list_lock);
- goto drop;
- }
-@@ -2112,20 +2111,14 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
-
- jh = bh2jh(bh);
-
-- if (buffer_locked(bh) || buffer_dirty(bh))
-- goto out;
--
- if (jh->b_next_transaction != NULL || jh->b_transaction != NULL)
-- goto out;
-+ return;
-
- spin_lock(&journal->j_list_lock);
-- if (jh->b_cp_transaction != NULL) {
-- /* written-back checkpointed metadata buffer */
-- JBUFFER_TRACE(jh, "remove from checkpoint list");
-- __jbd2_journal_remove_checkpoint(jh);
-- }
-+ /* Remove written-back checkpointed metadata buffer */
-+ if (jh->b_cp_transaction != NULL)
-+ jbd2_journal_try_remove_checkpoint(jh);
- spin_unlock(&journal->j_list_lock);
--out:
- return;
- }
-
-diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
-index 91a2cf4bc5756..c212da35a052c 100644
---- a/include/linux/jbd2.h
-+++ b/include/linux/jbd2.h
-@@ -1443,6 +1443,7 @@ extern void jbd2_journal_commit_transaction(journal_t *);
- void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy);
- unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal, unsigned long *nr_to_scan);
- int __jbd2_journal_remove_checkpoint(struct journal_head *);
-+int jbd2_journal_try_remove_checkpoint(struct journal_head *jh);
- void jbd2_journal_destroy_checkpoint(journal_t *journal);
- void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *);
-
---
-2.39.2
-
+++ /dev/null
-From 71da043e7bda0b64713cf3496d168b8bc5b75c0c Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 6 Jun 2023 21:59:25 +0800
-Subject: jbd2: remove journal_clean_one_cp_list()
-
-From: Zhang Yi <yi.zhang@huawei.com>
-
-[ Upstream commit b98dba273a0e47dbfade89c9af73c5b012a4eabb ]
-
-journal_clean_one_cp_list() and journal_shrink_one_cp_list() are almost
-the same, so merge them into journal_shrink_one_cp_list(), remove the
-nr_to_scan parameter, always scan and try to free the whole checkpoint
-list.
-
-Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Link: https://lore.kernel.org/r/20230606135928.434610-4-yi.zhang@huaweicloud.com
-Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-Stable-dep-of: 46f881b5b175 ("jbd2: fix a race when checking checkpoint buffer busy")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/jbd2/checkpoint.c | 75 +++++++++----------------------------
- include/trace/events/jbd2.h | 12 ++----
- 2 files changed, 21 insertions(+), 66 deletions(-)
-
-diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
-index 723b4eb112828..42b34cab64fbd 100644
---- a/fs/jbd2/checkpoint.c
-+++ b/fs/jbd2/checkpoint.c
-@@ -349,50 +349,10 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
-
- /* Checkpoint list management */
-
--/*
-- * journal_clean_one_cp_list
-- *
-- * Find all the written-back checkpoint buffers in the given list and
-- * release them. If 'destroy' is set, clean all buffers unconditionally.
-- *
-- * Called with j_list_lock held.
-- * Returns 1 if we freed the transaction, 0 otherwise.
-- */
--static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
--{
-- struct journal_head *last_jh;
-- struct journal_head *next_jh = jh;
--
-- if (!jh)
-- return 0;
--
-- last_jh = jh->b_cpprev;
-- do {
-- jh = next_jh;
-- next_jh = jh->b_cpnext;
--
-- if (!destroy && __cp_buffer_busy(jh))
-- return 0;
--
-- if (__jbd2_journal_remove_checkpoint(jh))
-- return 1;
-- /*
-- * This function only frees up some memory
-- * if possible so we dont have an obligation
-- * to finish processing. Bail out if preemption
-- * requested:
-- */
-- if (need_resched())
-- return 0;
-- } while (jh != last_jh);
--
-- return 0;
--}
--
- /*
- * journal_shrink_one_cp_list
- *
-- * Find 'nr_to_scan' written-back checkpoint buffers in the given list
-+ * Find all the written-back checkpoint buffers in the given list
- * and try to release them. If the whole transaction is released, set
- * the 'released' parameter. Return the number of released checkpointed
- * buffers.
-@@ -400,15 +360,15 @@ static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
- * Called with j_list_lock held.
- */
- static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
-- unsigned long *nr_to_scan,
-- bool *released)
-+ bool destroy, bool *released)
- {
- struct journal_head *last_jh;
- struct journal_head *next_jh = jh;
- unsigned long nr_freed = 0;
- int ret;
-
-- if (!jh || *nr_to_scan == 0)
-+ *released = false;
-+ if (!jh)
- return 0;
-
- last_jh = jh->b_cpprev;
-@@ -416,8 +376,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
- jh = next_jh;
- next_jh = jh->b_cpnext;
-
-- (*nr_to_scan)--;
-- if (__cp_buffer_busy(jh))
-+ if (!destroy && __cp_buffer_busy(jh))
- continue;
-
- nr_freed++;
-@@ -429,7 +388,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
-
- if (need_resched())
- break;
-- } while (jh != last_jh && *nr_to_scan);
-+ } while (jh != last_jh);
-
- return nr_freed;
- }
-@@ -447,11 +406,11 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- unsigned long *nr_to_scan)
- {
- transaction_t *transaction, *last_transaction, *next_transaction;
-- bool released;
-+ bool __maybe_unused released;
- tid_t first_tid = 0, last_tid = 0, next_tid = 0;
- tid_t tid = 0;
- unsigned long nr_freed = 0;
-- unsigned long nr_scanned = *nr_to_scan;
-+ unsigned long freed;
-
- again:
- spin_lock(&journal->j_list_lock);
-@@ -480,10 +439,11 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- transaction = next_transaction;
- next_transaction = transaction->t_cpnext;
- tid = transaction->t_tid;
-- released = false;
-
-- nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_list,
-- nr_to_scan, &released);
-+ freed = journal_shrink_one_cp_list(transaction->t_checkpoint_list,
-+ false, &released);
-+ nr_freed += freed;
-+ (*nr_to_scan) -= min(*nr_to_scan, freed);
- if (*nr_to_scan == 0)
- break;
- if (need_resched() || spin_needbreak(&journal->j_list_lock))
-@@ -504,9 +464,8 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- if (*nr_to_scan && next_tid)
- goto again;
- out:
-- nr_scanned -= *nr_to_scan;
- trace_jbd2_shrink_checkpoint_list(journal, first_tid, tid, last_tid,
-- nr_freed, nr_scanned, next_tid);
-+ nr_freed, next_tid);
-
- return nr_freed;
- }
-@@ -522,7 +481,7 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
- {
- transaction_t *transaction, *last_transaction, *next_transaction;
-- int ret;
-+ bool released;
-
- transaction = journal->j_checkpoint_transactions;
- if (!transaction)
-@@ -533,8 +492,8 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
- do {
- transaction = next_transaction;
- next_transaction = transaction->t_cpnext;
-- ret = journal_clean_one_cp_list(transaction->t_checkpoint_list,
-- destroy);
-+ journal_shrink_one_cp_list(transaction->t_checkpoint_list,
-+ destroy, &released);
- /*
- * This function only frees up some memory if possible so we
- * dont have an obligation to finish processing. Bail out if
-@@ -547,7 +506,7 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
- * avoids pointless scanning of transactions which still
- * weren't checkpointed.
- */
-- if (!ret)
-+ if (!released)
- return;
- } while (transaction != last_transaction);
- }
-diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h
-index 8f5ee380d3093..5646ae15a957a 100644
---- a/include/trace/events/jbd2.h
-+++ b/include/trace/events/jbd2.h
-@@ -462,11 +462,9 @@ TRACE_EVENT(jbd2_shrink_scan_exit,
- TRACE_EVENT(jbd2_shrink_checkpoint_list,
-
- TP_PROTO(journal_t *journal, tid_t first_tid, tid_t tid, tid_t last_tid,
-- unsigned long nr_freed, unsigned long nr_scanned,
-- tid_t next_tid),
-+ unsigned long nr_freed, tid_t next_tid),
-
-- TP_ARGS(journal, first_tid, tid, last_tid, nr_freed,
-- nr_scanned, next_tid),
-+ TP_ARGS(journal, first_tid, tid, last_tid, nr_freed, next_tid),
-
- TP_STRUCT__entry(
- __field(dev_t, dev)
-@@ -474,7 +472,6 @@ TRACE_EVENT(jbd2_shrink_checkpoint_list,
- __field(tid_t, tid)
- __field(tid_t, last_tid)
- __field(unsigned long, nr_freed)
-- __field(unsigned long, nr_scanned)
- __field(tid_t, next_tid)
- ),
-
-@@ -484,15 +481,14 @@ TRACE_EVENT(jbd2_shrink_checkpoint_list,
- __entry->tid = tid;
- __entry->last_tid = last_tid;
- __entry->nr_freed = nr_freed;
-- __entry->nr_scanned = nr_scanned;
- __entry->next_tid = next_tid;
- ),
-
- TP_printk("dev %d,%d shrink transaction %u-%u(%u) freed %lu "
-- "scanned %lu next transaction %u",
-+ "next transaction %u",
- MAJOR(__entry->dev), MINOR(__entry->dev),
- __entry->first_tid, __entry->tid, __entry->last_tid,
-- __entry->nr_freed, __entry->nr_scanned, __entry->next_tid)
-+ __entry->nr_freed, __entry->next_tid)
- );
-
- #endif /* _TRACE_JBD2_H */
---
-2.39.2
-
+++ /dev/null
-From 9772b6005d10a0cfe725dba954d66e8ee6fa1e10 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 6 Jun 2023 21:59:24 +0800
-Subject: jbd2: remove t_checkpoint_io_list
-
-From: Zhang Yi <yi.zhang@huawei.com>
-
-[ Upstream commit be22255360f80d3af789daad00025171a65424a5 ]
-
-Since t_checkpoint_io_list was stop using in jbd2_log_do_checkpoint()
-now, it's time to remove the whole t_checkpoint_io_list logic.
-
-Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Link: https://lore.kernel.org/r/20230606135928.434610-3-yi.zhang@huaweicloud.com
-Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-Stable-dep-of: 46f881b5b175 ("jbd2: fix a race when checking checkpoint buffer busy")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/jbd2/checkpoint.c | 42 ++----------------------------------------
- fs/jbd2/commit.c | 3 +--
- include/linux/jbd2.h | 6 ------
- 3 files changed, 3 insertions(+), 48 deletions(-)
-
-diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
-index c4e0da6db7195..723b4eb112828 100644
---- a/fs/jbd2/checkpoint.c
-+++ b/fs/jbd2/checkpoint.c
-@@ -27,7 +27,7 @@
- *
- * Called with j_list_lock held.
- */
--static inline void __buffer_unlink_first(struct journal_head *jh)
-+static inline void __buffer_unlink(struct journal_head *jh)
- {
- transaction_t *transaction = jh->b_cp_transaction;
-
-@@ -40,23 +40,6 @@ static inline void __buffer_unlink_first(struct journal_head *jh)
- }
- }
-
--/*
-- * Unlink a buffer from a transaction checkpoint(io) list.
-- *
-- * Called with j_list_lock held.
-- */
--static inline void __buffer_unlink(struct journal_head *jh)
--{
-- transaction_t *transaction = jh->b_cp_transaction;
--
-- __buffer_unlink_first(jh);
-- if (transaction->t_checkpoint_io_list == jh) {
-- transaction->t_checkpoint_io_list = jh->b_cpnext;
-- if (transaction->t_checkpoint_io_list == jh)
-- transaction->t_checkpoint_io_list = NULL;
-- }
--}
--
- /*
- * Check a checkpoint buffer could be release or not.
- *
-@@ -505,15 +488,6 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
- break;
- if (need_resched() || spin_needbreak(&journal->j_list_lock))
- break;
-- if (released)
-- continue;
--
-- nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_io_list,
-- nr_to_scan, &released);
-- if (*nr_to_scan == 0)
-- break;
-- if (need_resched() || spin_needbreak(&journal->j_list_lock))
-- break;
- } while (transaction != last_transaction);
-
- if (transaction != last_transaction) {
-@@ -568,17 +542,6 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
- */
- if (need_resched())
- return;
-- if (ret)
-- continue;
-- /*
-- * It is essential that we are as careful as in the case of
-- * t_checkpoint_list with removing the buffer from the list as
-- * we can possibly see not yet submitted buffers on io_list
-- */
-- ret = journal_clean_one_cp_list(transaction->
-- t_checkpoint_io_list, destroy);
-- if (need_resched())
-- return;
- /*
- * Stop scanning if we couldn't free the transaction. This
- * avoids pointless scanning of transactions which still
-@@ -663,7 +626,7 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
- jbd2_journal_put_journal_head(jh);
-
- /* Is this transaction empty? */
-- if (transaction->t_checkpoint_list || transaction->t_checkpoint_io_list)
-+ if (transaction->t_checkpoint_list)
- return 0;
-
- /*
-@@ -755,7 +718,6 @@ void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transact
- J_ASSERT(transaction->t_forget == NULL);
- J_ASSERT(transaction->t_shadow_list == NULL);
- J_ASSERT(transaction->t_checkpoint_list == NULL);
-- J_ASSERT(transaction->t_checkpoint_io_list == NULL);
- J_ASSERT(atomic_read(&transaction->t_updates) == 0);
- J_ASSERT(journal->j_committing_transaction != transaction);
- J_ASSERT(journal->j_running_transaction != transaction);
-diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
-index b33155dd70017..1073259902a60 100644
---- a/fs/jbd2/commit.c
-+++ b/fs/jbd2/commit.c
-@@ -1141,8 +1141,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
- spin_lock(&journal->j_list_lock);
- commit_transaction->t_state = T_FINISHED;
- /* Check if the transaction can be dropped now that we are finished */
-- if (commit_transaction->t_checkpoint_list == NULL &&
-- commit_transaction->t_checkpoint_io_list == NULL) {
-+ if (commit_transaction->t_checkpoint_list == NULL) {
- __jbd2_journal_drop_transaction(journal, commit_transaction);
- jbd2_journal_free_transaction(commit_transaction);
- }
-diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
-index f619bae1dcc5d..91a2cf4bc5756 100644
---- a/include/linux/jbd2.h
-+++ b/include/linux/jbd2.h
-@@ -622,12 +622,6 @@ struct transaction_s
- */
- struct journal_head *t_checkpoint_list;
-
-- /*
-- * Doubly-linked circular list of all buffers submitted for IO while
-- * checkpointing. [j_list_lock]
-- */
-- struct journal_head *t_checkpoint_io_list;
--
- /*
- * Doubly-linked circular list of metadata buffers being
- * shadowed by log IO. The IO buffers on the iobuf list and
---
-2.39.2
-
drm-amd-display-update-extended-blank-for-dcn314-onw.patch
drm-amd-display-fix-possible-underflow-for-displays-.patch
drm-amd-display-prevent-vtotal-from-being-set-to-0.patch
-jbd2-remove-t_checkpoint_io_list.patch
-jbd2-remove-journal_clean_one_cp_list.patch
-jbd2-fix-a-race-when-checking-checkpoint-buffer-busy.patch
ext4-add-ext4_mb_hint_goal_only-test-in-ext4_mb_use_.patch
ext4-mballoc-remove-useless-setting-of-ac_criteria.patch
ext4-fix-rbtree-traversal-bug-in-ext4_mb_use_preallo.patch