]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.4
authorSasha Levin <sashal@kernel.org>
Sat, 14 Jan 2023 14:23:27 +0000 (09:23 -0500)
committerSasha Levin <sashal@kernel.org>
Sat, 14 Jan 2023 14:23:27 +0000 (09:23 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
16 files changed:
queue-5.4/asoc-intel-bytcr_rt5640-add-quirk-for-the-advantech-.patch-10536 [new file with mode: 0644]
queue-5.4/ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-qu.patch [new file with mode: 0644]
queue-5.4/ext4-fix-uninititialized-value-in-ext4_evict_inode.patch [new file with mode: 0644]
queue-5.4/ext4-fix-use-after-free-in-ext4_orphan_cleanup.patch [new file with mode: 0644]
queue-5.4/ext4-jbd2-provide-accessor-function-for-handle-credi.patch [new file with mode: 0644]
queue-5.4/ext4-lost-matching-pair-of-trace-in-ext4_truncate.patch [new file with mode: 0644]
queue-5.4/ext4-provide-function-to-handle-transaction-restarts.patch [new file with mode: 0644]
queue-5.4/jbd2-drop-pointless-wakeup-from-jbd2_journal_stop.patch [new file with mode: 0644]
queue-5.4/jbd2-factor-out-common-parts-of-stopping-and-restart.patch [new file with mode: 0644]
queue-5.4/jbd2-reorganize-jbd2_journal_stop.patch [new file with mode: 0644]
queue-5.4/jbd2-use-the-correct-print-format.patch [new file with mode: 0644]
queue-5.4/ocfs2-use-accessor-function-for-h_buffer_credits.patch [new file with mode: 0644]
queue-5.4/quota-factor-out-setup-of-quota-inode.patch [new file with mode: 0644]
queue-5.4/series
queue-5.4/usb-ulpi-defer-ulpi_register-on-ulpi_read_id-timeout.patch [new file with mode: 0644]
queue-5.4/wifi-wilc1000-sdio-fix-module-autoloading.patch [new file with mode: 0644]

diff --git a/queue-5.4/asoc-intel-bytcr_rt5640-add-quirk-for-the-advantech-.patch-10536 b/queue-5.4/asoc-intel-bytcr_rt5640-add-quirk-for-the-advantech-.patch-10536
new file mode 100644 (file)
index 0000000..b99524b
--- /dev/null
@@ -0,0 +1,59 @@
+From 43a94a0cc3625f6dfd83b1894c093e4d08402520 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 13 Dec 2022 13:32:46 +0100
+Subject: ASoC: Intel: bytcr_rt5640: Add quirk for the Advantech MICA-071
+ tablet
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit a1dec9d70b6ad97087b60b81d2492134a84208c6 ]
+
+The Advantech MICA-071 tablet deviates from the defaults for
+a non CR Bay Trail based tablet in several ways:
+
+1. It uses an analog MIC on IN3 rather then using DMIC1
+2. It only has 1 speaker
+3. It needs the OVCD current threshold to be set to 1500uA instead of
+   the default 2000uA to reliable differentiate between headphones vs
+   headsets
+
+Add a quirk with these settings for this tablet.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+Link: https://lore.kernel.org/r/20221213123246.11226-1-hdegoede@redhat.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/intel/boards/bytcr_rt5640.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
+index 6a8edb0a559d..6da730636a85 100644
+--- a/sound/soc/intel/boards/bytcr_rt5640.c
++++ b/sound/soc/intel/boards/bytcr_rt5640.c
+@@ -453,6 +453,21 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
++      {
++              /* Advantech MICA-071 */
++              .matches = {
++                      DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Advantech"),
++                      DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MICA-071"),
++              },
++              /* OVCD Th = 1500uA to reliable detect head-phones vs -set */
++              .driver_data = (void *)(BYT_RT5640_IN3_MAP |
++                                      BYT_RT5640_JD_SRC_JD2_IN4N |
++                                      BYT_RT5640_OVCD_TH_1500UA |
++                                      BYT_RT5640_OVCD_SF_0P75 |
++                                      BYT_RT5640_MONO_SPEAKER |
++                                      BYT_RT5640_DIFF_MIC |
++                                      BYT_RT5640_MCLK_EN),
++      },
+       {
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"),
+-- 
+2.35.1
+
diff --git a/queue-5.4/ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-qu.patch b/queue-5.4/ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-qu.patch
new file mode 100644 (file)
index 0000000..217b6a0
--- /dev/null
@@ -0,0 +1,114 @@
+From c002f4c6ba2b250e85c059413a39df931f1263d7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Oct 2022 12:23:07 +0800
+Subject: ext4: fix bug_on in __es_tree_search caused by bad quota inode
+
+From: Baokun Li <libaokun1@huawei.com>
+
+[ Upstream commit d323877484765aaacbb2769b06e355c2041ed115 ]
+
+We got a issue as fllows:
+==================================================================
+ kernel BUG at fs/ext4/extents_status.c:202!
+ invalid opcode: 0000 [#1] PREEMPT SMP
+ CPU: 1 PID: 810 Comm: mount Not tainted 6.1.0-rc1-next-g9631525255e3 #352
+ RIP: 0010:__es_tree_search.isra.0+0xb8/0xe0
+ RSP: 0018:ffffc90001227900 EFLAGS: 00010202
+ RAX: 0000000000000000 RBX: 0000000077512a0f RCX: 0000000000000000
+ RDX: 0000000000000002 RSI: 0000000000002a10 RDI: ffff8881004cd0c8
+ RBP: ffff888177512ac8 R08: 47ffffffffffffff R09: 0000000000000001
+ R10: 0000000000000001 R11: 00000000000679af R12: 0000000000002a10
+ R13: ffff888177512d88 R14: 0000000077512a10 R15: 0000000000000000
+ FS: 00007f4bd76dbc40(0000)GS:ffff88842fd00000(0000)knlGS:0000000000000000
+ CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+ CR2: 00005653bf993cf8 CR3: 000000017bfdf000 CR4: 00000000000006e0
+ DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+ DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+ Call Trace:
+  <TASK>
+  ext4_es_cache_extent+0xe2/0x210
+  ext4_cache_extents+0xd2/0x110
+  ext4_find_extent+0x5d5/0x8c0
+  ext4_ext_map_blocks+0x9c/0x1d30
+  ext4_map_blocks+0x431/0xa50
+  ext4_getblk+0x82/0x340
+  ext4_bread+0x14/0x110
+  ext4_quota_read+0xf0/0x180
+  v2_read_header+0x24/0x90
+  v2_check_quota_file+0x2f/0xa0
+  dquot_load_quota_sb+0x26c/0x760
+  dquot_load_quota_inode+0xa5/0x190
+  ext4_enable_quotas+0x14c/0x300
+  __ext4_fill_super+0x31cc/0x32c0
+  ext4_fill_super+0x115/0x2d0
+  get_tree_bdev+0x1d2/0x360
+  ext4_get_tree+0x19/0x30
+  vfs_get_tree+0x26/0xe0
+  path_mount+0x81d/0xfc0
+  do_mount+0x8d/0xc0
+  __x64_sys_mount+0xc0/0x160
+  do_syscall_64+0x35/0x80
+  entry_SYSCALL_64_after_hwframe+0x63/0xcd
+  </TASK>
+==================================================================
+
+Above issue may happen as follows:
+-------------------------------------
+ext4_fill_super
+ ext4_orphan_cleanup
+  ext4_enable_quotas
+   ext4_quota_enable
+    ext4_iget --> get error inode <5>
+     ext4_ext_check_inode --> Wrong imode makes it escape inspection
+     make_bad_inode(inode) --> EXT4_BOOT_LOADER_INO set imode
+    dquot_load_quota_inode
+     vfs_setup_quota_inode --> check pass
+     dquot_load_quota_sb
+      v2_check_quota_file
+       v2_read_header
+        ext4_quota_read
+         ext4_bread
+          ext4_getblk
+           ext4_map_blocks
+            ext4_ext_map_blocks
+             ext4_find_extent
+              ext4_cache_extents
+               ext4_es_cache_extent
+                __es_tree_search.isra.0
+                 ext4_es_end --> Wrong extents trigger BUG_ON
+
+In the above issue, s_usr_quota_inum is set to 5, but inode<5> contains
+incorrect imode and disordered extents. Because 5 is EXT4_BOOT_LOADER_INO,
+the ext4_ext_check_inode check in the ext4_iget function can be bypassed,
+finally, the extents that are not checked trigger the BUG_ON in the
+__es_tree_search function. To solve this issue, check whether the inode is
+bad_inode in vfs_setup_quota_inode().
+
+Signed-off-by: Baokun Li <libaokun1@huawei.com>
+Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
+Reviewed-by: Jason Yan <yanaijie@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20221026042310.3839669-2-libaokun1@huawei.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/quota/dquot.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
+index 84f61ab05890..1d652af48f0b 100644
+--- a/fs/quota/dquot.c
++++ b/fs/quota/dquot.c
+@@ -2311,6 +2311,8 @@ static int vfs_setup_quota_inode(struct inode *inode, int type)
+       struct super_block *sb = inode->i_sb;
+       struct quota_info *dqopt = sb_dqopt(sb);
++      if (is_bad_inode(inode))
++              return -EUCLEAN;
+       if (!S_ISREG(inode->i_mode))
+               return -EACCES;
+       if (IS_RDONLY(inode))
+-- 
+2.35.1
+
diff --git a/queue-5.4/ext4-fix-uninititialized-value-in-ext4_evict_inode.patch b/queue-5.4/ext4-fix-uninititialized-value-in-ext4_evict_inode.patch
new file mode 100644 (file)
index 0000000..cf9ef58
--- /dev/null
@@ -0,0 +1,97 @@
+From 85f6be5c405641d72662bd1dd4bc2530ed6d26d6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Nov 2022 15:36:03 +0800
+Subject: ext4: fix uninititialized value in 'ext4_evict_inode'
+
+From: Ye Bin <yebin10@huawei.com>
+
+[ Upstream commit 7ea71af94eaaaf6d9aed24bc94a05b977a741cb9 ]
+
+Syzbot found the following issue:
+=====================================================
+BUG: KMSAN: uninit-value in ext4_evict_inode+0xdd/0x26b0 fs/ext4/inode.c:180
+ ext4_evict_inode+0xdd/0x26b0 fs/ext4/inode.c:180
+ evict+0x365/0x9a0 fs/inode.c:664
+ iput_final fs/inode.c:1747 [inline]
+ iput+0x985/0xdd0 fs/inode.c:1773
+ __ext4_new_inode+0xe54/0x7ec0 fs/ext4/ialloc.c:1361
+ ext4_mknod+0x376/0x840 fs/ext4/namei.c:2844
+ vfs_mknod+0x79d/0x830 fs/namei.c:3914
+ do_mknodat+0x47d/0xaa0
+ __do_sys_mknodat fs/namei.c:3992 [inline]
+ __se_sys_mknodat fs/namei.c:3989 [inline]
+ __ia32_sys_mknodat+0xeb/0x150 fs/namei.c:3989
+ do_syscall_32_irqs_on arch/x86/entry/common.c:112 [inline]
+ __do_fast_syscall_32+0xa2/0x100 arch/x86/entry/common.c:178
+ do_fast_syscall_32+0x33/0x70 arch/x86/entry/common.c:203
+ do_SYSENTER_32+0x1b/0x20 arch/x86/entry/common.c:246
+ entry_SYSENTER_compat_after_hwframe+0x70/0x82
+
+Uninit was created at:
+ __alloc_pages+0x9f1/0xe80 mm/page_alloc.c:5578
+ alloc_pages+0xaae/0xd80 mm/mempolicy.c:2285
+ alloc_slab_page mm/slub.c:1794 [inline]
+ allocate_slab+0x1b5/0x1010 mm/slub.c:1939
+ new_slab mm/slub.c:1992 [inline]
+ ___slab_alloc+0x10c3/0x2d60 mm/slub.c:3180
+ __slab_alloc mm/slub.c:3279 [inline]
+ slab_alloc_node mm/slub.c:3364 [inline]
+ slab_alloc mm/slub.c:3406 [inline]
+ __kmem_cache_alloc_lru mm/slub.c:3413 [inline]
+ kmem_cache_alloc_lru+0x6f3/0xb30 mm/slub.c:3429
+ alloc_inode_sb include/linux/fs.h:3117 [inline]
+ ext4_alloc_inode+0x5f/0x860 fs/ext4/super.c:1321
+ alloc_inode+0x83/0x440 fs/inode.c:259
+ new_inode_pseudo fs/inode.c:1018 [inline]
+ new_inode+0x3b/0x430 fs/inode.c:1046
+ __ext4_new_inode+0x2a7/0x7ec0 fs/ext4/ialloc.c:959
+ ext4_mkdir+0x4d5/0x1560 fs/ext4/namei.c:2992
+ vfs_mkdir+0x62a/0x870 fs/namei.c:4035
+ do_mkdirat+0x466/0x7b0 fs/namei.c:4060
+ __do_sys_mkdirat fs/namei.c:4075 [inline]
+ __se_sys_mkdirat fs/namei.c:4073 [inline]
+ __ia32_sys_mkdirat+0xc4/0x120 fs/namei.c:4073
+ do_syscall_32_irqs_on arch/x86/entry/common.c:112 [inline]
+ __do_fast_syscall_32+0xa2/0x100 arch/x86/entry/common.c:178
+ do_fast_syscall_32+0x33/0x70 arch/x86/entry/common.c:203
+ do_SYSENTER_32+0x1b/0x20 arch/x86/entry/common.c:246
+ entry_SYSENTER_compat_after_hwframe+0x70/0x82
+
+CPU: 1 PID: 4625 Comm: syz-executor.2 Not tainted 6.1.0-rc4-syzkaller-62821-gcb231e2f67ec #0
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/26/2022
+=====================================================
+
+Now, 'ext4_alloc_inode()' didn't init 'ei->i_flags'. If new inode failed
+before set 'ei->i_flags' in '__ext4_new_inode()', then do 'iput()'. As after
+6bc0d63dad7f commit will access 'ei->i_flags' in 'ext4_evict_inode()' which
+will lead to access uninit-value.
+To solve above issue just init 'ei->i_flags' in 'ext4_alloc_inode()'.
+
+Reported-by: syzbot+57b25da729eb0b88177d@syzkaller.appspotmail.com
+Signed-off-by: Ye Bin <yebin10@huawei.com>
+Fixes: 6bc0d63dad7f ("ext4: remove EA inode entry from mbcache on inode eviction")
+Reviewed-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Eric Biggers <ebiggers@google.com>
+Link: https://lore.kernel.org/r/20221117073603.2598882-1-yebin@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/super.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index 4c014d67dfaf..789a9f6a2ec6 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -1085,6 +1085,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
+               return NULL;
+       inode_set_iversion(&ei->vfs_inode, 1);
++      ei->i_flags = 0;
+       spin_lock_init(&ei->i_raw_lock);
+       INIT_LIST_HEAD(&ei->i_prealloc_list);
+       spin_lock_init(&ei->i_prealloc_lock);
+-- 
+2.35.1
+
diff --git a/queue-5.4/ext4-fix-use-after-free-in-ext4_orphan_cleanup.patch b/queue-5.4/ext4-fix-use-after-free-in-ext4_orphan_cleanup.patch
new file mode 100644 (file)
index 0000000..d771c62
--- /dev/null
@@ -0,0 +1,80 @@
+From 6f96c33700f094419c8c7019a3f988ef1ece0ad7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Nov 2022 16:06:33 +0800
+Subject: ext4: fix use-after-free in ext4_orphan_cleanup
+
+From: Baokun Li <libaokun1@huawei.com>
+
+[ Upstream commit a71248b1accb2b42e4980afef4fa4a27fa0e36f5 ]
+
+I caught a issue as follows:
+==================================================================
+ BUG: KASAN: use-after-free in __list_add_valid+0x28/0x1a0
+ Read of size 8 at addr ffff88814b13f378 by task mount/710
+
+ CPU: 1 PID: 710 Comm: mount Not tainted 6.1.0-rc3-next #370
+ Call Trace:
+  <TASK>
+  dump_stack_lvl+0x73/0x9f
+  print_report+0x25d/0x759
+  kasan_report+0xc0/0x120
+  __asan_load8+0x99/0x140
+  __list_add_valid+0x28/0x1a0
+  ext4_orphan_cleanup+0x564/0x9d0 [ext4]
+  __ext4_fill_super+0x48e2/0x5300 [ext4]
+  ext4_fill_super+0x19f/0x3a0 [ext4]
+  get_tree_bdev+0x27b/0x450
+  ext4_get_tree+0x19/0x30 [ext4]
+  vfs_get_tree+0x49/0x150
+  path_mount+0xaae/0x1350
+  do_mount+0xe2/0x110
+  __x64_sys_mount+0xf0/0x190
+  do_syscall_64+0x35/0x80
+  entry_SYSCALL_64_after_hwframe+0x63/0xcd
+  </TASK>
+ [...]
+==================================================================
+
+Above issue may happen as follows:
+-------------------------------------
+ext4_fill_super
+  ext4_orphan_cleanup
+   --- loop1: assume last_orphan is 12 ---
+    list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan)
+    ext4_truncate --> return 0
+      ext4_inode_attach_jinode --> return -ENOMEM
+    iput(inode) --> free inode<12>
+   --- loop2: last_orphan is still 12 ---
+    list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan);
+    // use inode<12> and trigger UAF
+
+To solve this issue, we need to propagate the return value of
+ext4_inode_attach_jinode() appropriately.
+
+Signed-off-by: Baokun Li <libaokun1@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20221102080633.1630225-1-libaokun1@huawei.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/inode.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 5eb1d9ac269c..0830a4de47bc 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -4530,7 +4530,8 @@ int ext4_truncate(struct inode *inode)
+       /* If we zero-out tail of the page, we have to create jinode for jbd2 */
+       if (inode->i_size & (inode->i_sb->s_blocksize - 1)) {
+-              if (ext4_inode_attach_jinode(inode) < 0)
++              err = ext4_inode_attach_jinode(inode);
++              if (err)
+                       goto out_trace;
+       }
+-- 
+2.35.1
+
diff --git a/queue-5.4/ext4-jbd2-provide-accessor-function-for-handle-credi.patch b/queue-5.4/ext4-jbd2-provide-accessor-function-for-handle-credi.patch
new file mode 100644 (file)
index 0000000..6c2ed4b
--- /dev/null
@@ -0,0 +1,124 @@
+From da383a89ea15bc937f28cf199eeee546d82be16a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Nov 2019 17:44:17 +0100
+Subject: ext4, jbd2: Provide accessor function for handle credits
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit a9a8344ee1714f835ba394077e8c13d751e2f148 ]
+
+Provide accessor function to get number of credits available in a handle
+and use it from ext4. Later, computation of available credits won't be
+so straightforward.
+
+Reviewed-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20191105164437.32602-11-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: d87a7b4c77a9 ("jbd2: use the correct print format")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/ext4_jbd2.c  | 13 +++++++------
+ fs/ext4/ext4_jbd2.h  |  7 -------
+ fs/ext4/xattr.c      |  2 +-
+ include/linux/jbd2.h |  6 ++++++
+ 4 files changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
+index 2b98d893cda9..731bbfdbce5b 100644
+--- a/fs/ext4/ext4_jbd2.c
++++ b/fs/ext4/ext4_jbd2.c
+@@ -119,8 +119,8 @@ handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
+               return ext4_get_nojournal();
+       sb = handle->h_journal->j_private;
+-      trace_ext4_journal_start_reserved(sb, handle->h_buffer_credits,
+-                                        _RET_IP_);
++      trace_ext4_journal_start_reserved(sb,
++                              jbd2_handle_buffer_credits(handle), _RET_IP_);
+       err = ext4_journal_check_start(sb);
+       if (err < 0) {
+               jbd2_journal_free_reserved(handle);
+@@ -138,10 +138,10 @@ int __ext4_journal_ensure_credits(handle_t *handle, int check_cred,
+ {
+       if (!ext4_handle_valid(handle))
+               return 0;
+-      if (handle->h_buffer_credits >= check_cred)
++      if (jbd2_handle_buffer_credits(handle) >= check_cred)
+               return 0;
+       return ext4_journal_extend(handle,
+-                                 extend_cred - handle->h_buffer_credits);
++                         extend_cred - jbd2_handle_buffer_credits(handle));
+ }
+ static void ext4_journal_abort_handle(const char *caller, unsigned int line,
+@@ -289,7 +289,7 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
+                                      handle->h_type,
+                                      handle->h_line_no,
+                                      handle->h_requested_credits,
+-                                     handle->h_buffer_credits, err);
++                                     jbd2_handle_buffer_credits(handle), err);
+                               return err;
+                       }
+                       ext4_error_inode(inode, where, line,
+@@ -300,7 +300,8 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
+                                        handle->h_type,
+                                        handle->h_line_no,
+                                        handle->h_requested_credits,
+-                                       handle->h_buffer_credits, err);
++                                       jbd2_handle_buffer_credits(handle),
++                                       err);
+               }
+       } else {
+               if (inode)
+diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
+index 481bf770a374..a4b980eae4da 100644
+--- a/fs/ext4/ext4_jbd2.h
++++ b/fs/ext4/ext4_jbd2.h
+@@ -288,13 +288,6 @@ static inline int ext4_handle_is_aborted(handle_t *handle)
+       return 0;
+ }
+-static inline int ext4_handle_has_enough_credits(handle_t *handle, int needed)
+-{
+-      if (ext4_handle_valid(handle) && handle->h_buffer_credits < needed)
+-              return 0;
+-      return 1;
+-}
+-
+ #define ext4_journal_start_sb(sb, type, nblocks)                      \
+       __ext4_journal_start_sb((sb), __LINE__, (type), (nblocks), 0)
+diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
+index cf1af6a4a567..40f76cf6d031 100644
+--- a/fs/ext4/xattr.c
++++ b/fs/ext4/xattr.c
+@@ -2330,7 +2330,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
+                                                  flags & XATTR_CREATE);
+               brelse(bh);
+-              if (!ext4_handle_has_enough_credits(handle, credits)) {
++              if (jbd2_handle_buffer_credits(handle) < credits) {
+                       error = -ENOSPC;
+                       goto cleanup;
+               }
+diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
+index b0e97e5de8ca..a0768a4b3e84 100644
+--- a/include/linux/jbd2.h
++++ b/include/linux/jbd2.h
+@@ -1644,6 +1644,12 @@ static inline tid_t  jbd2_get_latest_transaction(journal_t *journal)
+       return tid;
+ }
++
++static inline int jbd2_handle_buffer_credits(handle_t *handle)
++{
++      return handle->h_buffer_credits;
++}
++
+ #ifdef __KERNEL__
+ #define buffer_trace_init(bh) do {} while (0)
+-- 
+2.35.1
+
diff --git a/queue-5.4/ext4-lost-matching-pair-of-trace-in-ext4_truncate.patch b/queue-5.4/ext4-lost-matching-pair-of-trace-in-ext4_truncate.patch
new file mode 100644 (file)
index 0000000..b477bda
--- /dev/null
@@ -0,0 +1,79 @@
+From 9bd6f19f9a8ea9041eadb1d5e259e647a34705a2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Jul 2020 16:30:27 +0800
+Subject: ext4: lost matching-pair of trace in ext4_truncate
+
+From: zhengliang <zhengliang6@huawei.com>
+
+[ Upstream commit 9a5d265fed014115f35e598022c956e5d2fb863e ]
+
+It should call trace exit in all return path for ext4_truncate.
+
+Signed-off-by: zhengliang <zhengliang6@huawei.com>
+Reviewed-by: Andreas Dilger <adilger@dilger.ca>
+Reviewed-by: Ritesh Harjani <riteshh@linux.ibm.com>
+Link: https://lore.kernel.org/r/20200701083027.45996-1-zhengliang6@huawei.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: a71248b1accb ("ext4: fix use-after-free in ext4_orphan_cleanup")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/inode.c | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index a39567e03580..5eb1d9ac269c 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -4513,7 +4513,7 @@ int ext4_truncate(struct inode *inode)
+       trace_ext4_truncate_enter(inode);
+       if (!ext4_can_truncate(inode))
+-              return 0;
++              goto out_trace;
+       ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
+@@ -4524,16 +4524,14 @@ int ext4_truncate(struct inode *inode)
+               int has_inline = 1;
+               err = ext4_inline_data_truncate(inode, &has_inline);
+-              if (err)
+-                      return err;
+-              if (has_inline)
+-                      return 0;
++              if (err || has_inline)
++                      goto out_trace;
+       }
+       /* If we zero-out tail of the page, we have to create jinode for jbd2 */
+       if (inode->i_size & (inode->i_sb->s_blocksize - 1)) {
+               if (ext4_inode_attach_jinode(inode) < 0)
+-                      return 0;
++                      goto out_trace;
+       }
+       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
+@@ -4542,8 +4540,10 @@ int ext4_truncate(struct inode *inode)
+               credits = ext4_blocks_for_truncate(inode);
+       handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
+-      if (IS_ERR(handle))
+-              return PTR_ERR(handle);
++      if (IS_ERR(handle)) {
++              err = PTR_ERR(handle);
++              goto out_trace;
++      }
+       if (inode->i_size & (inode->i_sb->s_blocksize - 1))
+               ext4_block_truncate_page(handle, mapping, inode->i_size);
+@@ -4592,6 +4592,7 @@ int ext4_truncate(struct inode *inode)
+       ext4_mark_inode_dirty(handle, inode);
+       ext4_journal_stop(handle);
++out_trace:
+       trace_ext4_truncate_exit(inode);
+       return err;
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.4/ext4-provide-function-to-handle-transaction-restarts.patch b/queue-5.4/ext4-provide-function-to-handle-transaction-restarts.patch
new file mode 100644 (file)
index 0000000..b17bfcc
--- /dev/null
@@ -0,0 +1,799 @@
+From 629cf5472a71183744208ab6d8ee4305367bb86b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Nov 2019 17:44:16 +0100
+Subject: ext4: Provide function to handle transaction restarts
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit a413036791d040e33badcc634453a4d0c0705499 ]
+
+Provide ext4_journal_ensure_credits_fn() function to ensure transaction
+has given amount of credits and call helper function to prepare for
+restarting a transaction. This allows to remove some boilerplate code
+from various places, add proper error handling for the case where
+transaction extension or restart fails, and reduces following changes
+needed for proper revoke record reservation tracking.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20191105164437.32602-10-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: d87a7b4c77a9 ("jbd2: use the correct print format")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/ext4.h      |  4 +-
+ fs/ext4/ext4_jbd2.c | 11 ++++++
+ fs/ext4/ext4_jbd2.h | 48 +++++++++++++++++++++++
+ fs/ext4/extents.c   | 68 +++++++++++++++++++-------------
+ fs/ext4/indirect.c  | 93 +++++++++++++++++++++++++-------------------
+ fs/ext4/inode.c     | 26 -------------
+ fs/ext4/migrate.c   | 95 +++++++++++++++++----------------------------
+ fs/ext4/resize.c    | 46 +++++-----------------
+ fs/ext4/xattr.c     | 90 ++++++++++++++++--------------------------
+ 9 files changed, 234 insertions(+), 247 deletions(-)
+
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index 946804c3c4b1..6017a55b3834 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -2634,7 +2634,6 @@ extern int ext4_can_truncate(struct inode *inode);
+ extern int ext4_truncate(struct inode *);
+ extern int ext4_break_layouts(struct inode *);
+ extern int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length);
+-extern int ext4_truncate_restart_trans(handle_t *, struct inode *, int nblocks);
+ extern void ext4_set_inode_flags(struct inode *);
+ extern int ext4_alloc_da_blocks(struct inode *inode);
+ extern void ext4_set_aops(struct inode *inode);
+@@ -3327,6 +3326,9 @@ extern int ext4_swap_extents(handle_t *handle, struct inode *inode1,
+                            ext4_lblk_t lblk2,  ext4_lblk_t count,
+                            int mark_unwritten,int *err);
+ extern int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu);
++extern int ext4_datasem_ensure_credits(handle_t *handle, struct inode *inode,
++                                     int check_cred, int restart_cred);
++
+ /* move_extent.c */
+ extern void ext4_double_down_write_data_sem(struct inode *first,
+diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
+index 7c70b08d104c..2b98d893cda9 100644
+--- a/fs/ext4/ext4_jbd2.c
++++ b/fs/ext4/ext4_jbd2.c
+@@ -133,6 +133,17 @@ handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
+       return handle;
+ }
++int __ext4_journal_ensure_credits(handle_t *handle, int check_cred,
++                                int extend_cred)
++{
++      if (!ext4_handle_valid(handle))
++              return 0;
++      if (handle->h_buffer_credits >= check_cred)
++              return 0;
++      return ext4_journal_extend(handle,
++                                 extend_cred - handle->h_buffer_credits);
++}
++
+ static void ext4_journal_abort_handle(const char *caller, unsigned int line,
+                                     const char *err_fn,
+                                     struct buffer_head *bh,
+diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
+index ef8fcf7d0d3b..481bf770a374 100644
+--- a/fs/ext4/ext4_jbd2.h
++++ b/fs/ext4/ext4_jbd2.h
+@@ -346,6 +346,54 @@ static inline int ext4_journal_restart(handle_t *handle, int nblocks)
+       return 0;
+ }
++int __ext4_journal_ensure_credits(handle_t *handle, int check_cred,
++                                int extend_cred);
++
++
++/*
++ * Ensure @handle has at least @check_creds credits available. If not,
++ * transaction will be extended or restarted to contain at least @extend_cred
++ * credits. Before restarting transaction @fn is executed to allow for cleanup
++ * before the transaction is restarted.
++ *
++ * The return value is < 0 in case of error, 0 in case the handle has enough
++ * credits or transaction extension succeeded, 1 in case transaction had to be
++ * restarted.
++ */
++#define ext4_journal_ensure_credits_fn(handle, check_cred, extend_cred, fn) \
++({                                                                    \
++      __label__ __ensure_end;                                         \
++      int err = __ext4_journal_ensure_credits((handle), (check_cred), \
++                                              (extend_cred));         \
++                                                                      \
++      if (err <= 0)                                                   \
++              goto __ensure_end;                                      \
++      err = (fn);                                                     \
++      if (err < 0)                                                    \
++              goto __ensure_end;                                      \
++      err = ext4_journal_restart((handle), (extend_cred));            \
++      if (err == 0)                                                   \
++              err = 1;                                                \
++__ensure_end:                                                         \
++      err;                                                            \
++})
++
++/*
++ * Ensure given handle has at least requested amount of credits available,
++ * possibly restarting transaction if needed.
++ */
++static inline int ext4_journal_ensure_credits(handle_t *handle, int credits)
++{
++      return ext4_journal_ensure_credits_fn(handle, credits, credits, 0);
++}
++
++static inline int ext4_journal_ensure_credits_batch(handle_t *handle,
++                                                  int credits)
++{
++      return ext4_journal_ensure_credits_fn(handle, credits,
++                                            EXT4_MAX_TRANS_DATA, 0);
++}
++
+ static inline int ext4_journal_blocks_per_page(struct inode *inode)
+ {
+       if (EXT4_JOURNAL(inode) != NULL)
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+index 27760c39f70e..81226addfefe 100644
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -100,29 +100,40 @@ static int ext4_split_extent_at(handle_t *handle,
+ static int ext4_find_delayed_extent(struct inode *inode,
+                                   struct extent_status *newes);
+-static int ext4_ext_truncate_extend_restart(handle_t *handle,
+-                                          struct inode *inode,
+-                                          int needed)
++static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped)
+ {
+-      int err;
+-
+-      if (!ext4_handle_valid(handle))
+-              return 0;
+-      if (handle->h_buffer_credits >= needed)
+-              return 0;
+       /*
+-       * If we need to extend the journal get a few extra blocks
+-       * while we're at it for efficiency's sake.
++       * Drop i_data_sem to avoid deadlock with ext4_map_blocks.  At this
++       * moment, get_block can be called only for blocks inside i_size since
++       * page cache has been already dropped and writes are blocked by
++       * i_mutex. So we can safely drop the i_data_sem here.
+        */
+-      needed += 3;
+-      err = ext4_journal_extend(handle, needed - handle->h_buffer_credits);
+-      if (err <= 0)
+-              return err;
+-      err = ext4_truncate_restart_trans(handle, inode, needed);
+-      if (err == 0)
+-              err = -EAGAIN;
++      BUG_ON(EXT4_JOURNAL(inode) == NULL);
++      ext4_discard_preallocations(inode);
++      up_write(&EXT4_I(inode)->i_data_sem);
++      *dropped = 1;
++      return 0;
++}
+-      return err;
++/*
++ * Make sure 'handle' has at least 'check_cred' credits. If not, restart
++ * transaction with 'restart_cred' credits. The function drops i_data_sem
++ * when restarting transaction and gets it after transaction is restarted.
++ *
++ * The function returns 0 on success, 1 if transaction had to be restarted,
++ * and < 0 in case of fatal error.
++ */
++int ext4_datasem_ensure_credits(handle_t *handle, struct inode *inode,
++                              int check_cred, int restart_cred)
++{
++      int ret;
++      int dropped = 0;
++
++      ret = ext4_journal_ensure_credits_fn(handle, check_cred, restart_cred,
++                      ext4_ext_trunc_restart_fn(inode, &dropped));
++      if (dropped)
++              down_write(&EXT4_I(inode)->i_data_sem);
++      return ret;
+ }
+ /*
+@@ -2868,9 +2879,13 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
+               }
+               credits += EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb);
+-              err = ext4_ext_truncate_extend_restart(handle, inode, credits);
+-              if (err)
++              err = ext4_datasem_ensure_credits(handle, inode, credits,
++                                                credits);
++              if (err) {
++                      if (err > 0)
++                              err = -EAGAIN;
+                       goto out;
++              }
+               err = ext4_ext_get_access(handle, inode, path + depth);
+               if (err)
+@@ -5259,13 +5274,10 @@ ext4_access_path(handle_t *handle, struct inode *inode,
+        * descriptor) for each block group; assume two block
+        * groups
+        */
+-      if (handle->h_buffer_credits < 7) {
+-              credits = ext4_writepage_trans_blocks(inode);
+-              err = ext4_ext_truncate_extend_restart(handle, inode, credits);
+-              /* EAGAIN is success */
+-              if (err && err != -EAGAIN)
+-                      return err;
+-      }
++      credits = ext4_writepage_trans_blocks(inode);
++      err = ext4_datasem_ensure_credits(handle, inode, 7, credits);
++      if (err < 0)
++              return err;
+       err = ext4_ext_get_access(handle, inode, path);
+       return err;
+diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
+index a131d2781342..9e13e31a1a22 100644
+--- a/fs/ext4/indirect.c
++++ b/fs/ext4/indirect.c
+@@ -696,27 +696,62 @@ int ext4_ind_trans_blocks(struct inode *inode, int nrblocks)
+       return DIV_ROUND_UP(nrblocks, EXT4_ADDR_PER_BLOCK(inode->i_sb)) + 4;
+ }
++static int ext4_ind_trunc_restart_fn(handle_t *handle, struct inode *inode,
++                                   struct buffer_head *bh, int *dropped)
++{
++      int err;
++
++      if (bh) {
++              BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
++              err = ext4_handle_dirty_metadata(handle, inode, bh);
++              if (unlikely(err))
++                      return err;
++      }
++      err = ext4_mark_inode_dirty(handle, inode);
++      if (unlikely(err))
++              return err;
++      /*
++       * Drop i_data_sem to avoid deadlock with ext4_map_blocks.  At this
++       * moment, get_block can be called only for blocks inside i_size since
++       * page cache has been already dropped and writes are blocked by
++       * i_mutex. So we can safely drop the i_data_sem here.
++       */
++      BUG_ON(EXT4_JOURNAL(inode) == NULL);
++      ext4_discard_preallocations(inode);
++      up_write(&EXT4_I(inode)->i_data_sem);
++      *dropped = 1;
++      return 0;
++}
++
+ /*
+  * Truncate transactions can be complex and absolutely huge.  So we need to
+  * be able to restart the transaction at a conventient checkpoint to make
+  * sure we don't overflow the journal.
+  *
+  * Try to extend this transaction for the purposes of truncation.  If
+- * extend fails, we need to propagate the failure up and restart the
+- * transaction in the top-level truncate loop. --sct
+- *
+- * Returns 0 if we managed to create more room.  If we can't create more
+- * room, and the transaction must be restarted we return 1.
++ * extend fails, we restart transaction.
+  */
+-static int try_to_extend_transaction(handle_t *handle, struct inode *inode)
++static int ext4_ind_truncate_ensure_credits(handle_t *handle,
++                                          struct inode *inode,
++                                          struct buffer_head *bh)
+ {
+-      if (!ext4_handle_valid(handle))
+-              return 0;
+-      if (ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS+1))
+-              return 0;
+-      if (!ext4_journal_extend(handle, ext4_blocks_for_truncate(inode)))
+-              return 0;
+-      return 1;
++      int ret;
++      int dropped = 0;
++
++      ret = ext4_journal_ensure_credits_fn(handle, EXT4_RESERVE_TRANS_BLOCKS,
++                      ext4_blocks_for_truncate(inode),
++                      ext4_ind_trunc_restart_fn(handle, inode, bh, &dropped));
++      if (dropped)
++              down_write(&EXT4_I(inode)->i_data_sem);
++      if (ret <= 0)
++              return ret;
++      if (bh) {
++              BUFFER_TRACE(bh, "retaking write access");
++              ret = ext4_journal_get_write_access(handle, bh);
++              if (unlikely(ret))
++                      return ret;
++      }
++      return 0;
+ }
+ /*
+@@ -851,27 +886,9 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
+               return 1;
+       }
+-      if (try_to_extend_transaction(handle, inode)) {
+-              if (bh) {
+-                      BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
+-                      err = ext4_handle_dirty_metadata(handle, inode, bh);
+-                      if (unlikely(err))
+-                              goto out_err;
+-              }
+-              err = ext4_mark_inode_dirty(handle, inode);
+-              if (unlikely(err))
+-                      goto out_err;
+-              err = ext4_truncate_restart_trans(handle, inode,
+-                                      ext4_blocks_for_truncate(inode));
+-              if (unlikely(err))
+-                      goto out_err;
+-              if (bh) {
+-                      BUFFER_TRACE(bh, "retaking write access");
+-                      err = ext4_journal_get_write_access(handle, bh);
+-                      if (unlikely(err))
+-                              goto out_err;
+-              }
+-      }
++      err = ext4_ind_truncate_ensure_credits(handle, inode, bh);
++      if (err < 0)
++              goto out_err;
+       for (p = first; p < last; p++)
+               *p = 0;
+@@ -1054,11 +1071,9 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
+                        */
+                       if (ext4_handle_is_aborted(handle))
+                               return;
+-                      if (try_to_extend_transaction(handle, inode)) {
+-                              ext4_mark_inode_dirty(handle, inode);
+-                              ext4_truncate_restart_trans(handle, inode,
+-                                          ext4_blocks_for_truncate(inode));
+-                      }
++                      if (ext4_ind_truncate_ensure_credits(handle, inode,
++                                                           NULL) < 0)
++                              return;
+                       /*
+                        * The forget flag here is critical because if
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index b38427b8d083..a39567e03580 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -163,32 +163,6 @@ int ext4_inode_is_fast_symlink(struct inode *inode)
+              (inode->i_size < EXT4_N_BLOCKS * 4);
+ }
+-/*
+- * Restart the transaction associated with *handle.  This does a commit,
+- * so before we call here everything must be consistently dirtied against
+- * this transaction.
+- */
+-int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode,
+-                               int nblocks)
+-{
+-      int ret;
+-
+-      /*
+-       * Drop i_data_sem to avoid deadlock with ext4_map_blocks.  At this
+-       * moment, get_block can be called only for blocks inside i_size since
+-       * page cache has been already dropped and writes are blocked by
+-       * i_mutex. So we can safely drop the i_data_sem here.
+-       */
+-      BUG_ON(EXT4_JOURNAL(inode) == NULL);
+-      jbd_debug(2, "restarting handle %p\n", handle);
+-      up_write(&EXT4_I(inode)->i_data_sem);
+-      ret = ext4_journal_restart(handle, nblocks);
+-      down_write(&EXT4_I(inode)->i_data_sem);
+-      ext4_discard_preallocations(inode);
+-
+-      return ret;
+-}
+-
+ /*
+  * Called at the last iput() if i_nlink is zero.
+  */
+diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
+index dbba3c3a2f06..6d1243819ab3 100644
+--- a/fs/ext4/migrate.c
++++ b/fs/ext4/migrate.c
+@@ -50,29 +50,9 @@ static int finish_range(handle_t *handle, struct inode *inode,
+       needed = ext4_ext_calc_credits_for_single_extent(inode,
+                   lb->last_block - lb->first_block + 1, path);
+-      /*
+-       * Make sure the credit we accumalated is not really high
+-       */
+-      if (needed && ext4_handle_has_enough_credits(handle,
+-                                              EXT4_RESERVE_TRANS_BLOCKS)) {
+-              up_write((&EXT4_I(inode)->i_data_sem));
+-              retval = ext4_journal_restart(handle, needed);
+-              down_write((&EXT4_I(inode)->i_data_sem));
+-              if (retval)
+-                      goto err_out;
+-      } else if (needed) {
+-              retval = ext4_journal_extend(handle, needed);
+-              if (retval) {
+-                      /*
+-                       * IF not able to extend the journal restart the journal
+-                       */
+-                      up_write((&EXT4_I(inode)->i_data_sem));
+-                      retval = ext4_journal_restart(handle, needed);
+-                      down_write((&EXT4_I(inode)->i_data_sem));
+-                      if (retval)
+-                              goto err_out;
+-              }
+-      }
++      retval = ext4_datasem_ensure_credits(handle, inode, needed, needed);
++      if (retval < 0)
++              goto err_out;
+       retval = ext4_ext_insert_extent(handle, inode, &path, &newext, 0);
+ err_out:
+       up_write((&EXT4_I(inode)->i_data_sem));
+@@ -196,26 +176,6 @@ static int update_tind_extent_range(handle_t *handle, struct inode *inode,
+ }
+-static int extend_credit_for_blkdel(handle_t *handle, struct inode *inode)
+-{
+-      int retval = 0, needed;
+-
+-      if (ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS+1))
+-              return 0;
+-      /*
+-       * We are freeing a blocks. During this we touch
+-       * superblock, group descriptor and block bitmap.
+-       * So allocate a credit of 3. We may update
+-       * quota (user and group).
+-       */
+-      needed = 3 + EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb);
+-
+-      if (ext4_journal_extend(handle, needed) != 0)
+-              retval = ext4_journal_restart(handle, needed);
+-
+-      return retval;
+-}
+-
+ static int free_dind_blocks(handle_t *handle,
+                               struct inode *inode, __le32 i_data)
+ {
+@@ -223,6 +183,7 @@ static int free_dind_blocks(handle_t *handle,
+       __le32 *tmp_idata;
+       struct buffer_head *bh;
+       unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
++      int err;
+       bh = ext4_sb_bread(inode->i_sb, le32_to_cpu(i_data), 0);
+       if (IS_ERR(bh))
+@@ -231,7 +192,12 @@ static int free_dind_blocks(handle_t *handle,
+       tmp_idata = (__le32 *)bh->b_data;
+       for (i = 0; i < max_entries; i++) {
+               if (tmp_idata[i]) {
+-                      extend_credit_for_blkdel(handle, inode);
++                      err = ext4_journal_ensure_credits(handle,
++                                              EXT4_RESERVE_TRANS_BLOCKS);
++                      if (err < 0) {
++                              put_bh(bh);
++                              return err;
++                      }
+                       ext4_free_blocks(handle, inode, NULL,
+                                        le32_to_cpu(tmp_idata[i]), 1,
+                                        EXT4_FREE_BLOCKS_METADATA |
+@@ -239,7 +205,9 @@ static int free_dind_blocks(handle_t *handle,
+               }
+       }
+       put_bh(bh);
+-      extend_credit_for_blkdel(handle, inode);
++      err = ext4_journal_ensure_credits(handle, EXT4_RESERVE_TRANS_BLOCKS);
++      if (err < 0)
++              return err;
+       ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1,
+                        EXT4_FREE_BLOCKS_METADATA |
+                        EXT4_FREE_BLOCKS_FORGET);
+@@ -270,7 +238,9 @@ static int free_tind_blocks(handle_t *handle,
+               }
+       }
+       put_bh(bh);
+-      extend_credit_for_blkdel(handle, inode);
++      retval = ext4_journal_ensure_credits(handle, EXT4_RESERVE_TRANS_BLOCKS);
++      if (retval < 0)
++              return retval;
+       ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1,
+                        EXT4_FREE_BLOCKS_METADATA |
+                        EXT4_FREE_BLOCKS_FORGET);
+@@ -283,7 +253,10 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data)
+       /* ei->i_data[EXT4_IND_BLOCK] */
+       if (i_data[0]) {
+-              extend_credit_for_blkdel(handle, inode);
++              retval = ext4_journal_ensure_credits(handle,
++                                                   EXT4_RESERVE_TRANS_BLOCKS);
++              if (retval < 0)
++                      return retval;
+               ext4_free_blocks(handle, inode, NULL,
+                               le32_to_cpu(i_data[0]), 1,
+                                EXT4_FREE_BLOCKS_METADATA |
+@@ -318,12 +291,9 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
+        * One credit accounted for writing the
+        * i_data field of the original inode
+        */
+-      retval = ext4_journal_extend(handle, 1);
+-      if (retval) {
+-              retval = ext4_journal_restart(handle, 1);
+-              if (retval)
+-                      goto err_out;
+-      }
++      retval = ext4_journal_ensure_credits(handle, 1);
++      if (retval < 0)
++              goto err_out;
+       i_data[0] = ei->i_data[EXT4_IND_BLOCK];
+       i_data[1] = ei->i_data[EXT4_DIND_BLOCK];
+@@ -391,15 +361,19 @@ static int free_ext_idx(handle_t *handle, struct inode *inode,
+               ix = EXT_FIRST_INDEX(eh);
+               for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ix++) {
+                       retval = free_ext_idx(handle, inode, ix);
+-                      if (retval)
+-                              break;
++                      if (retval) {
++                              put_bh(bh);
++                              return retval;
++                      }
+               }
+       }
+       put_bh(bh);
+-      extend_credit_for_blkdel(handle, inode);
++      retval = ext4_journal_ensure_credits(handle, EXT4_RESERVE_TRANS_BLOCKS);
++      if (retval < 0)
++              return retval;
+       ext4_free_blocks(handle, inode, NULL, block, 1,
+                        EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
+-      return retval;
++      return 0;
+ }
+ /*
+@@ -578,9 +552,9 @@ int ext4_ext_migrate(struct inode *inode)
+       }
+       /* We mark the tmp_inode dirty via ext4_ext_tree_init. */
+-      if (ext4_journal_extend(handle, 1) != 0)
+-              ext4_journal_restart(handle, 1);
+-
++      retval = ext4_journal_ensure_credits(handle, 1);
++      if (retval < 0)
++              goto out_stop;
+       /*
+        * Mark the tmp_inode as of size zero
+        */
+@@ -599,6 +573,7 @@ int ext4_ext_migrate(struct inode *inode)
+       /* Reset the extent details */
+       ext4_ext_tree_init(handle, tmp_inode);
++out_stop:
+       ext4_journal_stop(handle);
+ out_tmp_inode:
+       unlock_new_inode(tmp_inode);
+diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
+index 880307ba0f27..44b52921f7f4 100644
+--- a/fs/ext4/resize.c
++++ b/fs/ext4/resize.c
+@@ -430,30 +430,6 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
+       return bh;
+ }
+-/*
+- * If we have fewer than thresh credits, extend by EXT4_MAX_TRANS_DATA.
+- * If that fails, restart the transaction & regain write access for the
+- * buffer head which is used for block_bitmap modifications.
+- */
+-static int extend_or_restart_transaction(handle_t *handle, int thresh)
+-{
+-      int err;
+-
+-      if (ext4_handle_has_enough_credits(handle, thresh))
+-              return 0;
+-
+-      err = ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA);
+-      if (err < 0)
+-              return err;
+-      if (err) {
+-              err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA);
+-              if (err)
+-                      return err;
+-      }
+-
+-      return 0;
+-}
+-
+ /*
+  * set_flexbg_block_bitmap() mark clusters [@first_cluster, @last_cluster] used.
+  *
+@@ -493,8 +469,8 @@ static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle,
+                       continue;
+               }
+-              err = extend_or_restart_transaction(handle, 1);
+-              if (err)
++              err = ext4_journal_ensure_credits_batch(handle, 1);
++              if (err < 0)
+                       return err;
+               bh = sb_getblk(sb, flex_gd->groups[group].block_bitmap);
+@@ -586,8 +562,8 @@ static int setup_new_flex_group_blocks(struct super_block *sb,
+                       struct buffer_head *gdb;
+                       ext4_debug("update backup group %#04llx\n", block);
+-                      err = extend_or_restart_transaction(handle, 1);
+-                      if (err)
++                      err = ext4_journal_ensure_credits_batch(handle, 1);
++                      if (err < 0)
+                               goto out;
+                       gdb = sb_getblk(sb, block);
+@@ -644,8 +620,8 @@ static int setup_new_flex_group_blocks(struct super_block *sb,
+               /* Initialize block bitmap of the @group */
+               block = group_data[i].block_bitmap;
+-              err = extend_or_restart_transaction(handle, 1);
+-              if (err)
++              err = ext4_journal_ensure_credits_batch(handle, 1);
++              if (err < 0)
+                       goto out;
+               bh = bclean(handle, sb, block);
+@@ -673,8 +649,8 @@ static int setup_new_flex_group_blocks(struct super_block *sb,
+               /* Initialize inode bitmap of the @group */
+               block = group_data[i].inode_bitmap;
+-              err = extend_or_restart_transaction(handle, 1);
+-              if (err)
++              err = ext4_journal_ensure_credits_batch(handle, 1);
++              if (err < 0)
+                       goto out;
+               /* Mark unused entries in inode bitmap used */
+               bh = bclean(handle, sb, block);
+@@ -1157,10 +1133,8 @@ static void update_backups(struct super_block *sb, sector_t blk_off, char *data,
+               ext4_fsblk_t backup_block;
+               /* Out of journal space, and can't get more - abort - so sad */
+-              if (ext4_handle_valid(handle) &&
+-                  handle->h_buffer_credits == 0 &&
+-                  ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA) &&
+-                  (err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA)))
++              err = ext4_journal_ensure_credits_batch(handle, 1);
++              if (err < 0)
+                       break;
+               if (meta_bg == 0)
+diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
+index 78df2d65998e..cf1af6a4a567 100644
+--- a/fs/ext4/xattr.c
++++ b/fs/ext4/xattr.c
+@@ -982,55 +982,6 @@ int __ext4_xattr_set_credits(struct super_block *sb, struct inode *inode,
+       return credits;
+ }
+-static int ext4_xattr_ensure_credits(handle_t *handle, struct inode *inode,
+-                                   int credits, struct buffer_head *bh,
+-                                   bool dirty, bool block_csum)
+-{
+-      int error;
+-
+-      if (!ext4_handle_valid(handle))
+-              return 0;
+-
+-      if (handle->h_buffer_credits >= credits)
+-              return 0;
+-
+-      error = ext4_journal_extend(handle, credits - handle->h_buffer_credits);
+-      if (!error)
+-              return 0;
+-      if (error < 0) {
+-              ext4_warning(inode->i_sb, "Extend journal (error %d)", error);
+-              return error;
+-      }
+-
+-      if (bh && dirty) {
+-              if (block_csum)
+-                      ext4_xattr_block_csum_set(inode, bh);
+-              error = ext4_handle_dirty_metadata(handle, NULL, bh);
+-              if (error) {
+-                      ext4_warning(inode->i_sb, "Handle metadata (error %d)",
+-                                   error);
+-                      return error;
+-              }
+-      }
+-
+-      error = ext4_journal_restart(handle, credits);
+-      if (error) {
+-              ext4_warning(inode->i_sb, "Restart journal (error %d)", error);
+-              return error;
+-      }
+-
+-      if (bh) {
+-              error = ext4_journal_get_write_access(handle, bh);
+-              if (error) {
+-                      ext4_warning(inode->i_sb,
+-                                   "Get write access failed (error %d)",
+-                                   error);
+-                      return error;
+-              }
+-      }
+-      return 0;
+-}
+-
+ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
+                                      int ref_change)
+ {
+@@ -1148,6 +1099,24 @@ static int ext4_xattr_inode_inc_ref_all(handle_t *handle, struct inode *parent,
+       return saved_err;
+ }
++static int ext4_xattr_restart_fn(handle_t *handle, struct inode *inode,
++                      struct buffer_head *bh, bool block_csum, bool dirty)
++{
++      int error;
++
++      if (bh && dirty) {
++              if (block_csum)
++                      ext4_xattr_block_csum_set(inode, bh);
++              error = ext4_handle_dirty_metadata(handle, NULL, bh);
++              if (error) {
++                      ext4_warning(inode->i_sb, "Handle metadata (error %d)",
++                                   error);
++                      return error;
++              }
++      }
++      return 0;
++}
++
+ static void
+ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent,
+                            struct buffer_head *bh,
+@@ -1184,13 +1153,23 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent,
+                       continue;
+               }
+-              err = ext4_xattr_ensure_credits(handle, parent, credits, bh,
+-                                              dirty, block_csum);
+-              if (err) {
++              err = ext4_journal_ensure_credits_fn(handle, credits, credits,
++                      ext4_xattr_restart_fn(handle, parent, bh, block_csum,
++                                            dirty));
++              if (err < 0) {
+                       ext4_warning_inode(ea_inode, "Ensure credits err=%d",
+                                          err);
+                       continue;
+               }
++              if (err > 0) {
++                      err = ext4_journal_get_write_access(handle, bh);
++                      if (err) {
++                              ext4_warning_inode(ea_inode,
++                                              "Re-get write access err=%d",
++                                              err);
++                              continue;
++                      }
++              }
+               err = ext4_xattr_inode_dec_ref(handle, ea_inode);
+               if (err) {
+@@ -2879,11 +2858,8 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
+       struct inode *ea_inode;
+       int error;
+-      error = ext4_xattr_ensure_credits(handle, inode, extra_credits,
+-                                        NULL /* bh */,
+-                                        false /* dirty */,
+-                                        false /* block_csum */);
+-      if (error) {
++      error = ext4_journal_ensure_credits(handle, extra_credits);
++      if (error < 0) {
+               EXT4_ERROR_INODE(inode, "ensure credits (error %d)", error);
+               goto cleanup;
+       }
+-- 
+2.35.1
+
diff --git a/queue-5.4/jbd2-drop-pointless-wakeup-from-jbd2_journal_stop.patch b/queue-5.4/jbd2-drop-pointless-wakeup-from-jbd2_journal_stop.patch
new file mode 100644 (file)
index 0000000..08c1e8d
--- /dev/null
@@ -0,0 +1,50 @@
+From 58a5adc78307d3204ab19ba2ed2eb1cd0929363f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Nov 2019 17:44:22 +0100
+Subject: jbd2: Drop pointless wakeup from jbd2_journal_stop()
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 5559b2d81b51de75cb7864bb1fbb82982f7e8fff ]
+
+When we drop last handle from a transaction and journal->j_barrier_count
+> 0, jbd2_journal_stop() wakes up journal->j_wait_transaction_locked
+wait queue. This looks pointless - wait for outstanding handles always
+happens on journal->j_wait_updates waitqueue.
+journal->j_wait_transaction_locked is used to wait for transaction state
+changes and by start_this_handle() for waiting until
+journal->j_barrier_count drops to 0. The first case is clearly
+irrelevant here since only jbd2 thread changes transaction state. The
+second case looks related but jbd2_journal_unlock_updates() is
+responsible for the wakeup in this case. So just drop the wakeup.
+
+Reviewed-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20191105164437.32602-16-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: d87a7b4c77a9 ("jbd2: use the correct print format")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/transaction.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
+index ce66dbbf0f90..6d78648392f0 100644
+--- a/fs/jbd2/transaction.c
++++ b/fs/jbd2/transaction.c
+@@ -1850,11 +1850,8 @@ int jbd2_journal_stop(handle_t *handle)
+        * once we do this, we must not dereference transaction
+        * pointer again.
+        */
+-      if (atomic_dec_and_test(&transaction->t_updates)) {
++      if (atomic_dec_and_test(&transaction->t_updates))
+               wake_up(&journal->j_wait_updates);
+-              if (journal->j_barrier_count)
+-                      wake_up(&journal->j_wait_transaction_locked);
+-      }
+       rwsem_release(&journal->j_trans_commit_map, 1, _THIS_IP_);
+-- 
+2.35.1
+
diff --git a/queue-5.4/jbd2-factor-out-common-parts-of-stopping-and-restart.patch b/queue-5.4/jbd2-factor-out-common-parts-of-stopping-and-restart.patch
new file mode 100644 (file)
index 0000000..3a9785c
--- /dev/null
@@ -0,0 +1,205 @@
+From 80aa738f12e908dff5edaf9940b57127ba63363b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Nov 2019 17:44:23 +0100
+Subject: jbd2: Factor out common parts of stopping and restarting a handle
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit ec8b6f600e49dc87a8564807fec4193bf93ee2b5 ]
+
+jbd2__journal_restart() has quite some code that is common with
+jbd2_journal_stop(). Factor this functionality into stop_this_handle()
+helper and use it from both functions. Note that this also drops
+t_handle_lock protection from jbd2__journal_restart() as
+jbd2_journal_stop() does the same thing without it.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20191105164437.32602-17-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: d87a7b4c77a9 ("jbd2: use the correct print format")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/transaction.c | 98 ++++++++++++++++++++-----------------------
+ 1 file changed, 46 insertions(+), 52 deletions(-)
+
+diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
+index 6d78648392f0..ee9a778c8fbe 100644
+--- a/fs/jbd2/transaction.c
++++ b/fs/jbd2/transaction.c
+@@ -514,12 +514,17 @@ handle_t *jbd2_journal_start(journal_t *journal, int nblocks)
+ }
+ EXPORT_SYMBOL(jbd2_journal_start);
+-void jbd2_journal_free_reserved(handle_t *handle)
++static void __jbd2_journal_unreserve_handle(handle_t *handle)
+ {
+       journal_t *journal = handle->h_journal;
+       WARN_ON(!handle->h_reserved);
+       sub_reserved_credits(journal, handle->h_buffer_credits);
++}
++
++void jbd2_journal_free_reserved(handle_t *handle)
++{
++      __jbd2_journal_unreserve_handle(handle);
+       jbd2_free_handle(handle);
+ }
+ EXPORT_SYMBOL(jbd2_journal_free_reserved);
+@@ -657,6 +662,28 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
+       return result;
+ }
++static void stop_this_handle(handle_t *handle)
++{
++      transaction_t *transaction = handle->h_transaction;
++      journal_t *journal = transaction->t_journal;
++
++      J_ASSERT(journal_current_handle() == handle);
++      J_ASSERT(atomic_read(&transaction->t_updates) > 0);
++      current->journal_info = NULL;
++      atomic_sub(handle->h_buffer_credits,
++                 &transaction->t_outstanding_credits);
++      if (handle->h_rsv_handle)
++              __jbd2_journal_unreserve_handle(handle->h_rsv_handle);
++      if (atomic_dec_and_test(&transaction->t_updates))
++              wake_up(&journal->j_wait_updates);
++
++      rwsem_release(&journal->j_trans_commit_map, 1, _THIS_IP_);
++      /*
++       * Scope of the GFP_NOFS context is over here and so we can restore the
++       * original alloc context.
++       */
++      memalloc_nofs_restore(handle->saved_alloc_context);
++}
+ /**
+  * int jbd2_journal_restart() - restart a handle .
+@@ -679,52 +706,34 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask)
+       transaction_t *transaction = handle->h_transaction;
+       journal_t *journal;
+       tid_t           tid;
+-      int             need_to_start, ret;
++      int             need_to_start;
+       /* If we've had an abort of any type, don't even think about
+        * actually doing the restart! */
+       if (is_handle_aborted(handle))
+               return 0;
+       journal = transaction->t_journal;
++      tid = transaction->t_tid;
+       /*
+        * First unlink the handle from its current transaction, and start the
+        * commit on that.
+        */
+-      J_ASSERT(atomic_read(&transaction->t_updates) > 0);
+-      J_ASSERT(journal_current_handle() == handle);
+-
+-      read_lock(&journal->j_state_lock);
+-      spin_lock(&transaction->t_handle_lock);
+-      atomic_sub(handle->h_buffer_credits,
+-                 &transaction->t_outstanding_credits);
+-      if (handle->h_rsv_handle) {
+-              sub_reserved_credits(journal,
+-                                   handle->h_rsv_handle->h_buffer_credits);
+-      }
+-      if (atomic_dec_and_test(&transaction->t_updates))
+-              wake_up(&journal->j_wait_updates);
+-      tid = transaction->t_tid;
+-      spin_unlock(&transaction->t_handle_lock);
++      jbd_debug(2, "restarting handle %p\n", handle);
++      stop_this_handle(handle);
+       handle->h_transaction = NULL;
+-      current->journal_info = NULL;
+-      jbd_debug(2, "restarting handle %p\n", handle);
++      /*
++       * TODO: If we use READ_ONCE / WRITE_ONCE for j_commit_request we can
++       * get rid of pointless j_state_lock traffic like this.
++       */
++      read_lock(&journal->j_state_lock);
+       need_to_start = !tid_geq(journal->j_commit_request, tid);
+       read_unlock(&journal->j_state_lock);
+       if (need_to_start)
+               jbd2_log_start_commit(journal, tid);
+-
+-      rwsem_release(&journal->j_trans_commit_map, 1, _THIS_IP_);
+       handle->h_buffer_credits = nblocks;
+-      /*
+-       * Restore the original nofs context because the journal restart
+-       * is basically the same thing as journal stop and start.
+-       * start_this_handle will start a new nofs context.
+-       */
+-      memalloc_nofs_restore(handle->saved_alloc_context);
+-      ret = start_this_handle(journal, handle, gfp_mask);
+-      return ret;
++      return start_this_handle(journal, handle, gfp_mask);
+ }
+ EXPORT_SYMBOL(jbd2__journal_restart);
+@@ -1734,16 +1743,12 @@ int jbd2_journal_stop(handle_t *handle)
+                * Handle is already detached from the transaction so there is
+                * nothing to do other than free the handle.
+                */
+-              if (handle->h_rsv_handle)
+-                      jbd2_free_handle(handle->h_rsv_handle);
++              memalloc_nofs_restore(handle->saved_alloc_context);
+               goto free_and_exit;
+       }
+       journal = transaction->t_journal;
+       tid = transaction->t_tid;
+-      J_ASSERT(journal_current_handle() == handle);
+-      J_ASSERT(atomic_read(&transaction->t_updates) > 0);
+-
+       if (is_handle_aborted(handle))
+               err = -EIO;
+@@ -1813,9 +1818,6 @@ int jbd2_journal_stop(handle_t *handle)
+       if (handle->h_sync)
+               transaction->t_synchronous_commit = 1;
+-      current->journal_info = NULL;
+-      atomic_sub(handle->h_buffer_credits,
+-                 &transaction->t_outstanding_credits);
+       /*
+        * If the handle is marked SYNC, we need to set another commit
+@@ -1845,27 +1847,19 @@ int jbd2_journal_stop(handle_t *handle)
+       }
+       /*
+-       * Once we drop t_updates, if it goes to zero the transaction
+-       * could start committing on us and eventually disappear.  So
+-       * once we do this, we must not dereference transaction
+-       * pointer again.
++       * Once stop_this_handle() drops t_updates, the transaction could start
++       * committing on us and eventually disappear.  So we must not
++       * dereference transaction pointer again after calling
++       * stop_this_handle().
+        */
+-      if (atomic_dec_and_test(&transaction->t_updates))
+-              wake_up(&journal->j_wait_updates);
+-
+-      rwsem_release(&journal->j_trans_commit_map, 1, _THIS_IP_);
++      stop_this_handle(handle);
+       if (wait_for_commit)
+               err = jbd2_log_wait_commit(journal, tid);
+-      if (handle->h_rsv_handle)
+-              jbd2_journal_free_reserved(handle->h_rsv_handle);
+ free_and_exit:
+-      /*
+-       * Scope of the GFP_NOFS context is over here and so we can restore the
+-       * original alloc context.
+-       */
+-      memalloc_nofs_restore(handle->saved_alloc_context);
++      if (handle->h_rsv_handle)
++              jbd2_free_handle(handle->h_rsv_handle);
+       jbd2_free_handle(handle);
+       return err;
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.4/jbd2-reorganize-jbd2_journal_stop.patch b/queue-5.4/jbd2-reorganize-jbd2_journal_stop.patch
new file mode 100644 (file)
index 0000000..3142971
--- /dev/null
@@ -0,0 +1,104 @@
+From 6fddfed79a11832d9931d6a0d5aa6b42022a716c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Nov 2019 17:44:20 +0100
+Subject: jbd2: Reorganize jbd2_journal_stop()
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit dfaf5ffda227be3e867fee7c0f6a66749392fbd0 ]
+
+Move code in jbd2_journal_stop() around a bit. It removes some
+unnecessary code duplication and will make factoring out parts common
+with jbd2__journal_restart() easier.
+
+Reviewed-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20191105164437.32602-14-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: d87a7b4c77a9 ("jbd2: use the correct print format")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/transaction.c | 40 ++++++++++++++++------------------------
+ 1 file changed, 16 insertions(+), 24 deletions(-)
+
+diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
+index 09f4d00fece2..ce66dbbf0f90 100644
+--- a/fs/jbd2/transaction.c
++++ b/fs/jbd2/transaction.c
+@@ -1722,41 +1722,34 @@ int jbd2_journal_stop(handle_t *handle)
+       tid_t tid;
+       pid_t pid;
++      if (--handle->h_ref > 0) {
++              jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1,
++                                               handle->h_ref);
++              if (is_handle_aborted(handle))
++                      return -EIO;
++              return 0;
++      }
+       if (!transaction) {
+               /*
+-               * Handle is already detached from the transaction so
+-               * there is nothing to do other than decrease a refcount,
+-               * or free the handle if refcount drops to zero
++               * Handle is already detached from the transaction so there is
++               * nothing to do other than free the handle.
+                */
+-              if (--handle->h_ref > 0) {
+-                      jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1,
+-                                                       handle->h_ref);
+-                      return err;
+-              } else {
+-                      if (handle->h_rsv_handle)
+-                              jbd2_free_handle(handle->h_rsv_handle);
+-                      goto free_and_exit;
+-              }
++              if (handle->h_rsv_handle)
++                      jbd2_free_handle(handle->h_rsv_handle);
++              goto free_and_exit;
+       }
+       journal = transaction->t_journal;
++      tid = transaction->t_tid;
+       J_ASSERT(journal_current_handle() == handle);
++      J_ASSERT(atomic_read(&transaction->t_updates) > 0);
+       if (is_handle_aborted(handle))
+               err = -EIO;
+-      else
+-              J_ASSERT(atomic_read(&transaction->t_updates) > 0);
+-
+-      if (--handle->h_ref > 0) {
+-              jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1,
+-                        handle->h_ref);
+-              return err;
+-      }
+       jbd_debug(4, "Handle %p going down\n", handle);
+       trace_jbd2_handle_stats(journal->j_fs_dev->bd_dev,
+-                              transaction->t_tid,
+-                              handle->h_type, handle->h_line_no,
++                              tid, handle->h_type, handle->h_line_no,
+                               jiffies - handle->h_start_jiffies,
+                               handle->h_sync, handle->h_requested_credits,
+                               (handle->h_requested_credits -
+@@ -1841,7 +1834,7 @@ int jbd2_journal_stop(handle_t *handle)
+               jbd_debug(2, "transaction too old, requesting commit for "
+                                       "handle %p\n", handle);
+               /* This is non-blocking */
+-              jbd2_log_start_commit(journal, transaction->t_tid);
++              jbd2_log_start_commit(journal, tid);
+               /*
+                * Special case: JBD2_SYNC synchronous updates require us
+@@ -1857,7 +1850,6 @@ int jbd2_journal_stop(handle_t *handle)
+        * once we do this, we must not dereference transaction
+        * pointer again.
+        */
+-      tid = transaction->t_tid;
+       if (atomic_dec_and_test(&transaction->t_updates)) {
+               wake_up(&journal->j_wait_updates);
+               if (journal->j_barrier_count)
+-- 
+2.35.1
+
diff --git a/queue-5.4/jbd2-use-the-correct-print-format.patch b/queue-5.4/jbd2-use-the-correct-print-format.patch
new file mode 100644 (file)
index 0000000..7188013
--- /dev/null
@@ -0,0 +1,202 @@
+From 61e286eeca71ccf5b54c872b0fd3e27d76f38738 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Oct 2022 19:33:44 +0800
+Subject: jbd2: use the correct print format
+
+From: Bixuan Cui <cuibixuan@linux.alibaba.com>
+
+[ Upstream commit d87a7b4c77a997d5388566dd511ca8e6b8e8a0a8 ]
+
+The print format error was found when using ftrace event:
+    <...>-1406 [000] .... 23599442.895823: jbd2_end_commit: dev 252,8 transaction -1866216965 sync 0 head -1866217368
+    <...>-1406 [000] .... 23599442.896299: jbd2_start_commit: dev 252,8 transaction -1866216964 sync 0
+
+Use the correct print format for transaction, head and tid.
+
+Fixes: 879c5e6b7cb4 ('jbd2: convert instrumentation from markers to tracepoints')
+Signed-off-by: Bixuan Cui <cuibixuan@linux.alibaba.com>
+Reviewed-by: Jason Yan <yanaijie@huawei.com>
+Link: https://lore.kernel.org/r/1665488024-95172-1-git-send-email-cuibixuan@linux.alibaba.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/trace/events/jbd2.h | 40 ++++++++++++++++++-------------------
+ 1 file changed, 20 insertions(+), 20 deletions(-)
+
+diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h
+index 2310b259329f..c9fb7b987a3a 100644
+--- a/include/trace/events/jbd2.h
++++ b/include/trace/events/jbd2.h
+@@ -40,7 +40,7 @@ DECLARE_EVENT_CLASS(jbd2_commit,
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        char,   sync_commit               )
+-              __field(        int,    transaction               )
++              __field(        tid_t,  transaction               )
+       ),
+       TP_fast_assign(
+@@ -49,7 +49,7 @@ DECLARE_EVENT_CLASS(jbd2_commit,
+               __entry->transaction    = commit_transaction->t_tid;
+       ),
+-      TP_printk("dev %d,%d transaction %d sync %d",
++      TP_printk("dev %d,%d transaction %u sync %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->transaction, __entry->sync_commit)
+ );
+@@ -97,8 +97,8 @@ TRACE_EVENT(jbd2_end_commit,
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(        char,   sync_commit               )
+-              __field(        int,    transaction               )
+-              __field(        int,    head                      )
++              __field(        tid_t,  transaction               )
++              __field(        tid_t,  head                      )
+       ),
+       TP_fast_assign(
+@@ -108,7 +108,7 @@ TRACE_EVENT(jbd2_end_commit,
+               __entry->head           = journal->j_tail_sequence;
+       ),
+-      TP_printk("dev %d,%d transaction %d sync %d head %d",
++      TP_printk("dev %d,%d transaction %u sync %d head %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->transaction, __entry->sync_commit, __entry->head)
+ );
+@@ -134,14 +134,14 @@ TRACE_EVENT(jbd2_submit_inode_data,
+ );
+ TRACE_EVENT(jbd2_handle_start,
+-      TP_PROTO(dev_t dev, unsigned long tid, unsigned int type,
++      TP_PROTO(dev_t dev, tid_t tid, unsigned int type,
+                unsigned int line_no, int requested_blocks),
+       TP_ARGS(dev, tid, type, line_no, requested_blocks),
+       TP_STRUCT__entry(
+               __field(                dev_t,  dev             )
+-              __field(        unsigned long,  tid             )
++              __field(                tid_t,  tid             )
+               __field(         unsigned int,  type            )
+               __field(         unsigned int,  line_no         )
+               __field(                  int,  requested_blocks)
+@@ -155,14 +155,14 @@ TRACE_EVENT(jbd2_handle_start,
+               __entry->requested_blocks = requested_blocks;
+       ),
+-      TP_printk("dev %d,%d tid %lu type %u line_no %u "
++      TP_printk("dev %d,%d tid %u type %u line_no %u "
+                 "requested_blocks %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid,
+                 __entry->type, __entry->line_no, __entry->requested_blocks)
+ );
+ TRACE_EVENT(jbd2_handle_extend,
+-      TP_PROTO(dev_t dev, unsigned long tid, unsigned int type,
++      TP_PROTO(dev_t dev, tid_t tid, unsigned int type,
+                unsigned int line_no, int buffer_credits,
+                int requested_blocks),
+@@ -170,7 +170,7 @@ TRACE_EVENT(jbd2_handle_extend,
+       TP_STRUCT__entry(
+               __field(                dev_t,  dev             )
+-              __field(        unsigned long,  tid             )
++              __field(                tid_t,  tid             )
+               __field(         unsigned int,  type            )
+               __field(         unsigned int,  line_no         )
+               __field(                  int,  buffer_credits  )
+@@ -186,7 +186,7 @@ TRACE_EVENT(jbd2_handle_extend,
+               __entry->requested_blocks = requested_blocks;
+       ),
+-      TP_printk("dev %d,%d tid %lu type %u line_no %u "
++      TP_printk("dev %d,%d tid %u type %u line_no %u "
+                 "buffer_credits %d requested_blocks %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid,
+                 __entry->type, __entry->line_no, __entry->buffer_credits,
+@@ -194,7 +194,7 @@ TRACE_EVENT(jbd2_handle_extend,
+ );
+ TRACE_EVENT(jbd2_handle_stats,
+-      TP_PROTO(dev_t dev, unsigned long tid, unsigned int type,
++      TP_PROTO(dev_t dev, tid_t tid, unsigned int type,
+                unsigned int line_no, int interval, int sync,
+                int requested_blocks, int dirtied_blocks),
+@@ -203,7 +203,7 @@ TRACE_EVENT(jbd2_handle_stats,
+       TP_STRUCT__entry(
+               __field(                dev_t,  dev             )
+-              __field(        unsigned long,  tid             )
++              __field(                tid_t,  tid             )
+               __field(         unsigned int,  type            )
+               __field(         unsigned int,  line_no         )
+               __field(                  int,  interval        )
+@@ -223,7 +223,7 @@ TRACE_EVENT(jbd2_handle_stats,
+               __entry->dirtied_blocks   = dirtied_blocks;
+       ),
+-      TP_printk("dev %d,%d tid %lu type %u line_no %u interval %d "
++      TP_printk("dev %d,%d tid %u type %u line_no %u interval %d "
+                 "sync %d requested_blocks %d dirtied_blocks %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid,
+                 __entry->type, __entry->line_no, __entry->interval,
+@@ -232,14 +232,14 @@ TRACE_EVENT(jbd2_handle_stats,
+ );
+ TRACE_EVENT(jbd2_run_stats,
+-      TP_PROTO(dev_t dev, unsigned long tid,
++      TP_PROTO(dev_t dev, tid_t tid,
+                struct transaction_run_stats_s *stats),
+       TP_ARGS(dev, tid, stats),
+       TP_STRUCT__entry(
+               __field(                dev_t,  dev             )
+-              __field(        unsigned long,  tid             )
++              __field(                tid_t,  tid             )
+               __field(        unsigned long,  wait            )
+               __field(        unsigned long,  request_delay   )
+               __field(        unsigned long,  running         )
+@@ -265,7 +265,7 @@ TRACE_EVENT(jbd2_run_stats,
+               __entry->blocks_logged  = stats->rs_blocks_logged;
+       ),
+-      TP_printk("dev %d,%d tid %lu wait %u request_delay %u running %u "
++      TP_printk("dev %d,%d tid %u wait %u request_delay %u running %u "
+                 "locked %u flushing %u logging %u handle_count %u "
+                 "blocks %u blocks_logged %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid,
+@@ -280,14 +280,14 @@ TRACE_EVENT(jbd2_run_stats,
+ );
+ TRACE_EVENT(jbd2_checkpoint_stats,
+-      TP_PROTO(dev_t dev, unsigned long tid,
++      TP_PROTO(dev_t dev, tid_t tid,
+                struct transaction_chp_stats_s *stats),
+       TP_ARGS(dev, tid, stats),
+       TP_STRUCT__entry(
+               __field(                dev_t,  dev             )
+-              __field(        unsigned long,  tid             )
++              __field(                tid_t,  tid             )
+               __field(        unsigned long,  chp_time        )
+               __field(                __u32,  forced_to_close )
+               __field(                __u32,  written         )
+@@ -303,7 +303,7 @@ TRACE_EVENT(jbd2_checkpoint_stats,
+               __entry->dropped        = stats->cs_dropped;
+       ),
+-      TP_printk("dev %d,%d tid %lu chp_time %u forced_to_close %u "
++      TP_printk("dev %d,%d tid %u chp_time %u forced_to_close %u "
+                 "written %u dropped %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid,
+                 jiffies_to_msecs(__entry->chp_time),
+-- 
+2.35.1
+
diff --git a/queue-5.4/ocfs2-use-accessor-function-for-h_buffer_credits.patch b/queue-5.4/ocfs2-use-accessor-function-for-h_buffer_credits.patch
new file mode 100644 (file)
index 0000000..ad150bb
--- /dev/null
@@ -0,0 +1,168 @@
+From 332d74ed7afca6f1f88a6eff40c61ee73e68b513 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Nov 2019 17:44:18 +0100
+Subject: ocfs2: Use accessor function for h_buffer_credits
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 9797a902480521dc8e7a478e38f0c896ffff8784 ]
+
+Use the jbd2 accessor function for h_buffer_credits.
+
+Reviewed-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20191105164437.32602-12-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: d87a7b4c77a9 ("jbd2: use the correct print format")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ocfs2/alloc.c   | 32 ++++++++++++++++----------------
+ fs/ocfs2/journal.c |  4 ++--
+ 2 files changed, 18 insertions(+), 18 deletions(-)
+
+diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
+index 4db87b26cf7b..9bc3e926b717 100644
+--- a/fs/ocfs2/alloc.c
++++ b/fs/ocfs2/alloc.c
+@@ -2288,9 +2288,9 @@ static int ocfs2_extend_rotate_transaction(handle_t *handle, int subtree_depth,
+       int ret = 0;
+       int credits = (path->p_tree_depth - subtree_depth) * 2 + 1 + op_credits;
+-      if (handle->h_buffer_credits < credits)
++      if (jbd2_handle_buffer_credits(handle) < credits)
+               ret = ocfs2_extend_trans(handle,
+-                                       credits - handle->h_buffer_credits);
++                              credits - jbd2_handle_buffer_credits(handle));
+       return ret;
+ }
+@@ -2367,7 +2367,7 @@ static int ocfs2_rotate_tree_right(handle_t *handle,
+                                  struct ocfs2_path *right_path,
+                                  struct ocfs2_path **ret_left_path)
+ {
+-      int ret, start, orig_credits = handle->h_buffer_credits;
++      int ret, start, orig_credits = jbd2_handle_buffer_credits(handle);
+       u32 cpos;
+       struct ocfs2_path *left_path = NULL;
+       struct super_block *sb = ocfs2_metadata_cache_get_super(et->et_ci);
+@@ -3148,7 +3148,7 @@ static int ocfs2_rotate_tree_left(handle_t *handle,
+                                 struct ocfs2_path *path,
+                                 struct ocfs2_cached_dealloc_ctxt *dealloc)
+ {
+-      int ret, orig_credits = handle->h_buffer_credits;
++      int ret, orig_credits = jbd2_handle_buffer_credits(handle);
+       struct ocfs2_path *tmp_path = NULL, *restart_path = NULL;
+       struct ocfs2_extent_block *eb;
+       struct ocfs2_extent_list *el;
+@@ -3386,8 +3386,8 @@ static int ocfs2_merge_rec_right(struct ocfs2_path *left_path,
+                                                       right_path);
+               ret = ocfs2_extend_rotate_transaction(handle, subtree_index,
+-                                                    handle->h_buffer_credits,
+-                                                    right_path);
++                                      jbd2_handle_buffer_credits(handle),
++                                      right_path);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+@@ -3548,8 +3548,8 @@ static int ocfs2_merge_rec_left(struct ocfs2_path *right_path,
+                                                       right_path);
+               ret = ocfs2_extend_rotate_transaction(handle, subtree_index,
+-                                                    handle->h_buffer_credits,
+-                                                    left_path);
++                                      jbd2_handle_buffer_credits(handle),
++                                      left_path);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+@@ -3623,7 +3623,7 @@ static int ocfs2_merge_rec_left(struct ocfs2_path *right_path,
+                   le16_to_cpu(el->l_next_free_rec) == 1) {
+                       /* extend credit for ocfs2_remove_rightmost_path */
+                       ret = ocfs2_extend_rotate_transaction(handle, 0,
+-                                      handle->h_buffer_credits,
++                                      jbd2_handle_buffer_credits(handle),
+                                       right_path);
+                       if (ret) {
+                               mlog_errno(ret);
+@@ -3669,7 +3669,7 @@ static int ocfs2_try_to_merge_extent(handle_t *handle,
+       if (ctxt->c_split_covers_rec && ctxt->c_has_empty_extent) {
+               /* extend credit for ocfs2_remove_rightmost_path */
+               ret = ocfs2_extend_rotate_transaction(handle, 0,
+-                              handle->h_buffer_credits,
++                              jbd2_handle_buffer_credits(handle),
+                               path);
+               if (ret) {
+                       mlog_errno(ret);
+@@ -3725,7 +3725,7 @@ static int ocfs2_try_to_merge_extent(handle_t *handle,
+               /* extend credit for ocfs2_remove_rightmost_path */
+               ret = ocfs2_extend_rotate_transaction(handle, 0,
+-                                      handle->h_buffer_credits,
++                                      jbd2_handle_buffer_credits(handle),
+                                       path);
+               if (ret) {
+                       mlog_errno(ret);
+@@ -3755,7 +3755,7 @@ static int ocfs2_try_to_merge_extent(handle_t *handle,
+               /* extend credit for ocfs2_remove_rightmost_path */
+               ret = ocfs2_extend_rotate_transaction(handle, 0,
+-                              handle->h_buffer_credits,
++                              jbd2_handle_buffer_credits(handle),
+                               path);
+               if (ret) {
+                       mlog_errno(ret);
+@@ -3799,7 +3799,7 @@ static int ocfs2_try_to_merge_extent(handle_t *handle,
+               if (ctxt->c_split_covers_rec) {
+                       /* extend credit for ocfs2_remove_rightmost_path */
+                       ret = ocfs2_extend_rotate_transaction(handle, 0,
+-                                      handle->h_buffer_credits,
++                                      jbd2_handle_buffer_credits(handle),
+                                       path);
+                       if (ret) {
+                               mlog_errno(ret);
+@@ -5358,7 +5358,7 @@ static int ocfs2_truncate_rec(handle_t *handle,
+       if (ocfs2_is_empty_extent(&el->l_recs[0]) && index > 0) {
+               /* extend credit for ocfs2_remove_rightmost_path */
+               ret = ocfs2_extend_rotate_transaction(handle, 0,
+-                              handle->h_buffer_credits,
++                              jbd2_handle_buffer_credits(handle),
+                               path);
+               if (ret) {
+                       mlog_errno(ret);
+@@ -5427,8 +5427,8 @@ static int ocfs2_truncate_rec(handle_t *handle,
+       }
+       ret = ocfs2_extend_rotate_transaction(handle, 0,
+-                                            handle->h_buffer_credits,
+-                                            path);
++                                      jbd2_handle_buffer_credits(handle),
++                                      path);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
+index da95ed79c12e..595745602f1e 100644
+--- a/fs/ocfs2/journal.c
++++ b/fs/ocfs2/journal.c
+@@ -420,7 +420,7 @@ int ocfs2_extend_trans(handle_t *handle, int nblocks)
+       if (!nblocks)
+               return 0;
+-      old_nblocks = handle->h_buffer_credits;
++      old_nblocks = jbd2_handle_buffer_credits(handle);
+       trace_ocfs2_extend_trans(old_nblocks, nblocks);
+@@ -461,7 +461,7 @@ int ocfs2_allocate_extend_trans(handle_t *handle, int thresh)
+       BUG_ON(!handle);
+-      old_nblks = handle->h_buffer_credits;
++      old_nblks = jbd2_handle_buffer_credits(handle);
+       trace_ocfs2_allocate_extend_trans(old_nblks, thresh);
+       if (old_nblks < thresh)
+-- 
+2.35.1
+
diff --git a/queue-5.4/quota-factor-out-setup-of-quota-inode.patch b/queue-5.4/quota-factor-out-setup-of-quota-inode.patch
new file mode 100644 (file)
index 0000000..cc40224
--- /dev/null
@@ -0,0 +1,192 @@
+From ef2b9f063beca969f15a1a39acb5153616b054ea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 Nov 2019 17:45:31 +0100
+Subject: quota: Factor out setup of quota inode
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit c7d3d28360fdb3ed3a5aa0bab19315e0fdc994a1 ]
+
+Factor out setting up of quota inode and eventual error cleanup from
+vfs_load_quota_inode(). This will simplify situation for filesystems
+that don't have any quota inodes.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Stable-dep-of: d32387748476 ("ext4: fix bug_on in __es_tree_search caused by bad quota inode")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/quota/dquot.c         | 108 ++++++++++++++++++++++++---------------
+ include/linux/quotaops.h |   2 +
+ 2 files changed, 69 insertions(+), 41 deletions(-)
+
+diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
+index dc5f8654b277..84f61ab05890 100644
+--- a/fs/quota/dquot.c
++++ b/fs/quota/dquot.c
+@@ -2306,28 +2306,60 @@ EXPORT_SYMBOL(dquot_quota_off);
+  *    Turn quotas on on a device
+  */
+-/*
+- * Helper function to turn quotas on when we already have the inode of
+- * quota file and no quota information is loaded.
+- */
+-static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
++static int vfs_setup_quota_inode(struct inode *inode, int type)
++{
++      struct super_block *sb = inode->i_sb;
++      struct quota_info *dqopt = sb_dqopt(sb);
++
++      if (!S_ISREG(inode->i_mode))
++              return -EACCES;
++      if (IS_RDONLY(inode))
++              return -EROFS;
++      if (sb_has_quota_loaded(sb, type))
++              return -EBUSY;
++
++      dqopt->files[type] = igrab(inode);
++      if (!dqopt->files[type])
++              return -EIO;
++      if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
++              /* We don't want quota and atime on quota files (deadlocks
++               * possible) Also nobody should write to the file - we use
++               * special IO operations which ignore the immutable bit. */
++              inode_lock(inode);
++              inode->i_flags |= S_NOQUOTA;
++              inode_unlock(inode);
++              /*
++               * When S_NOQUOTA is set, remove dquot references as no more
++               * references can be added
++               */
++              __dquot_drop(inode);
++      }
++      return 0;
++}
++
++static void vfs_cleanup_quota_inode(struct super_block *sb, int type)
++{
++      struct quota_info *dqopt = sb_dqopt(sb);
++      struct inode *inode = dqopt->files[type];
++
++      if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
++              inode_lock(inode);
++              inode->i_flags &= ~S_NOQUOTA;
++              inode_unlock(inode);
++      }
++      dqopt->files[type] = NULL;
++      iput(inode);
++}
++
++int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
+       unsigned int flags)
+ {
+       struct quota_format_type *fmt = find_quota_format(format_id);
+-      struct super_block *sb = inode->i_sb;
+       struct quota_info *dqopt = sb_dqopt(sb);
+       int error;
+       if (!fmt)
+               return -ESRCH;
+-      if (!S_ISREG(inode->i_mode)) {
+-              error = -EACCES;
+-              goto out_fmt;
+-      }
+-      if (IS_RDONLY(inode)) {
+-              error = -EROFS;
+-              goto out_fmt;
+-      }
+       if (!sb->s_op->quota_write || !sb->s_op->quota_read ||
+           (type == PRJQUOTA && sb->dq_op->get_projid == NULL)) {
+               error = -EINVAL;
+@@ -2359,27 +2391,9 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
+               invalidate_bdev(sb->s_bdev);
+       }
+-      if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
+-              /* We don't want quota and atime on quota files (deadlocks
+-               * possible) Also nobody should write to the file - we use
+-               * special IO operations which ignore the immutable bit. */
+-              inode_lock(inode);
+-              inode->i_flags |= S_NOQUOTA;
+-              inode_unlock(inode);
+-              /*
+-               * When S_NOQUOTA is set, remove dquot references as no more
+-               * references can be added
+-               */
+-              __dquot_drop(inode);
+-      }
+-
+-      error = -EIO;
+-      dqopt->files[type] = igrab(inode);
+-      if (!dqopt->files[type])
+-              goto out_file_flags;
+       error = -EINVAL;
+       if (!fmt->qf_ops->check_quota_file(sb, type))
+-              goto out_file_init;
++              goto out_fmt;
+       dqopt->ops[type] = fmt->qf_ops;
+       dqopt->info[type].dqi_format = fmt;
+@@ -2387,7 +2401,7 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
+       INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list);
+       error = dqopt->ops[type]->read_file_info(sb, type);
+       if (error < 0)
+-              goto out_file_init;
++              goto out_fmt;
+       if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) {
+               spin_lock(&dq_data_lock);
+               dqopt->info[type].dqi_flags |= DQF_SYS_FILE;
+@@ -2402,18 +2416,30 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
+               dquot_disable(sb, type, flags);
+       return error;
+-out_file_init:
+-      dqopt->files[type] = NULL;
+-      iput(inode);
+-out_file_flags:
+-      inode_lock(inode);
+-      inode->i_flags &= ~S_NOQUOTA;
+-      inode_unlock(inode);
+ out_fmt:
+       put_quota_format(fmt);
+       return error;
+ }
++EXPORT_SYMBOL(dquot_load_quota_sb);
++
++/*
++ * Helper function to turn quotas on when we already have the inode of
++ * quota file and no quota information is loaded.
++ */
++static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
++      unsigned int flags)
++{
++      int err;
++
++      err = vfs_setup_quota_inode(inode, type);
++      if (err < 0)
++              return err;
++      err = dquot_load_quota_sb(inode->i_sb, type, format_id, flags);
++      if (err < 0)
++              vfs_cleanup_quota_inode(inode->i_sb, type);
++      return err;
++}
+ /* Reenable quotas on remount RW */
+ int dquot_resume(struct super_block *sb, int type)
+diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
+index 91e0b7624053..ec10897f7f60 100644
+--- a/include/linux/quotaops.h
++++ b/include/linux/quotaops.h
+@@ -99,6 +99,8 @@ int dquot_file_open(struct inode *inode, struct file *file);
+ int dquot_enable(struct inode *inode, int type, int format_id,
+       unsigned int flags);
++int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
++      unsigned int flags);
+ int dquot_quota_on(struct super_block *sb, int type, int format_id,
+       const struct path *path);
+ int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
+-- 
+2.35.1
+
index 31de0b4b2eb6396502c2abdf39c4ee17a30322ce..a8091cf0b9af5e585b0cee65b1869ae316f44389 100644 (file)
@@ -609,3 +609,18 @@ s390-percpu-add-read_once-to-arch_this_cpu_to_op_simple.patch
 net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch
 alsa-pcm-move-rwsem-lock-inside-snd_ctl_elem_read-to-prevent-uaf.patch
 alsa-hda-hdmi-add-a-hp-device-0x8715-to-force-connect-list.patch
+asoc-intel-bytcr_rt5640-add-quirk-for-the-advantech-.patch-10536
+wifi-wilc1000-sdio-fix-module-autoloading.patch
+usb-ulpi-defer-ulpi_register-on-ulpi_read_id-timeout.patch
+ext4-provide-function-to-handle-transaction-restarts.patch
+ext4-jbd2-provide-accessor-function-for-handle-credi.patch
+ocfs2-use-accessor-function-for-h_buffer_credits.patch
+jbd2-reorganize-jbd2_journal_stop.patch
+jbd2-drop-pointless-wakeup-from-jbd2_journal_stop.patch
+jbd2-factor-out-common-parts-of-stopping-and-restart.patch
+jbd2-use-the-correct-print-format.patch
+quota-factor-out-setup-of-quota-inode.patch
+ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-qu.patch
+ext4-lost-matching-pair-of-trace-in-ext4_truncate.patch
+ext4-fix-use-after-free-in-ext4_orphan_cleanup.patch
+ext4-fix-uninititialized-value-in-ext4_evict_inode.patch
diff --git a/queue-5.4/usb-ulpi-defer-ulpi_register-on-ulpi_read_id-timeout.patch b/queue-5.4/usb-ulpi-defer-ulpi_register-on-ulpi_read_id-timeout.patch
new file mode 100644 (file)
index 0000000..25a7780
--- /dev/null
@@ -0,0 +1,49 @@
+From bcd06b7e46305eecedfd5f9b87494c1e810d53f2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 5 Dec 2022 21:15:26 +0100
+Subject: usb: ulpi: defer ulpi_register on ulpi_read_id timeout
+
+From: Ferry Toth <ftoth@exalondelft.nl>
+
+[ Upstream commit 8a7b31d545d3a15f0e6f5984ae16f0ca4fd76aac ]
+
+Since commit 0f0101719138 ("usb: dwc3: Don't switch OTG -> peripheral
+if extcon is present") Dual Role support on Intel Merrifield platform
+broke due to rearranging the call to dwc3_get_extcon().
+
+It appears to be caused by ulpi_read_id() on the first test write failing
+with -ETIMEDOUT. Currently ulpi_read_id() expects to discover the phy via
+DT when the test write fails and returns 0 in that case, even if DT does not
+provide the phy. As a result usb probe completes without phy.
+
+Make ulpi_read_id() return -ETIMEDOUT to its user if the first test write
+fails. The user should then handle it appropriately. A follow up patch
+will make dwc3_core_init() set -EPROBE_DEFER in this case and bail out.
+
+Fixes: ef6a7bcfb01c ("usb: ulpi: Support device discovery via DT")
+Cc: stable@vger.kernel.org
+Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Signed-off-by: Ferry Toth <ftoth@exalondelft.nl>
+Link: https://lore.kernel.org/r/20221205201527.13525-2-ftoth@exalondelft.nl
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/common/ulpi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
+index c42c152bbc33..94700c1d2f6e 100644
+--- a/drivers/usb/common/ulpi.c
++++ b/drivers/usb/common/ulpi.c
+@@ -207,7 +207,7 @@ static int ulpi_read_id(struct ulpi *ulpi)
+       /* Test the interface */
+       ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa);
+       if (ret < 0)
+-              goto err;
++              return ret;
+       ret = ulpi_read(ulpi, ULPI_SCRATCH);
+       if (ret < 0)
+-- 
+2.35.1
+
diff --git a/queue-5.4/wifi-wilc1000-sdio-fix-module-autoloading.patch b/queue-5.4/wifi-wilc1000-sdio-fix-module-autoloading.patch
new file mode 100644 (file)
index 0000000..4a6526a
--- /dev/null
@@ -0,0 +1,36 @@
+From 2085ee74e78c63cecfc65a826f629e4cc3115b99 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Oct 2022 19:12:21 +0200
+Subject: wifi: wilc1000: sdio: fix module autoloading
+
+From: Michael Walle <michael@walle.cc>
+
+[ Upstream commit 57d545b5a3d6ce3a8fb6b093f02bfcbb908973f3 ]
+
+There are no SDIO module aliases included in the driver, therefore,
+module autoloading isn't working. Add the proper MODULE_DEVICE_TABLE().
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Michael Walle <michael@walle.cc>
+Signed-off-by: Kalle Valo <kvalo@kernel.org>
+Link: https://lore.kernel.org/r/20221027171221.491937-1-michael@walle.cc
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/staging/wilc1000/wilc_sdio.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c
+index c787c5da8f2b..22a30da011e1 100644
+--- a/drivers/staging/wilc1000/wilc_sdio.c
++++ b/drivers/staging/wilc1000/wilc_sdio.c
+@@ -20,6 +20,7 @@ static const struct sdio_device_id wilc_sdio_ids[] = {
+       { SDIO_DEVICE(SDIO_VENDOR_ID_WILC, SDIO_DEVICE_ID_WILC) },
+       { },
+ };
++MODULE_DEVICE_TABLE(sdio, wilc_sdio_ids);
+ #define WILC_SDIO_BLOCK_SIZE 512
+-- 
+2.35.1
+