--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
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
--- /dev/null
+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
+
--- /dev/null
+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
+