This is a note to let you know that I've just added the patch titled ext4: fix data races when using cached status extents to the 6.1-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: ext4-fix-data-races-when-using-cached-status-extents.patch and it can be found in the queue-6.1 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From 492888df0c7b42fc0843631168b0021bc4caee84 Mon Sep 17 00:00:00 2001 From: Jan Kara <jack@xxxxxxx> Date: Thu, 4 May 2023 14:55:24 +0200 Subject: ext4: fix data races when using cached status extents From: Jan Kara <jack@xxxxxxx> commit 492888df0c7b42fc0843631168b0021bc4caee84 upstream. When using cached extent stored in extent status tree in tree->cache_es another process holding ei->i_es_lock for reading can be racing with us setting new value of tree->cache_es. If the compiler would decide to refetch tree->cache_es at an unfortunate moment, it could result in a bogus in_range() check. Fix the possible race by using READ_ONCE() when using tree->cache_es only under ei->i_es_lock for reading. Cc: stable@xxxxxxxxxx Reported-by: syzbot+4a03518df1e31b537066@xxxxxxxxxxxxxxxxxxxxxxxxx Link: https://lore.kernel.org/all/000000000000d3b33905fa0fd4a6@xxxxxxxxxx Suggested-by: Dmitry Vyukov <dvyukov@xxxxxxxxxx> Signed-off-by: Jan Kara <jack@xxxxxxx> Link: https://lore.kernel.org/r/20230504125524.10802-1-jack@xxxxxxx Signed-off-by: Theodore Ts'o <tytso@xxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- fs/ext4/extents_status.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c @@ -269,14 +269,12 @@ static void __es_find_extent_range(struc /* see if the extent has been cached */ es->es_lblk = es->es_len = es->es_pblk = 0; - if (tree->cache_es) { - es1 = tree->cache_es; - if (in_range(lblk, es1->es_lblk, es1->es_len)) { - es_debug("%u cached by [%u/%u) %llu %x\n", - lblk, es1->es_lblk, es1->es_len, - ext4_es_pblock(es1), ext4_es_status(es1)); - goto out; - } + es1 = READ_ONCE(tree->cache_es); + if (es1 && in_range(lblk, es1->es_lblk, es1->es_len)) { + es_debug("%u cached by [%u/%u) %llu %x\n", + lblk, es1->es_lblk, es1->es_len, + ext4_es_pblock(es1), ext4_es_status(es1)); + goto out; } es1 = __es_tree_search(&tree->root, lblk); @@ -295,7 +293,7 @@ out: } if (es1 && matching_fn(es1)) { - tree->cache_es = es1; + WRITE_ONCE(tree->cache_es, es1); es->es_lblk = es1->es_lblk; es->es_len = es1->es_len; es->es_pblk = es1->es_pblk; @@ -933,14 +931,12 @@ int ext4_es_lookup_extent(struct inode * /* find extent in cache firstly */ es->es_lblk = es->es_len = es->es_pblk = 0; - if (tree->cache_es) { - es1 = tree->cache_es; - if (in_range(lblk, es1->es_lblk, es1->es_len)) { - es_debug("%u cached by [%u/%u)\n", - lblk, es1->es_lblk, es1->es_len); - found = 1; - goto out; - } + es1 = READ_ONCE(tree->cache_es); + if (es1 && in_range(lblk, es1->es_lblk, es1->es_len)) { + es_debug("%u cached by [%u/%u)\n", + lblk, es1->es_lblk, es1->es_len); + found = 1; + goto out; } node = tree->root.rb_node; Patches currently in stable-queue which might be from jack@xxxxxxx are queue-6.1/inotify-avoid-reporting-event-with-invalid-wd.patch queue-6.1/ext4-fix-warning-in-mb_find_extent.patch queue-6.1/writeback-fix-call-of-incorrect-macro.patch queue-6.1/ext4-check-iomap-type-only-if-ext4_iomap_begin-does-not-fail.patch queue-6.1/ext4-fix-lockdep-warning-when-enabling-mmp.patch queue-6.1/ext4-fix-data-races-when-using-cached-status-extents.patch