* FAILED: patch "[PATCH] ext4: drop extent cache when splitting extent fails" failed to apply to 6.6-stable tree
@ 2026-02-24 21:44 gregkh
2026-02-25 3:42 ` [PATCH 6.6.y 1/5] ext4: get rid of ppath in ext4_find_extent() Sasha Levin
0 siblings, 1 reply; 6+ messages in thread
From: gregkh @ 2026-02-24 21:44 UTC (permalink / raw)
To: yi.zhang, libaokun1, ojaswin, tytso; +Cc: stable
The patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 79b592e8f1b435796cbc2722190368e3e8ffd7a1
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026022428-ranged-scrabble-b28b@gregkh' --subject-prefix 'PATCH 6.6.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 79b592e8f1b435796cbc2722190368e3e8ffd7a1 Mon Sep 17 00:00:00 2001
From: Zhang Yi <yi.zhang@huawei.com>
Date: Sat, 29 Nov 2025 18:32:39 +0800
Subject: [PATCH] ext4: drop extent cache when splitting extent fails
When the split extent fails, we might leave some extents still being
processed and return an error directly, which will result in stale
extent entries remaining in the extent status tree. So drop all of the
remaining potentially stale extents if the splitting fails.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Baokun Li <libaokun1@huawei.com>
Cc: stable@kernel.org
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Message-ID: <20251129103247.686136-8-yi.zhang@huaweicloud.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 1094e4923451..945995d68c4d 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3267,7 +3267,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle,
err = PTR_ERR(path);
if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM)
- return path;
+ goto out_path;
/*
* Get a new path to try to zeroout or fix the extent length.
@@ -3281,7 +3281,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle,
if (IS_ERR(path)) {
EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld",
split, PTR_ERR(path));
- return path;
+ goto out_path;
}
depth = ext_depth(inode);
ex = path[depth].p_ext;
@@ -3358,6 +3358,10 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle,
ext4_free_ext_path(path);
path = ERR_PTR(err);
}
+out_path:
+ if (IS_ERR(path))
+ /* Remove all remaining potentially stale extents. */
+ ext4_es_remove_extent(inode, ee_block, ee_len);
ext4_ext_show_leaf(inode, path);
return path;
}
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 6.6.y 1/5] ext4: get rid of ppath in ext4_find_extent()
2026-02-24 21:44 FAILED: patch "[PATCH] ext4: drop extent cache when splitting extent fails" failed to apply to 6.6-stable tree gregkh
@ 2026-02-25 3:42 ` Sasha Levin
2026-02-25 3:42 ` [PATCH 6.6.y 2/5] ext4: get rid of ppath in ext4_ext_create_new_leaf() Sasha Levin
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Sasha Levin @ 2026-02-25 3:42 UTC (permalink / raw)
To: stable; +Cc: Baokun Li, Jan Kara, Ojaswin Mujoo, Theodore Ts'o,
Sasha Levin
From: Baokun Li <libaokun1@huawei.com>
[ Upstream commit 0be4c0c2f17bd10ae16c852f02d51a6a7b318aca ]
The use of path and ppath is now very confusing, so to make the code more
readable, pass path between functions uniformly, and get rid of ppath.
Getting rid of ppath in ext4_find_extent() requires its caller to update
ppath. These ppaths will also be dropped later. No functional changes.
Signed-off-by: Baokun Li <libaokun1@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Link: https://patch.msgid.link/20240822023545.1994557-12-libaokun@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Stable-dep-of: 79b592e8f1b4 ("ext4: drop extent cache when splitting extent fails")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ext4/ext4.h | 2 +-
fs/ext4/extents.c | 55 +++++++++++++++++++++++--------------------
fs/ext4/move_extent.c | 7 +++---
3 files changed, 34 insertions(+), 30 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 85ba12a48f26a..dd0317d66c1db 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -3712,7 +3712,7 @@ extern int ext4_ext_insert_extent(handle_t *, struct inode *,
struct ext4_ext_path **,
struct ext4_extent *, int);
extern struct ext4_ext_path *ext4_find_extent(struct inode *, ext4_lblk_t,
- struct ext4_ext_path **,
+ struct ext4_ext_path *,
int flags);
extern void ext4_free_ext_path(struct ext4_ext_path *);
extern int ext4_ext_check_inode(struct inode *inode);
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index a3d3c9fc64262..9644a9203152c 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -881,11 +881,10 @@ void ext4_ext_tree_init(handle_t *handle, struct inode *inode)
struct ext4_ext_path *
ext4_find_extent(struct inode *inode, ext4_lblk_t block,
- struct ext4_ext_path **orig_path, int flags)
+ struct ext4_ext_path *path, int flags)
{
struct ext4_extent_header *eh;
struct buffer_head *bh;
- struct ext4_ext_path *path = orig_path ? *orig_path : NULL;
short int depth, i, ppos = 0;
int ret;
gfp_t gfp_flags = GFP_NOFS;
@@ -906,7 +905,7 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
ext4_ext_drop_refs(path);
if (depth > path[0].p_maxdepth) {
kfree(path);
- *orig_path = path = NULL;
+ path = NULL;
}
}
if (!path) {
@@ -957,14 +956,10 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
ext4_ext_show_path(inode, path);
- if (orig_path)
- *orig_path = path;
return path;
err:
ext4_free_ext_path(path);
- if (orig_path)
- *orig_path = NULL;
return ERR_PTR(ret);
}
@@ -1429,7 +1424,7 @@ static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
/* refill path */
path = ext4_find_extent(inode,
(ext4_lblk_t)le32_to_cpu(newext->ee_block),
- ppath, gb_flags);
+ path, gb_flags);
if (IS_ERR(path))
err = PTR_ERR(path);
} else {
@@ -1441,7 +1436,7 @@ static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
/* refill path */
path = ext4_find_extent(inode,
(ext4_lblk_t)le32_to_cpu(newext->ee_block),
- ppath, gb_flags);
+ path, gb_flags);
if (IS_ERR(path)) {
err = PTR_ERR(path);
goto out;
@@ -1457,8 +1452,8 @@ static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
goto repeat;
}
}
-
out:
+ *ppath = IS_ERR(path) ? NULL : path;
return err;
}
@@ -3243,15 +3238,17 @@ static int ext4_split_extent_at(handle_t *handle,
* WARN_ON may be triggered in ext4_da_update_reserve_space() due to
* an incorrect ee_len causing the i_reserved_data_blocks exception.
*/
- path = ext4_find_extent(inode, ee_block, ppath,
+ path = ext4_find_extent(inode, ee_block, *ppath,
flags | EXT4_EX_NOFAIL);
if (IS_ERR(path)) {
EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld",
split, PTR_ERR(path));
+ *ppath = NULL;
return PTR_ERR(path);
}
depth = ext_depth(inode);
ex = path[depth].p_ext;
+ *ppath = path;
if (EXT4_EXT_MAY_ZEROOUT & split_flag) {
if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) {
@@ -3361,9 +3358,12 @@ static int ext4_split_extent(handle_t *handle,
* Update path is required because previous ext4_split_extent_at() may
* result in split of original leaf or extent zeroout.
*/
- path = ext4_find_extent(inode, map->m_lblk, ppath, flags);
- if (IS_ERR(path))
+ path = ext4_find_extent(inode, map->m_lblk, *ppath, flags);
+ if (IS_ERR(path)) {
+ *ppath = NULL;
return PTR_ERR(path);
+ }
+ *ppath = path;
depth = ext_depth(inode);
ex = path[depth].p_ext;
if (!ex) {
@@ -3749,9 +3749,12 @@ static int ext4_convert_unwritten_extents_endio(handle_t *handle,
EXT4_GET_BLOCKS_CONVERT);
if (err < 0)
return err;
- path = ext4_find_extent(inode, map->m_lblk, ppath, 0);
- if (IS_ERR(path))
+ path = ext4_find_extent(inode, map->m_lblk, *ppath, 0);
+ if (IS_ERR(path)) {
+ *ppath = NULL;
return PTR_ERR(path);
+ }
+ *ppath = path;
depth = ext_depth(inode);
ex = path[depth].p_ext;
}
@@ -3807,9 +3810,12 @@ convert_initialized_extent(handle_t *handle, struct inode *inode,
EXT4_GET_BLOCKS_CONVERT_UNWRITTEN);
if (err < 0)
return err;
- path = ext4_find_extent(inode, map->m_lblk, ppath, 0);
- if (IS_ERR(path))
+ path = ext4_find_extent(inode, map->m_lblk, *ppath, 0);
+ if (IS_ERR(path)) {
+ *ppath = NULL;
return PTR_ERR(path);
+ }
+ *ppath = path;
depth = ext_depth(inode);
ex = path[depth].p_ext;
if (!ex) {
@@ -5194,7 +5200,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
* won't be shifted beyond EXT_MAX_BLOCKS.
*/
if (SHIFT == SHIFT_LEFT) {
- path = ext4_find_extent(inode, start - 1, &path,
+ path = ext4_find_extent(inode, start - 1, path,
EXT4_EX_NOCACHE);
if (IS_ERR(path))
return PTR_ERR(path);
@@ -5243,7 +5249,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
* becomes NULL to indicate the end of the loop.
*/
while (iterator && start <= stop) {
- path = ext4_find_extent(inode, *iterator, &path,
+ path = ext4_find_extent(inode, *iterator, path,
EXT4_EX_NOCACHE);
if (IS_ERR(path))
return PTR_ERR(path);
@@ -5825,11 +5831,8 @@ int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu)
/* search for the extent closest to the first block in the cluster */
path = ext4_find_extent(inode, EXT4_C2B(sbi, lclu), NULL, 0);
- if (IS_ERR(path)) {
- err = PTR_ERR(path);
- path = NULL;
- goto out;
- }
+ if (IS_ERR(path))
+ return PTR_ERR(path);
depth = ext_depth(inode);
@@ -5913,7 +5916,7 @@ int ext4_ext_replay_update_ex(struct inode *inode, ext4_lblk_t start,
if (ret)
goto out;
- path = ext4_find_extent(inode, start, &path, 0);
+ path = ext4_find_extent(inode, start, path, 0);
if (IS_ERR(path))
return PTR_ERR(path);
ex = path[path->p_depth].p_ext;
@@ -5927,7 +5930,7 @@ int ext4_ext_replay_update_ex(struct inode *inode, ext4_lblk_t start,
if (ret)
goto out;
- path = ext4_find_extent(inode, start, &path, 0);
+ path = ext4_find_extent(inode, start, path, 0);
if (IS_ERR(path))
return PTR_ERR(path);
ex = path[path->p_depth].p_ext;
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index a3b0acca02ca5..d5636a2a718a8 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -26,16 +26,17 @@ static inline int
get_ext_path(struct inode *inode, ext4_lblk_t lblock,
struct ext4_ext_path **ppath)
{
- struct ext4_ext_path *path;
+ struct ext4_ext_path *path = *ppath;
- path = ext4_find_extent(inode, lblock, ppath, EXT4_EX_NOCACHE);
+ *ppath = NULL;
+ path = ext4_find_extent(inode, lblock, path, EXT4_EX_NOCACHE);
if (IS_ERR(path))
return PTR_ERR(path);
if (path[ext_depth(inode)].p_ext == NULL) {
ext4_free_ext_path(path);
- *ppath = NULL;
return -ENODATA;
}
+ *ppath = path;
return 0;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 6.6.y 2/5] ext4: get rid of ppath in ext4_ext_create_new_leaf()
2026-02-25 3:42 ` [PATCH 6.6.y 1/5] ext4: get rid of ppath in ext4_find_extent() Sasha Levin
@ 2026-02-25 3:42 ` Sasha Levin
2026-02-25 3:42 ` [PATCH 6.6.y 3/5] ext4: get rid of ppath in ext4_ext_insert_extent() Sasha Levin
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-02-25 3:42 UTC (permalink / raw)
To: stable; +Cc: Baokun Li, Jan Kara, Ojaswin Mujoo, Theodore Ts'o,
Sasha Levin
From: Baokun Li <libaokun1@huawei.com>
[ Upstream commit a000bc8678cc2bb10a5b80b4e991e77c7b4612fd ]
The use of path and ppath is now very confusing, so to make the code more
readable, pass path between functions uniformly, and get rid of ppath.
To get rid of the ppath in ext4_ext_create_new_leaf(), the following is
done here:
* Free the extents path when an error is encountered.
* Its caller needs to update ppath if it uses ppath.
No functional changes.
Signed-off-by: Baokun Li <libaokun1@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Link: https://patch.msgid.link/20240822023545.1994557-14-libaokun@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Stable-dep-of: 79b592e8f1b4 ("ext4: drop extent cache when splitting extent fails")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ext4/extents.c | 43 ++++++++++++++++++++++---------------------
1 file changed, 22 insertions(+), 21 deletions(-)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 9644a9203152c..27db7c752dafd 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -1392,13 +1392,12 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
* finds empty index and adds new leaf.
* if no free index is found, then it requests in-depth growing.
*/
-static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
- unsigned int mb_flags,
- unsigned int gb_flags,
- struct ext4_ext_path **ppath,
- struct ext4_extent *newext)
+static struct ext4_ext_path *
+ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
+ unsigned int mb_flags, unsigned int gb_flags,
+ struct ext4_ext_path *path,
+ struct ext4_extent *newext)
{
- struct ext4_ext_path *path = *ppath;
struct ext4_ext_path *curp;
int depth, i, err = 0;
@@ -1419,28 +1418,25 @@ static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
* entry: create all needed subtree and add new leaf */
err = ext4_ext_split(handle, inode, mb_flags, path, newext, i);
if (err)
- goto out;
+ goto errout;
/* refill path */
path = ext4_find_extent(inode,
(ext4_lblk_t)le32_to_cpu(newext->ee_block),
path, gb_flags);
- if (IS_ERR(path))
- err = PTR_ERR(path);
+ return path;
} else {
/* tree is full, time to grow in depth */
err = ext4_ext_grow_indepth(handle, inode, mb_flags);
if (err)
- goto out;
+ goto errout;
/* refill path */
path = ext4_find_extent(inode,
(ext4_lblk_t)le32_to_cpu(newext->ee_block),
path, gb_flags);
- if (IS_ERR(path)) {
- err = PTR_ERR(path);
- goto out;
- }
+ if (IS_ERR(path))
+ return path;
/*
* only first (depth 0 -> 1) produces free space;
@@ -1452,9 +1448,11 @@ static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
goto repeat;
}
}
-out:
- *ppath = IS_ERR(path) ? NULL : path;
- return err;
+ return path;
+
+errout:
+ ext4_free_ext_path(path);
+ return ERR_PTR(err);
}
/*
@@ -2097,11 +2095,14 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
*/
if (gb_flags & EXT4_GET_BLOCKS_METADATA_NOFAIL)
mb_flags |= EXT4_MB_USE_RESERVED;
- err = ext4_ext_create_new_leaf(handle, inode, mb_flags, gb_flags,
- ppath, newext);
- if (err)
+ path = ext4_ext_create_new_leaf(handle, inode, mb_flags, gb_flags,
+ path, newext);
+ if (IS_ERR(path)) {
+ *ppath = NULL;
+ err = PTR_ERR(path);
goto cleanup;
- path = *ppath;
+ }
+ *ppath = path;
depth = ext_depth(inode);
eh = path[depth].p_hdr;
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 6.6.y 3/5] ext4: get rid of ppath in ext4_ext_insert_extent()
2026-02-25 3:42 ` [PATCH 6.6.y 1/5] ext4: get rid of ppath in ext4_find_extent() Sasha Levin
2026-02-25 3:42 ` [PATCH 6.6.y 2/5] ext4: get rid of ppath in ext4_ext_create_new_leaf() Sasha Levin
@ 2026-02-25 3:42 ` Sasha Levin
2026-02-25 3:42 ` [PATCH 6.6.y 4/5] ext4: get rid of ppath in ext4_split_extent_at() Sasha Levin
2026-02-25 3:42 ` [PATCH 6.6.y 5/5] ext4: drop extent cache when splitting extent fails Sasha Levin
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-02-25 3:42 UTC (permalink / raw)
To: stable; +Cc: Baokun Li, Jan Kara, Ojaswin Mujoo, Theodore Ts'o,
Sasha Levin
From: Baokun Li <libaokun1@huawei.com>
[ Upstream commit f7d1331f16a869c76a5102caebb58e840e1d509c ]
The use of path and ppath is now very confusing, so to make the code more
readable, pass path between functions uniformly, and get rid of ppath.
To get rid of the ppath in ext4_ext_insert_extent(), the following is done
here:
* Free the extents path when an error is encountered.
* Its caller needs to update ppath if it uses ppath.
* Free path when npath is used, free npath when it is not used.
* The got_allocated_blocks label in ext4_ext_map_blocks() does not
update err now, so err is updated to 0 if the err returned by
ext4_ext_search_right() is greater than 0 and is about to enter
got_allocated_blocks.
No functional changes.
Signed-off-by: Baokun Li <libaokun1@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Link: https://patch.msgid.link/20240822023545.1994557-15-libaokun@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Stable-dep-of: 79b592e8f1b4 ("ext4: drop extent cache when splitting extent fails")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ext4/ext4.h | 7 ++--
fs/ext4/extents.c | 88 ++++++++++++++++++++++++-------------------
fs/ext4/fast_commit.c | 8 ++--
fs/ext4/migrate.c | 5 ++-
4 files changed, 61 insertions(+), 47 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index dd0317d66c1db..ce8bd312c1b84 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -3708,9 +3708,10 @@ extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode,
int num,
struct ext4_ext_path *path);
-extern int ext4_ext_insert_extent(handle_t *, struct inode *,
- struct ext4_ext_path **,
- struct ext4_extent *, int);
+extern struct ext4_ext_path *ext4_ext_insert_extent(
+ handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path,
+ struct ext4_extent *newext, int gb_flags);
extern struct ext4_ext_path *ext4_find_extent(struct inode *, ext4_lblk_t,
struct ext4_ext_path *,
int flags);
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 27db7c752dafd..2d0a3ed6a3cc5 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -1960,16 +1960,15 @@ static unsigned int ext4_ext_check_overlap(struct ext4_sb_info *sbi,
* inserts requested extent as new one into the tree,
* creating new leaf in the no-space case.
*/
-int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
- struct ext4_ext_path **ppath,
- struct ext4_extent *newext, int gb_flags)
+struct ext4_ext_path *
+ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path,
+ struct ext4_extent *newext, int gb_flags)
{
- struct ext4_ext_path *path = *ppath;
struct ext4_extent_header *eh;
struct ext4_extent *ex, *fex;
struct ext4_extent *nearex; /* nearest extent */
- struct ext4_ext_path *npath = NULL;
- int depth, len, err;
+ int depth, len, err = 0;
ext4_lblk_t next;
int mb_flags = 0, unwritten;
@@ -1977,14 +1976,16 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
mb_flags |= EXT4_MB_DELALLOC_RESERVED;
if (unlikely(ext4_ext_get_actual_len(newext) == 0)) {
EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0");
- return -EFSCORRUPTED;
+ err = -EFSCORRUPTED;
+ goto errout;
}
depth = ext_depth(inode);
ex = path[depth].p_ext;
eh = path[depth].p_hdr;
if (unlikely(path[depth].p_hdr == NULL)) {
EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth);
- return -EFSCORRUPTED;
+ err = -EFSCORRUPTED;
+ goto errout;
}
/* try to insert block into found extent and return */
@@ -2022,7 +2023,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
err = ext4_ext_get_access(handle, inode,
path + depth);
if (err)
- return err;
+ goto errout;
unwritten = ext4_ext_is_unwritten(ex);
ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+ ext4_ext_get_actual_len(newext));
@@ -2047,7 +2048,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
err = ext4_ext_get_access(handle, inode,
path + depth);
if (err)
- return err;
+ goto errout;
unwritten = ext4_ext_is_unwritten(ex);
ex->ee_block = newext->ee_block;
@@ -2072,21 +2073,26 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block))
next = ext4_ext_next_leaf_block(path);
if (next != EXT_MAX_BLOCKS) {
+ struct ext4_ext_path *npath;
+
ext_debug(inode, "next leaf block - %u\n", next);
- BUG_ON(npath != NULL);
npath = ext4_find_extent(inode, next, NULL, gb_flags);
- if (IS_ERR(npath))
- return PTR_ERR(npath);
+ if (IS_ERR(npath)) {
+ err = PTR_ERR(npath);
+ goto errout;
+ }
BUG_ON(npath->p_depth != path->p_depth);
eh = npath[depth].p_hdr;
if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) {
ext_debug(inode, "next leaf isn't full(%d)\n",
le16_to_cpu(eh->eh_entries));
+ ext4_free_ext_path(path);
path = npath;
goto has_space;
}
ext_debug(inode, "next leaf has no free space(%d,%d)\n",
le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
+ ext4_free_ext_path(npath);
}
/*
@@ -2097,12 +2103,8 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
mb_flags |= EXT4_MB_USE_RESERVED;
path = ext4_ext_create_new_leaf(handle, inode, mb_flags, gb_flags,
path, newext);
- if (IS_ERR(path)) {
- *ppath = NULL;
- err = PTR_ERR(path);
- goto cleanup;
- }
- *ppath = path;
+ if (IS_ERR(path))
+ return path;
depth = ext_depth(inode);
eh = path[depth].p_hdr;
@@ -2111,7 +2113,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
err = ext4_ext_get_access(handle, inode, path + depth);
if (err)
- goto cleanup;
+ goto errout;
if (!nearex) {
/* there is no extent in this leaf, create first one */
@@ -2169,17 +2171,20 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
if (!(gb_flags & EXT4_GET_BLOCKS_PRE_IO))
ext4_ext_try_to_merge(handle, inode, path, nearex);
-
/* time to correct all indexes above */
err = ext4_ext_correct_indexes(handle, inode, path);
if (err)
- goto cleanup;
+ goto errout;
err = ext4_ext_dirty(handle, inode, path + path->p_depth);
+ if (err)
+ goto errout;
-cleanup:
- ext4_free_ext_path(npath);
- return err;
+ return path;
+
+errout:
+ ext4_free_ext_path(path);
+ return ERR_PTR(err);
}
static int ext4_fill_es_cache_info(struct inode *inode,
@@ -3227,24 +3232,29 @@ static int ext4_split_extent_at(handle_t *handle,
if (split_flag & EXT4_EXT_MARK_UNWRIT2)
ext4_ext_mark_unwritten(ex2);
- err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags);
- if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM)
+ path = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
+ if (!IS_ERR(path)) {
+ *ppath = path;
goto out;
+ }
+ *ppath = NULL;
+ err = PTR_ERR(path);
+ if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM)
+ return err;
/*
- * Update path is required because previous ext4_ext_insert_extent()
- * may have freed or reallocated the path. Using EXT4_EX_NOFAIL
- * guarantees that ext4_find_extent() will not return -ENOMEM,
- * otherwise -ENOMEM will cause a retry in do_writepages(), and a
- * WARN_ON may be triggered in ext4_da_update_reserve_space() due to
- * an incorrect ee_len causing the i_reserved_data_blocks exception.
+ * Get a new path to try to zeroout or fix the extent length.
+ * Using EXT4_EX_NOFAIL guarantees that ext4_find_extent()
+ * will not return -ENOMEM, otherwise -ENOMEM will cause a
+ * retry in do_writepages(), and a WARN_ON may be triggered
+ * in ext4_da_update_reserve_space() due to an incorrect
+ * ee_len causing the i_reserved_data_blocks exception.
*/
- path = ext4_find_extent(inode, ee_block, *ppath,
+ path = ext4_find_extent(inode, ee_block, NULL,
flags | EXT4_EX_NOFAIL);
if (IS_ERR(path)) {
EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld",
split, PTR_ERR(path));
- *ppath = NULL;
return PTR_ERR(path);
}
depth = ext_depth(inode);
@@ -3303,7 +3313,7 @@ static int ext4_split_extent_at(handle_t *handle,
ext4_ext_dirty(handle, inode, path + path->p_depth);
return err;
out:
- ext4_ext_show_leaf(inode, *ppath);
+ ext4_ext_show_leaf(inode, path);
return err;
}
@@ -4290,6 +4300,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
get_implied_cluster_alloc(inode->i_sb, map, &ex2, path)) {
ar.len = allocated = map->m_len;
newblock = map->m_pblk;
+ err = 0;
goto got_allocated_blocks;
}
@@ -4362,8 +4373,9 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
map->m_flags |= EXT4_MAP_UNWRITTEN;
}
- err = ext4_ext_insert_extent(handle, inode, &path, &newex, flags);
- if (err) {
+ path = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
if (allocated_clusters) {
int fb_flags = 0;
diff --git a/fs/ext4/fast_commit.c b/fs/ext4/fast_commit.c
index 62a6960242c5a..be65b5f51d9e2 100644
--- a/fs/ext4/fast_commit.c
+++ b/fs/ext4/fast_commit.c
@@ -1806,12 +1806,12 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
if (ext4_ext_is_unwritten(ex))
ext4_ext_mark_unwritten(&newex);
down_write(&EXT4_I(inode)->i_data_sem);
- ret = ext4_ext_insert_extent(
- NULL, inode, &path, &newex, 0);
+ path = ext4_ext_insert_extent(NULL, inode,
+ path, &newex, 0);
up_write((&EXT4_I(inode)->i_data_sem));
- ext4_free_ext_path(path);
- if (ret)
+ if (IS_ERR(path))
goto out;
+ ext4_free_ext_path(path);
goto next;
}
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
index a5e1492bbaaa5..1b0dfd963d3f0 100644
--- a/fs/ext4/migrate.c
+++ b/fs/ext4/migrate.c
@@ -37,7 +37,6 @@ static int finish_range(handle_t *handle, struct inode *inode,
path = ext4_find_extent(inode, lb->first_block, NULL, 0);
if (IS_ERR(path)) {
retval = PTR_ERR(path);
- path = NULL;
goto err_out;
}
@@ -53,7 +52,9 @@ static int finish_range(handle_t *handle, struct inode *inode,
retval = ext4_datasem_ensure_credits(handle, inode, needed, needed, 0);
if (retval < 0)
goto err_out;
- retval = ext4_ext_insert_extent(handle, inode, &path, &newext, 0);
+ path = ext4_ext_insert_extent(handle, inode, path, &newext, 0);
+ if (IS_ERR(path))
+ retval = PTR_ERR(path);
err_out:
up_write((&EXT4_I(inode)->i_data_sem));
ext4_free_ext_path(path);
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 6.6.y 4/5] ext4: get rid of ppath in ext4_split_extent_at()
2026-02-25 3:42 ` [PATCH 6.6.y 1/5] ext4: get rid of ppath in ext4_find_extent() Sasha Levin
2026-02-25 3:42 ` [PATCH 6.6.y 2/5] ext4: get rid of ppath in ext4_ext_create_new_leaf() Sasha Levin
2026-02-25 3:42 ` [PATCH 6.6.y 3/5] ext4: get rid of ppath in ext4_ext_insert_extent() Sasha Levin
@ 2026-02-25 3:42 ` Sasha Levin
2026-02-25 3:42 ` [PATCH 6.6.y 5/5] ext4: drop extent cache when splitting extent fails Sasha Levin
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-02-25 3:42 UTC (permalink / raw)
To: stable; +Cc: Baokun Li, Jan Kara, Ojaswin Mujoo, Theodore Ts'o,
Sasha Levin
From: Baokun Li <libaokun1@huawei.com>
[ Upstream commit 1de82b1b60d4613753254bf3cbf622a4c02c945c ]
The use of path and ppath is now very confusing, so to make the code more
readable, pass path between functions uniformly, and get rid of ppath.
To get rid of the ppath in ext4_split_extent_at(), the following is done
here:
* Free the extents path when an error is encountered.
* Its caller needs to update ppath if it uses ppath.
* Teach ext4_ext_show_leaf() to skip error pointer.
No functional changes.
Signed-off-by: Baokun Li <libaokun1@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Link: https://patch.msgid.link/20240822023545.1994557-16-libaokun@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Stable-dep-of: 79b592e8f1b4 ("ext4: drop extent cache when splitting extent fails")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ext4/extents.c | 85 ++++++++++++++++++++++++++---------------------
1 file changed, 47 insertions(+), 38 deletions(-)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 2d0a3ed6a3cc5..3fd5d4c500f56 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -84,12 +84,11 @@ static void ext4_extent_block_csum_set(struct inode *inode,
et->et_checksum = ext4_extent_block_csum(inode, eh);
}
-static int ext4_split_extent_at(handle_t *handle,
- struct inode *inode,
- struct ext4_ext_path **ppath,
- ext4_lblk_t split,
- int split_flag,
- int flags);
+static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle,
+ struct inode *inode,
+ struct ext4_ext_path *path,
+ ext4_lblk_t split,
+ int split_flag, int flags);
static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped)
{
@@ -335,9 +334,15 @@ ext4_force_split_extent_at(handle_t *handle, struct inode *inode,
if (nofail)
flags |= EXT4_GET_BLOCKS_METADATA_NOFAIL | EXT4_EX_NOFAIL;
- return ext4_split_extent_at(handle, inode, ppath, lblk, unwritten ?
+ path = ext4_split_extent_at(handle, inode, path, lblk, unwritten ?
EXT4_EXT_MARK_UNWRIT1|EXT4_EXT_MARK_UNWRIT2 : 0,
flags);
+ if (IS_ERR(path)) {
+ *ppath = NULL;
+ return PTR_ERR(path);
+ }
+ *ppath = path;
+ return 0;
}
static int
@@ -689,7 +694,7 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
struct ext4_extent *ex;
int i;
- if (!path)
+ if (IS_ERR_OR_NULL(path))
return;
eh = path[depth].p_hdr;
@@ -3153,16 +3158,14 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
* a> the extent are splitted into two extent.
* b> split is not needed, and just mark the extent.
*
- * return 0 on success.
+ * Return an extent path pointer on success, or an error pointer on failure.
*/
-static int ext4_split_extent_at(handle_t *handle,
- struct inode *inode,
- struct ext4_ext_path **ppath,
- ext4_lblk_t split,
- int split_flag,
- int flags)
+static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle,
+ struct inode *inode,
+ struct ext4_ext_path *path,
+ ext4_lblk_t split,
+ int split_flag, int flags)
{
- struct ext4_ext_path *path = *ppath;
ext4_fsblk_t newblock;
ext4_lblk_t ee_block;
struct ext4_extent *ex, newex, orig_ex, zero_ex;
@@ -3233,14 +3236,12 @@ static int ext4_split_extent_at(handle_t *handle,
ext4_ext_mark_unwritten(ex2);
path = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
- if (!IS_ERR(path)) {
- *ppath = path;
+ if (!IS_ERR(path))
goto out;
- }
- *ppath = NULL;
+
err = PTR_ERR(path);
if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM)
- return err;
+ return path;
/*
* Get a new path to try to zeroout or fix the extent length.
@@ -3250,16 +3251,14 @@ static int ext4_split_extent_at(handle_t *handle,
* in ext4_da_update_reserve_space() due to an incorrect
* ee_len causing the i_reserved_data_blocks exception.
*/
- path = ext4_find_extent(inode, ee_block, NULL,
- flags | EXT4_EX_NOFAIL);
+ path = ext4_find_extent(inode, ee_block, NULL, flags | EXT4_EX_NOFAIL);
if (IS_ERR(path)) {
EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld",
split, PTR_ERR(path));
- return PTR_ERR(path);
+ return path;
}
depth = ext_depth(inode);
ex = path[depth].p_ext;
- *ppath = path;
if (EXT4_EXT_MAY_ZEROOUT & split_flag) {
if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) {
@@ -3311,10 +3310,13 @@ static int ext4_split_extent_at(handle_t *handle,
* and err is a non-zero error code.
*/
ext4_ext_dirty(handle, inode, path + path->p_depth);
- return err;
out:
+ if (err) {
+ ext4_free_ext_path(path);
+ path = ERR_PTR(err);
+ }
ext4_ext_show_leaf(inode, path);
- return err;
+ return path;
}
/*
@@ -3358,10 +3360,14 @@ static int ext4_split_extent(handle_t *handle,
EXT4_EXT_MARK_UNWRIT2;
if (split_flag & EXT4_EXT_DATA_VALID2)
split_flag1 |= EXT4_EXT_DATA_VALID1;
- err = ext4_split_extent_at(handle, inode, ppath,
+ path = ext4_split_extent_at(handle, inode, path,
map->m_lblk + map->m_len, split_flag1, flags1);
- if (err)
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
+ *ppath = NULL;
goto out;
+ }
+ *ppath = path;
} else {
allocated = ee_len - (map->m_lblk - ee_block);
}
@@ -3369,7 +3375,7 @@ static int ext4_split_extent(handle_t *handle,
* Update path is required because previous ext4_split_extent_at() may
* result in split of original leaf or extent zeroout.
*/
- path = ext4_find_extent(inode, map->m_lblk, *ppath, flags);
+ path = ext4_find_extent(inode, map->m_lblk, path, flags);
if (IS_ERR(path)) {
*ppath = NULL;
return PTR_ERR(path);
@@ -3391,13 +3397,17 @@ static int ext4_split_extent(handle_t *handle,
split_flag1 |= split_flag & (EXT4_EXT_MAY_ZEROOUT |
EXT4_EXT_MARK_UNWRIT2);
}
- err = ext4_split_extent_at(handle, inode, ppath,
+ path = ext4_split_extent_at(handle, inode, path,
map->m_lblk, split_flag1, flags);
- if (err)
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
+ *ppath = NULL;
goto out;
+ }
+ *ppath = path;
}
- ext4_ext_show_leaf(inode, *ppath);
+ ext4_ext_show_leaf(inode, path);
out:
return err ? err : allocated;
}
@@ -5583,22 +5593,21 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
if (ext4_ext_is_unwritten(extent))
split_flag = EXT4_EXT_MARK_UNWRIT1 |
EXT4_EXT_MARK_UNWRIT2;
- ret = ext4_split_extent_at(handle, inode, &path,
+ path = ext4_split_extent_at(handle, inode, path,
offset_lblk, split_flag,
EXT4_EX_NOCACHE |
EXT4_GET_BLOCKS_PRE_IO |
EXT4_GET_BLOCKS_METADATA_NOFAIL);
}
- ext4_free_ext_path(path);
- if (ret < 0) {
+ if (IS_ERR(path)) {
up_write(&EXT4_I(inode)->i_data_sem);
+ ret = PTR_ERR(path);
goto out_stop;
}
- } else {
- ext4_free_ext_path(path);
}
+ ext4_free_ext_path(path);
ext4_es_remove_extent(inode, offset_lblk, EXT_MAX_BLOCKS - offset_lblk);
/*
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 6.6.y 5/5] ext4: drop extent cache when splitting extent fails
2026-02-25 3:42 ` [PATCH 6.6.y 1/5] ext4: get rid of ppath in ext4_find_extent() Sasha Levin
` (2 preceding siblings ...)
2026-02-25 3:42 ` [PATCH 6.6.y 4/5] ext4: get rid of ppath in ext4_split_extent_at() Sasha Levin
@ 2026-02-25 3:42 ` Sasha Levin
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-02-25 3:42 UTC (permalink / raw)
To: stable
Cc: Zhang Yi, Baokun Li, stable, Ojaswin Mujoo, Theodore Ts'o,
Sasha Levin
From: Zhang Yi <yi.zhang@huawei.com>
[ Upstream commit 79b592e8f1b435796cbc2722190368e3e8ffd7a1 ]
When the split extent fails, we might leave some extents still being
processed and return an error directly, which will result in stale
extent entries remaining in the extent status tree. So drop all of the
remaining potentially stale extents if the splitting fails.
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Baokun Li <libaokun1@huawei.com>
Cc: stable@kernel.org
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Message-ID: <20251129103247.686136-8-yi.zhang@huaweicloud.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ext4/extents.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 3fd5d4c500f56..3230f5c1207be 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3241,7 +3241,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle,
err = PTR_ERR(path);
if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM)
- return path;
+ goto out_path;
/*
* Get a new path to try to zeroout or fix the extent length.
@@ -3255,7 +3255,7 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle,
if (IS_ERR(path)) {
EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld",
split, PTR_ERR(path));
- return path;
+ goto out_path;
}
depth = ext_depth(inode);
ex = path[depth].p_ext;
@@ -3315,6 +3315,10 @@ static struct ext4_ext_path *ext4_split_extent_at(handle_t *handle,
ext4_free_ext_path(path);
path = ERR_PTR(err);
}
+out_path:
+ if (IS_ERR(path))
+ /* Remove all remaining potentially stale extents. */
+ ext4_es_remove_extent(inode, ee_block, ee_len);
ext4_ext_show_leaf(inode, path);
return path;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-02-25 3:42 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-24 21:44 FAILED: patch "[PATCH] ext4: drop extent cache when splitting extent fails" failed to apply to 6.6-stable tree gregkh
2026-02-25 3:42 ` [PATCH 6.6.y 1/5] ext4: get rid of ppath in ext4_find_extent() Sasha Levin
2026-02-25 3:42 ` [PATCH 6.6.y 2/5] ext4: get rid of ppath in ext4_ext_create_new_leaf() Sasha Levin
2026-02-25 3:42 ` [PATCH 6.6.y 3/5] ext4: get rid of ppath in ext4_ext_insert_extent() Sasha Levin
2026-02-25 3:42 ` [PATCH 6.6.y 4/5] ext4: get rid of ppath in ext4_split_extent_at() Sasha Levin
2026-02-25 3:42 ` [PATCH 6.6.y 5/5] ext4: drop extent cache when splitting extent fails Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox