]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.12-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Apr 2026 11:48:25 +0000 (05:48 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Apr 2026 11:48:25 +0000 (05:48 -0600)
added patches:
ocfs2-split-transactions-in-dio-completion-to-avoid-credit-exhaustion.patch

queue-6.12/ocfs2-split-transactions-in-dio-completion-to-avoid-credit-exhaustion.patch [new file with mode: 0644]
queue-6.12/series

diff --git a/queue-6.12/ocfs2-split-transactions-in-dio-completion-to-avoid-credit-exhaustion.patch b/queue-6.12/ocfs2-split-transactions-in-dio-completion-to-avoid-credit-exhaustion.patch
new file mode 100644 (file)
index 0000000..693d707
--- /dev/null
@@ -0,0 +1,180 @@
+From d647c5b2fbf81560818dacade360abc8c00a9665 Mon Sep 17 00:00:00 2001
+From: Heming Zhao <heming.zhao@suse.com>
+Date: Thu, 2 Apr 2026 21:43:27 +0800
+Subject: ocfs2: split transactions in dio completion to avoid credit exhaustion
+
+From: Heming Zhao <heming.zhao@suse.com>
+
+commit d647c5b2fbf81560818dacade360abc8c00a9665 upstream.
+
+During ocfs2 dio operations, JBD2 may report warnings via following
+call trace:
+ocfs2_dio_end_io_write
+ ocfs2_mark_extent_written
+  ocfs2_change_extent_flag
+   ocfs2_split_extent
+    ocfs2_try_to_merge_extent
+     ocfs2_extend_rotate_transaction
+      ocfs2_extend_trans
+       jbd2__journal_restart
+        start_this_handle
+         output: JBD2: kworker/6:2 wants too many credits credits:5450 rsv_credits:0 max:5449
+
+To prevent exceeding the credits limit, modify ocfs2_dio_end_io_write() to
+handle extents in a batch of transaction.
+
+Additionally, relocate ocfs2_del_inode_from_orphan().  The orphan inode
+should only be removed from the orphan list after the extent tree update
+is complete.  This ensures that if a crash occurs in the middle of extent
+tree updates, we won't leave stale blocks beyond EOF.
+
+This patch also changes the logic for updating the inode size and removing
+orphan, making it similar to ext4_dio_write_end_io().  Both operations are
+performed only when everything looks good.
+
+Finally, thanks to Jans and Joseph for providing the bug fix prototype and
+suggestions.
+
+Link: https://lkml.kernel.org/r/20260402134328.27334-2-heming.zhao@suse.com
+Signed-off-by: Heming Zhao <heming.zhao@suse.com>
+Suggested-by: Jan Kara <jack@suse.cz>
+Suggested-by: Joseph Qi <joseph.qi@linux.alibaba.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
+Cc: Mark Fasheh <mark@fasheh.com>
+Cc: Joel Becker <jlbec@evilplan.org>
+Cc: Junxiao Bi <junxiao.bi@oracle.com>
+Cc: Changwei Ge <gechangwei@live.cn>
+Cc: Jun Piao <piaojun@huawei.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ocfs2/aops.c |   74 ++++++++++++++++++++++++++++++++++----------------------
+ 1 file changed, 45 insertions(+), 29 deletions(-)
+
+--- a/fs/ocfs2/aops.c
++++ b/fs/ocfs2/aops.c
+@@ -37,6 +37,8 @@
+ #include "namei.h"
+ #include "sysfile.h"
++#define OCFS2_DIO_MARK_EXTENT_BATCH 200
++
+ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
+                                  struct buffer_head *bh_result, int create)
+ {
+@@ -2301,7 +2303,7 @@ static int ocfs2_dio_end_io_write(struct
+       struct ocfs2_alloc_context *meta_ac = NULL;
+       handle_t *handle = NULL;
+       loff_t end = offset + bytes;
+-      int ret = 0, credits = 0;
++      int ret = 0, credits = 0, batch = 0;
+       ocfs2_init_dealloc_ctxt(&dealloc);
+@@ -2318,18 +2320,6 @@ static int ocfs2_dio_end_io_write(struct
+               goto out;
+       }
+-      /* Delete orphan before acquire i_rwsem. */
+-      if (dwc->dw_orphaned) {
+-              BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
+-
+-              end = end > i_size_read(inode) ? end : 0;
+-
+-              ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh,
+-                              !!end, end);
+-              if (ret < 0)
+-                      mlog_errno(ret);
+-      }
+-
+       down_write(&oi->ip_alloc_sem);
+       di = (struct ocfs2_dinode *)di_bh->b_data;
+@@ -2350,24 +2340,25 @@ static int ocfs2_dio_end_io_write(struct
+       credits = ocfs2_calc_extend_credits(inode->i_sb, &di->id2.i_list);
+-      handle = ocfs2_start_trans(osb, credits);
+-      if (IS_ERR(handle)) {
+-              ret = PTR_ERR(handle);
+-              mlog_errno(ret);
+-              goto unlock;
+-      }
+-      ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
+-                                    OCFS2_JOURNAL_ACCESS_WRITE);
+-      if (ret) {
+-              mlog_errno(ret);
+-              goto commit;
+-      }
+-
+       list_for_each_entry(ue, &dwc->dw_zero_list, ue_node) {
++              if (!handle) {
++                      handle = ocfs2_start_trans(osb, credits);
++                      if (IS_ERR(handle)) {
++                              ret = PTR_ERR(handle);
++                              mlog_errno(ret);
++                              goto unlock;
++                      }
++                      ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
++                                      OCFS2_JOURNAL_ACCESS_WRITE);
++                      if (ret) {
++                              mlog_errno(ret);
++                              goto commit;
++                      }
++              }
+               ret = ocfs2_assure_trans_credits(handle, credits);
+               if (ret < 0) {
+                       mlog_errno(ret);
+-                      break;
++                      goto commit;
+               }
+               ret = ocfs2_mark_extent_written(inode, &et, handle,
+                                               ue->ue_cpos, 1,
+@@ -2375,19 +2366,44 @@ static int ocfs2_dio_end_io_write(struct
+                                               meta_ac, &dealloc);
+               if (ret < 0) {
+                       mlog_errno(ret);
+-                      break;
++                      goto commit;
++              }
++
++              if (++batch == OCFS2_DIO_MARK_EXTENT_BATCH) {
++                      ocfs2_commit_trans(osb, handle);
++                      handle = NULL;
++                      batch = 0;
+               }
+       }
+       if (end > i_size_read(inode)) {
++              if (!handle) {
++                      handle = ocfs2_start_trans(osb, credits);
++                      if (IS_ERR(handle)) {
++                              ret = PTR_ERR(handle);
++                              mlog_errno(ret);
++                              goto unlock;
++                      }
++              }
+               ret = ocfs2_set_inode_size(handle, inode, di_bh, end);
+               if (ret < 0)
+                       mlog_errno(ret);
+       }
++
+ commit:
+-      ocfs2_commit_trans(osb, handle);
++      if (handle)
++              ocfs2_commit_trans(osb, handle);
+ unlock:
+       up_write(&oi->ip_alloc_sem);
++
++      /* everything looks good, let's start the cleanup */
++      if (!ret && dwc->dw_orphaned) {
++              BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
++
++              ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh, 0, 0);
++              if (ret < 0)
++                      mlog_errno(ret);
++      }
+       ocfs2_inode_unlock(inode, 1);
+       brelse(di_bh);
+ out:
index 0147422f3976fd54b6c4c8ab428bf88719232bdc..339de805103f847e5e4e47a5d737a705ee35fb07 100644 (file)
@@ -24,3 +24,4 @@ rust-init-fix-clippy-undocumented_unsafe_blocks-warn.patch
 drm-amdgpu-use-vmemdup_array_user-in-amdgpu_bo_creat.patch
 drm-amdgpu-limit-bo-list-entry-count-to-prevent-reso.patch
 device-property-make-modifications-of-fwnode-flags-thread-safe.patch
+ocfs2-split-transactions-in-dio-completion-to-avoid-credit-exhaustion.patch