FAILED: patch "[PATCH] ext4: drop extent cache when splitting extent fails" failed to apply to 6.1-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.1-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 <[email protected]>.
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.1.y
git checkout FETCH_HEAD
git cherry-pick -x 79b592e8f1b435796cbc2722190368e3e8ffd7a1
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026022428-arrogant-refill-c828@gregkh' --subject-prefix 'PATCH 6.1.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 <[email protected]>
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.
Message-ID: <[email protected]>
fs/ext4/extents.c +6 -2
@@ -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; }
Sasha Levin
maintainerPATCH 1/6 ext4: make ext4_es_remove_extent() return void
From: Baokun Li <[email protected]>
[ Upstream commit ed5d285b3f2a9a37ff778c5e440daf49351fcc4d ]
Now ext4_es_remove_extent() never fails, so make it return void.
Stable-dep-of: 79b592e8f1b4 ("ext4: drop extent cache when splitting extent fails")
--- fs/ext4/extents.c | 34 ++++++---------------------------- fs/ext4/extents_status.c | 12 ++++++------ fs/ext4/extents_status.h | 4 ++-- fs/ext4/inline.c | 12 ++---------- fs/ext4/inode.c | 8 ++------ 5 files changed, 18 insertions(+), 52 deletions(-)
fs/ext4/extents.c +6 -28
@@ -4457,15 +4457,8 @@ int ext4_ext_truncate(handle_t *handle, struct inode *inode) last_block = (inode->i_size + sb->s_blocksize -1 ) >>EXT4_BLOCK_SIZE_BITS (sb); -retry: - err =ext4_es_remove_extent (inode, last_block, -EXT_MAX_BLOCKS - last_block); -if (err == -ENOMEM ) { -memalloc_retry_wait (GFP_ATOMIC ); - goto retry; - } -if (err) -return err; +ext4_es_remove_extent (inode, last_block,EXT_MAX_BLOCKS - last_block); + retry_remove_space: err =ext4_ext_remove_space (inode, last_block,EXT_MAX_BLOCKS -1 );if (err == -ENOMEM ) {
@@ -5412,13 +5405,7 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len)down_write (&EXT4_I (inode)->i_data_sem);ext4_discard_preallocations (inode,0 ); - - ret =ext4_es_remove_extent (inode, punch_start, -EXT_MAX_BLOCKS - punch_start); -if (ret) { -up_write (&EXT4_I (inode)->i_data_sem); - goto out_stop; - } +ext4_es_remove_extent (inode, punch_start,EXT_MAX_BLOCKS - punch_start); ret =ext4_ext_remove_space (inode, punch_start, punch_stop -1 );if (ret) {
@@ -5604,12 +5591,7 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)ext4_free_ext_path (path); } - ret =ext4_es_remove_extent (inode, offset_lblk, -EXT_MAX_BLOCKS - offset_lblk); -if (ret) { -up_write (&EXT4_I (inode)->i_data_sem); - goto out_stop; - } +ext4_es_remove_extent (inode, offset_lblk,EXT_MAX_BLOCKS - offset_lblk);/* * if offset_lblk lies in a hole which is at start of file, use
@@ -5668,12 +5650,8 @@ ext4_swap_extents(handle_t *handle, struct inode *inode1,BUG_ON (!inode_is_locked (inode1));BUG_ON (!inode_is_locked (inode2)); - *erp =ext4_es_remove_extent (inode1, lblk1, count); -if (unlikely (*erp)) -return 0 ; - *erp =ext4_es_remove_extent (inode2, lblk2, count); -if (unlikely (*erp)) -return 0 ; +ext4_es_remove_extent (inode1, lblk1, count); +ext4_es_remove_extent (inode2, lblk2, count);while (count) {struct ext4_extent *ex1, *ex2, tmp_ex;
fs/ext4/extents_status.c +6 -6
@@ -1494,10 +1494,10 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk,* @len - number of blocks to remove * * Reduces block/cluster reservation count and for bigalloc cancels pending -* reservations as needed. Returns 0 on success, error code on failure. +* reservations as needed. */ -int ext4_es_remove_extent (struct inode *inode,ext4_lblk_t lblk, -ext4_lblk_t len) +void ext4_es_remove_extent (struct inode *inode,ext4_lblk_t lblk, +ext4_lblk_t len) {ext4_lblk_t end;int err =0 ;
@@ -1505,14 +1505,14 @@ int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk,struct extent_status *es =NULL ;if (EXT4_SB (inode->i_sb)->s_mount_state &EXT4_FC_REPLAY ) -return 0 ; +return ;trace_ext4_es_remove_extent (inode, lblk, len);es_debug ("remove [%u/%u) from extent status tree of inode %lu\n" , lblk, len, inode->i_ino);if (!len) -return err; +return ; end = lblk + len -1 ;BUG_ON (end < lblk);
@@ -1539,7 +1539,7 @@ int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk,ext4_es_print_tree (inode);ext4_da_release_space (inode, reserved); -return 0 ; +return ; } static int __es_shrink(struct ext4_sb_info *sbi, int nr_to_scan,
fs/ext4/extents_status.h +2 -2
@@ -133,8 +133,8 @@ extern void ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,extern void ext4_es_cache_extent (struct inode *inode,ext4_lblk_t lblk,ext4_lblk_t len,ext4_fsblk_t pblk,unsigned int status); -extern int ext4_es_remove_extent (struct inode *inode,ext4_lblk_t lblk, -ext4_lblk_t len); +extern void ext4_es_remove_extent (struct inode *inode,ext4_lblk_t lblk, +ext4_lblk_t len); extern void ext4_es_find_extent_range(struct inode *inode, int (*match_fn)(struct extent_status *es), ext4_lblk_t lblk, ext4_lblk_t end,
fs/ext4/inline.c +2 -10
@@ -2004,16 +2004,8 @@ int ext4_inline_data_truncate(struct inode *inode, int *has_inline)* the extent status cache must be cleared to avoid leaving * behind stale delayed allocated extent entries */ -if (!ext4_test_inode_state (inode,EXT4_STATE_MAY_INLINE_DATA )) { -retry: - err =ext4_es_remove_extent (inode,0 ,EXT_MAX_BLOCKS ); -if (err == -ENOMEM ) { -memalloc_retry_wait (GFP_ATOMIC ); - goto retry; - } -if (err) - goto out_error; - } +if (!ext4_test_inode_state (inode,EXT4_STATE_MAY_INLINE_DATA )) +ext4_es_remove_extent (inode,0 ,EXT_MAX_BLOCKS );/* Clear the content in the xattr space. */ if (inline_size >EXT4_MIN_INLINE_DATA_SIZE ) {
fs/ext4/inode.c +2 -6
@@ -4134,12 +4134,8 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)down_write (&EXT4_I (inode)->i_data_sem);ext4_discard_preallocations (inode,0 ); - ret =ext4_es_remove_extent (inode, first_block, - stop_block - first_block); -if (ret) { -up_write (&EXT4_I (inode)->i_data_sem); - goto out_stop; - } +ext4_es_remove_extent (inode, first_block, + stop_block - first_block);if (ext4_test_inode_flag (inode,EXT4_INODE_EXTENTS )) ret = ext4_ext_remove_space(inode, first_block,
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 2/6 ext4: get rid of ppath in ext4_find_extent()
From: Baokun Li <[email protected]>
[ 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.
Stable-dep-of: 79b592e8f1b4 ("ext4: drop extent cache when splitting extent fails")
--- fs/ext4/ext4.h | 2 +- fs/ext4/extents.c | 55 +++++++++++++++++++++++-------------------- fs/ext4/move_extent.c | 7 +++--- 3 files changed, 34 insertions(+), 30 deletions(-)
fs/ext4/ext4.h +1 -1
@@ -3723,7 +3723,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);
fs/ext4/extents.c +29 -26
164 lines not on this page · raw message
fs/ext4/move_extent.c +4 -3
@@ -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 ; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 3/6 ext4: get rid of ppath in ext4_ext_create_new_leaf()
In reply to Sasha LevinFrom: Baokun Li <[email protected]>
[ 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.
Stable-dep-of: 79b592e8f1b4 ("ext4: drop extent cache when splitting extent fails")
--- fs/ext4/extents.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-)
fs/ext4/extents.c +22 -21
@@ -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;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 4/6 ext4: get rid of ppath in ext4_ext_insert_extent()
In reply to Sasha LevinFrom: Baokun Li <[email protected]>
[ 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.
Stable-dep-of: 79b592e8f1b4 ("ext4: drop extent cache when splitting extent fails")
--- 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(-)
fs/ext4/ext4.h +4 -3
@@ -3719,9 +3719,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);
fs/ext4/extents.c +50 -38
196 lines not on this page · raw message
fs/ext4/fast_commit.c +4 -4
@@ -1828,12 +1828,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; }
fs/ext4/migrate.c +3 -2
@@ -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);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 5/6 ext4: get rid of ppath in ext4_split_extent_at()
In reply to Sasha LevinFrom: Baokun Li <[email protected]>
[ 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.
Stable-dep-of: 79b592e8f1b4 ("ext4: drop extent cache when splitting extent fails")
--- fs/ext4/extents.c | 85 ++++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 38 deletions(-)
fs/ext4/extents.c +47 -38
@@ -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;
@@ -3155,16 +3160,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;
@@ -3235,14 +3238,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.
@@ -3252,16 +3253,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 )) {
@@ -3313,10 +3312,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; }/*
@@ -3360,10 +3362,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); }
@@ -3371,7 +3377,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);
@@ -3393,13 +3399,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; }
@@ -5594,22 +5604,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);/*
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 6/6 ext4: drop extent cache when splitting extent fails
In reply to Sasha LevinFrom: Zhang Yi <[email protected]>
[ 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.
Message-ID: <[email protected]>
--- fs/ext4/extents.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
fs/ext4/extents.c +6 -2
@@ -3243,7 +3243,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.
@@ -3257,7 +3257,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;
@@ -3317,6 +3317,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; }
Signature · 1 line
2.51.0