* [PATCH 0/3] bugfix for insert/collapse fallocate
@ 2021-09-03 6:27 yangerkun
2021-09-03 6:27 ` [PATCH 1/3] ext4: correct the left/middle/right debug message for binsearch yangerkun
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: yangerkun @ 2021-09-03 6:27 UTC (permalink / raw)
To: tytso, jack; +Cc: linux-ext4, yangerkun, yukuai3
yangerkun (3):
ext4: correct the left/middle/right debug message for binsearch
ext4: ensure enough credits in ext4_ext_shift_path_extents
ext4: stop use path once restart journal in
ext4_ext_shift_path_extents
fs/ext4/extents.c | 77 ++++++++++++++++++++++-------------------------
1 file changed, 36 insertions(+), 41 deletions(-)
--
2.31.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/3] ext4: correct the left/middle/right debug message for binsearch
2021-09-03 6:27 [PATCH 0/3] bugfix for insert/collapse fallocate yangerkun
@ 2021-09-03 6:27 ` yangerkun
2021-09-30 16:10 ` Jan Kara
2021-09-03 6:27 ` [PATCH 2/3] ext4: ensure enough credits in ext4_ext_shift_path_extents yangerkun
` (3 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: yangerkun @ 2021-09-03 6:27 UTC (permalink / raw)
To: tytso, jack; +Cc: linux-ext4, yangerkun, yukuai3
The debuginfo for binsearch want to show the left/middle/right extent
while the process search for the goal block. However we show this info
after we change right or left.
Signed-off-by: yangerkun <yangerkun@huawei.com>
---
fs/ext4/extents.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index c33e0a2cb6c3..7ae32078b48f 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -713,13 +713,14 @@ ext4_ext_binsearch_idx(struct inode *inode,
r = EXT_LAST_INDEX(eh);
while (l <= r) {
m = l + (r - l) / 2;
+ ext_debug(inode, "%p(%u):%p(%u):%p(%u) ", l,
+ le32_to_cpu(l->ei_block), m, le32_to_cpu(m->ei_block),
+ r, le32_to_cpu(r->ei_block));
+
if (block < le32_to_cpu(m->ei_block))
r = m - 1;
else
l = m + 1;
- ext_debug(inode, "%p(%u):%p(%u):%p(%u) ", l,
- le32_to_cpu(l->ei_block), m, le32_to_cpu(m->ei_block),
- r, le32_to_cpu(r->ei_block));
}
path->p_idx = l - 1;
@@ -781,13 +782,14 @@ ext4_ext_binsearch(struct inode *inode,
while (l <= r) {
m = l + (r - l) / 2;
+ ext_debug(inode, "%p(%u):%p(%u):%p(%u) ", l,
+ le32_to_cpu(l->ee_block), m, le32_to_cpu(m->ee_block),
+ r, le32_to_cpu(r->ee_block));
+
if (block < le32_to_cpu(m->ee_block))
r = m - 1;
else
l = m + 1;
- ext_debug(inode, "%p(%u):%p(%u):%p(%u) ", l,
- le32_to_cpu(l->ee_block), m, le32_to_cpu(m->ee_block),
- r, le32_to_cpu(r->ee_block));
}
path->p_ext = l - 1;
--
2.31.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/3] ext4: ensure enough credits in ext4_ext_shift_path_extents
2021-09-03 6:27 [PATCH 0/3] bugfix for insert/collapse fallocate yangerkun
2021-09-03 6:27 ` [PATCH 1/3] ext4: correct the left/middle/right debug message for binsearch yangerkun
@ 2021-09-03 6:27 ` yangerkun
2021-09-30 16:21 ` Jan Kara
2021-09-03 6:27 ` [PATCH 3/3] ext4: stop use path once restart journal " yangerkun
` (2 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: yangerkun @ 2021-09-03 6:27 UTC (permalink / raw)
To: tytso, jack; +Cc: linux-ext4, yangerkun, yukuai3
Like ext4_ext_rm_leaf, we can ensure enough credits before every call
that will consume credits. This can remove ext4_access_path which only
used in ext4_ext_shift_path_extents. It's a prepare patch for the next
bugfix patch.
Signed-off-by: yangerkun <yangerkun@huawei.com>
---
fs/ext4/extents.c | 49 +++++++++++++++--------------------------------
1 file changed, 15 insertions(+), 34 deletions(-)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 7ae32078b48f..a6fb0350f062 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4974,36 +4974,6 @@ int ext4_get_es_cache(struct inode *inode, struct fiemap_extent_info *fieinfo,
return ext4_fill_es_cache_info(inode, start_blk, len_blks, fieinfo);
}
-/*
- * ext4_access_path:
- * Function to access the path buffer for marking it dirty.
- * It also checks if there are sufficient credits left in the journal handle
- * to update path.
- */
-static int
-ext4_access_path(handle_t *handle, struct inode *inode,
- struct ext4_ext_path *path)
-{
- int credits, err;
-
- if (!ext4_handle_valid(handle))
- return 0;
-
- /*
- * Check if need to extend journal credits
- * 3 for leaf, sb, and inode plus 2 (bmap and group
- * descriptor) for each block group; assume two block
- * groups
- */
- credits = ext4_writepage_trans_blocks(inode);
- err = ext4_datasem_ensure_credits(handle, inode, 7, credits, 0);
- if (err < 0)
- return err;
-
- err = ext4_ext_get_access(handle, inode, path);
- return err;
-}
-
/*
* ext4_ext_shift_path_extents:
* Shift the extents of a path structure lying between path[depth].p_ext
@@ -5018,6 +4988,7 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
int depth, err = 0;
struct ext4_extent *ex_start, *ex_last;
bool update = false;
+ int credits, restart_credits;
depth = path->p_depth;
while (depth >= 0) {
@@ -5027,13 +4998,23 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
return -EFSCORRUPTED;
ex_last = EXT_LAST_EXTENT(path[depth].p_hdr);
+ /* leaf + sb + inode */
+ credits = 3;
+ if (ex_start == EXT_FIRST_EXTENT(path[depth].p_hdr)) {
+ update = true;
+ /* extent tree + sb + inode */
+ credits = depth + 2;
+ }
- err = ext4_access_path(handle, inode, path + depth);
+ restart_credits = ext4_writepage_trans_blocks(inode);
+ err = ext4_datasem_ensure_credits(handle, inode, credits,
+ restart_credits, 0);
if (err)
goto out;
- if (ex_start == EXT_FIRST_EXTENT(path[depth].p_hdr))
- update = true;
+ err = ext4_ext_get_access(handle, inode, path + depth);
+ if (err)
+ goto out;
while (ex_start <= ex_last) {
if (SHIFT == SHIFT_LEFT) {
@@ -5064,7 +5045,7 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
}
/* Update index too */
- err = ext4_access_path(handle, inode, path + depth);
+ err = ext4_ext_get_access(handle, inode, path + depth);
if (err)
goto out;
--
2.31.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/3] ext4: stop use path once restart journal in ext4_ext_shift_path_extents
2021-09-03 6:27 [PATCH 0/3] bugfix for insert/collapse fallocate yangerkun
2021-09-03 6:27 ` [PATCH 1/3] ext4: correct the left/middle/right debug message for binsearch yangerkun
2021-09-03 6:27 ` [PATCH 2/3] ext4: ensure enough credits in ext4_ext_shift_path_extents yangerkun
@ 2021-09-03 6:27 ` yangerkun
2021-09-30 16:43 ` Jan Kara
2021-09-24 9:32 ` [PATCH 0/3] bugfix for insert/collapse fallocate yangerkun
2021-10-07 15:49 ` Theodore Ts'o
4 siblings, 1 reply; 10+ messages in thread
From: yangerkun @ 2021-09-03 6:27 UTC (permalink / raw)
To: tytso, jack; +Cc: linux-ext4, yangerkun, yukuai3
We get a BUG as follow:
[52117.465187] ------------[ cut here ]------------
[52117.465686] kernel BUG at fs/ext4/extents.c:1756!
...
[52117.478306] Call Trace:
[52117.478565] ext4_ext_shift_extents+0x3ee/0x710
[52117.479020] ext4_fallocate+0x139c/0x1b40
[52117.479405] ? __do_sys_newfstat+0x6b/0x80
[52117.479805] vfs_fallocate+0x151/0x4b0
[52117.480177] ksys_fallocate+0x4a/0xa0
[52117.480533] __x64_sys_fallocate+0x22/0x30
[52117.480930] do_syscall_64+0x35/0x80
[52117.481277] entry_SYSCALL_64_after_hwframe+0x44/0xae
[52117.481769] RIP: 0033:0x7fa062f855ca
static int ext4_ext_try_to_merge_right(struct inode *inode,
struct ext4_ext_path *path,
struct ext4_extent *ex)
{
struct ext4_extent_header *eh;
unsigned int depth, len;
int merge_done = 0, unwritten;
depth = ext_depth(inode);
BUG_ON(path[depth].p_hdr == NULL); <=== trigger here
eh = path[depth].p_hdr;
Normally, we protect extent tree with i_data_sem, and once we really
need drop i_data_sem, we should reload the ext4_ext_path array after we
recatch i_data_sem since extent tree may has changed, the 'again' in
ext4_ext_remove_space give us a sample. But the other case
ext4_ext_shift_path_extents seems forget to do this(ext4_access_path may
drop i_data_sem and recatch it with not enough credits), and will lead
the upper BUG when there is a parallel extents split which will grow the
extent tree.
Fix it by introduce the again in ext4_ext_shift_extents.
Signed-off-by: yangerkun <yangerkun@huawei.com>
---
fs/ext4/extents.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index a6fb0350f062..0aa14f6ca914 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -5009,8 +5009,11 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
restart_credits = ext4_writepage_trans_blocks(inode);
err = ext4_datasem_ensure_credits(handle, inode, credits,
restart_credits, 0);
- if (err)
+ if (err) {
+ if (err > 0)
+ err = -EAGAIN;
goto out;
+ }
err = ext4_ext_get_access(handle, inode, path + depth);
if (err)
@@ -5084,6 +5087,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
int ret = 0, depth;
struct ext4_extent *extent;
ext4_lblk_t stop, *iterator, ex_start, ex_end;
+ ext4_lblk_t tmp = EXT_MAX_BLOCKS;
/* Let path point to the last extent */
path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL,
@@ -5137,11 +5141,15 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
* till we reach stop. In case of right shift, iterator points to stop
* and it is decreased till we reach start.
*/
+again:
if (SHIFT == SHIFT_LEFT)
iterator = &start;
else
iterator = &stop;
+ if (tmp != EXT_MAX_BLOCKS)
+ *iterator = tmp;
+
/*
* Its safe to start updating extents. Start and stop are unsigned, so
* in case of right shift if extent with 0 block is reached, iterator
@@ -5170,6 +5178,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
}
}
+ tmp = *iterator;
if (SHIFT == SHIFT_LEFT) {
extent = EXT_LAST_EXTENT(path[depth].p_hdr);
*iterator = le32_to_cpu(extent->ee_block) +
@@ -5188,6 +5197,9 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
}
ret = ext4_ext_shift_path_extents(path, shift, inode,
handle, SHIFT);
+ /* iterator can be NULL which means we should break */
+ if (ret == -EAGAIN)
+ goto again;
if (ret)
break;
}
--
2.31.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 0/3] bugfix for insert/collapse fallocate
2021-09-03 6:27 [PATCH 0/3] bugfix for insert/collapse fallocate yangerkun
` (2 preceding siblings ...)
2021-09-03 6:27 ` [PATCH 3/3] ext4: stop use path once restart journal " yangerkun
@ 2021-09-24 9:32 ` yangerkun
2021-10-07 15:49 ` Theodore Ts'o
4 siblings, 0 replies; 10+ messages in thread
From: yangerkun @ 2021-09-24 9:32 UTC (permalink / raw)
To: tytso, jack; +Cc: linux-ext4, yukuai3
gently ping...
在 2021/9/3 14:27, yangerkun 写道:
> yangerkun (3):
> ext4: correct the left/middle/right debug message for binsearch
> ext4: ensure enough credits in ext4_ext_shift_path_extents
> ext4: stop use path once restart journal in
> ext4_ext_shift_path_extents
>
> fs/ext4/extents.c | 77 ++++++++++++++++++++++-------------------------
> 1 file changed, 36 insertions(+), 41 deletions(-)
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/3] ext4: correct the left/middle/right debug message for binsearch
2021-09-03 6:27 ` [PATCH 1/3] ext4: correct the left/middle/right debug message for binsearch yangerkun
@ 2021-09-30 16:10 ` Jan Kara
0 siblings, 0 replies; 10+ messages in thread
From: Jan Kara @ 2021-09-30 16:10 UTC (permalink / raw)
To: yangerkun; +Cc: tytso, jack, linux-ext4, yukuai3
On Fri 03-09-21 14:27:46, yangerkun wrote:
> The debuginfo for binsearch want to show the left/middle/right extent
> while the process search for the goal block. However we show this info
> after we change right or left.
>
> Signed-off-by: yangerkun <yangerkun@huawei.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> fs/ext4/extents.c | 14 ++++++++------
> 1 file changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> index c33e0a2cb6c3..7ae32078b48f 100644
> --- a/fs/ext4/extents.c
> +++ b/fs/ext4/extents.c
> @@ -713,13 +713,14 @@ ext4_ext_binsearch_idx(struct inode *inode,
> r = EXT_LAST_INDEX(eh);
> while (l <= r) {
> m = l + (r - l) / 2;
> + ext_debug(inode, "%p(%u):%p(%u):%p(%u) ", l,
> + le32_to_cpu(l->ei_block), m, le32_to_cpu(m->ei_block),
> + r, le32_to_cpu(r->ei_block));
> +
> if (block < le32_to_cpu(m->ei_block))
> r = m - 1;
> else
> l = m + 1;
> - ext_debug(inode, "%p(%u):%p(%u):%p(%u) ", l,
> - le32_to_cpu(l->ei_block), m, le32_to_cpu(m->ei_block),
> - r, le32_to_cpu(r->ei_block));
> }
>
> path->p_idx = l - 1;
> @@ -781,13 +782,14 @@ ext4_ext_binsearch(struct inode *inode,
>
> while (l <= r) {
> m = l + (r - l) / 2;
> + ext_debug(inode, "%p(%u):%p(%u):%p(%u) ", l,
> + le32_to_cpu(l->ee_block), m, le32_to_cpu(m->ee_block),
> + r, le32_to_cpu(r->ee_block));
> +
> if (block < le32_to_cpu(m->ee_block))
> r = m - 1;
> else
> l = m + 1;
> - ext_debug(inode, "%p(%u):%p(%u):%p(%u) ", l,
> - le32_to_cpu(l->ee_block), m, le32_to_cpu(m->ee_block),
> - r, le32_to_cpu(r->ee_block));
> }
>
> path->p_ext = l - 1;
> --
> 2.31.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/3] ext4: ensure enough credits in ext4_ext_shift_path_extents
2021-09-03 6:27 ` [PATCH 2/3] ext4: ensure enough credits in ext4_ext_shift_path_extents yangerkun
@ 2021-09-30 16:21 ` Jan Kara
0 siblings, 0 replies; 10+ messages in thread
From: Jan Kara @ 2021-09-30 16:21 UTC (permalink / raw)
To: yangerkun; +Cc: tytso, jack, linux-ext4, yukuai3
On Fri 03-09-21 14:27:47, yangerkun wrote:
> Like ext4_ext_rm_leaf, we can ensure enough credits before every call
> that will consume credits. This can remove ext4_access_path which only
> used in ext4_ext_shift_path_extents. It's a prepare patch for the next
> bugfix patch.
>
> Signed-off-by: yangerkun <yangerkun@huawei.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> fs/ext4/extents.c | 49 +++++++++++++++--------------------------------
> 1 file changed, 15 insertions(+), 34 deletions(-)
>
> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> index 7ae32078b48f..a6fb0350f062 100644
> --- a/fs/ext4/extents.c
> +++ b/fs/ext4/extents.c
> @@ -4974,36 +4974,6 @@ int ext4_get_es_cache(struct inode *inode, struct fiemap_extent_info *fieinfo,
> return ext4_fill_es_cache_info(inode, start_blk, len_blks, fieinfo);
> }
>
> -/*
> - * ext4_access_path:
> - * Function to access the path buffer for marking it dirty.
> - * It also checks if there are sufficient credits left in the journal handle
> - * to update path.
> - */
> -static int
> -ext4_access_path(handle_t *handle, struct inode *inode,
> - struct ext4_ext_path *path)
> -{
> - int credits, err;
> -
> - if (!ext4_handle_valid(handle))
> - return 0;
> -
> - /*
> - * Check if need to extend journal credits
> - * 3 for leaf, sb, and inode plus 2 (bmap and group
> - * descriptor) for each block group; assume two block
> - * groups
> - */
> - credits = ext4_writepage_trans_blocks(inode);
> - err = ext4_datasem_ensure_credits(handle, inode, 7, credits, 0);
> - if (err < 0)
> - return err;
> -
> - err = ext4_ext_get_access(handle, inode, path);
> - return err;
> -}
> -
> /*
> * ext4_ext_shift_path_extents:
> * Shift the extents of a path structure lying between path[depth].p_ext
> @@ -5018,6 +4988,7 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
> int depth, err = 0;
> struct ext4_extent *ex_start, *ex_last;
> bool update = false;
> + int credits, restart_credits;
> depth = path->p_depth;
>
> while (depth >= 0) {
> @@ -5027,13 +4998,23 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
> return -EFSCORRUPTED;
>
> ex_last = EXT_LAST_EXTENT(path[depth].p_hdr);
> + /* leaf + sb + inode */
> + credits = 3;
> + if (ex_start == EXT_FIRST_EXTENT(path[depth].p_hdr)) {
> + update = true;
> + /* extent tree + sb + inode */
> + credits = depth + 2;
> + }
>
> - err = ext4_access_path(handle, inode, path + depth);
> + restart_credits = ext4_writepage_trans_blocks(inode);
> + err = ext4_datasem_ensure_credits(handle, inode, credits,
> + restart_credits, 0);
> if (err)
> goto out;
>
> - if (ex_start == EXT_FIRST_EXTENT(path[depth].p_hdr))
> - update = true;
> + err = ext4_ext_get_access(handle, inode, path + depth);
> + if (err)
> + goto out;
>
> while (ex_start <= ex_last) {
> if (SHIFT == SHIFT_LEFT) {
> @@ -5064,7 +5045,7 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
> }
>
> /* Update index too */
> - err = ext4_access_path(handle, inode, path + depth);
> + err = ext4_ext_get_access(handle, inode, path + depth);
> if (err)
> goto out;
>
> --
> 2.31.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] ext4: stop use path once restart journal in ext4_ext_shift_path_extents
2021-09-03 6:27 ` [PATCH 3/3] ext4: stop use path once restart journal " yangerkun
@ 2021-09-30 16:43 ` Jan Kara
2021-10-08 2:04 ` yangerkun
0 siblings, 1 reply; 10+ messages in thread
From: Jan Kara @ 2021-09-30 16:43 UTC (permalink / raw)
To: yangerkun; +Cc: tytso, jack, linux-ext4, yukuai3
Let me improve English a bit:
On Fri 03-09-21 14:27:48, yangerkun wrote:
> We get a BUG as follow:
We hit the following bug:
>
> [52117.465187] ------------[ cut here ]------------
> [52117.465686] kernel BUG at fs/ext4/extents.c:1756!
> ...
> [52117.478306] Call Trace:
> [52117.478565] ext4_ext_shift_extents+0x3ee/0x710
> [52117.479020] ext4_fallocate+0x139c/0x1b40
> [52117.479405] ? __do_sys_newfstat+0x6b/0x80
> [52117.479805] vfs_fallocate+0x151/0x4b0
> [52117.480177] ksys_fallocate+0x4a/0xa0
> [52117.480533] __x64_sys_fallocate+0x22/0x30
> [52117.480930] do_syscall_64+0x35/0x80
> [52117.481277] entry_SYSCALL_64_after_hwframe+0x44/0xae
> [52117.481769] RIP: 0033:0x7fa062f855ca
>
> static int ext4_ext_try_to_merge_right(struct inode *inode,
> struct ext4_ext_path *path,
> struct ext4_extent *ex)
> {
> struct ext4_extent_header *eh;
> unsigned int depth, len;
> int merge_done = 0, unwritten;
>
> depth = ext_depth(inode);
> BUG_ON(path[depth].p_hdr == NULL); <=== trigger here
> eh = path[depth].p_hdr;
>
> Normally, we protect extent tree with i_data_sem, and once we really
> need drop i_data_sem, we should reload the ext4_ext_path array after we
> recatch i_data_sem since extent tree may has changed, the 'again' in
> ext4_ext_remove_space give us a sample. But the other case
> ext4_ext_shift_path_extents seems forget to do this(ext4_access_path may
> drop i_data_sem and recatch it with not enough credits), and will lead
> the upper BUG when there is a parallel extents split which will grow the
> extent tree.
Normally, the extent tree is protected by i_data_sem and if we drop
i_data_sem in ext4_datasem_ensure_credits(), we need to reload
ext4_ext_path array after reacquiring i_data_sem since the extent tree may
have changed. The 'again' label in ext4_ext_remove_space() is an example of
this. But ext4_ext_shift_path_extents() forgets to reload ext4_ext_path and
thus can cause the above mentioned BUG when there is a parallel extents
split which will grow the extent tree.
>
> Fix it by introduce the again in ext4_ext_shift_extents.
>
> Signed-off-by: yangerkun <yangerkun@huawei.com>
> ---
> fs/ext4/extents.c | 14 +++++++++++++-
> 1 file changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> index a6fb0350f062..0aa14f6ca914 100644
> --- a/fs/ext4/extents.c
> +++ b/fs/ext4/extents.c
> @@ -5009,8 +5009,11 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
> restart_credits = ext4_writepage_trans_blocks(inode);
> err = ext4_datasem_ensure_credits(handle, inode, credits,
> restart_credits, 0);
> - if (err)
> + if (err) {
> + if (err > 0)
> + err = -EAGAIN;
> goto out;
> + }
Hum, I'd note that the previous patch actually broke
ext4_ext_shift_path_extents() which could return 1 after patch 2/3 and
probably confuse code upwards in the stack and now you fix it up in this
patch. Can you perhaps fixup the previous patch by changing the condition
to:
if (err < 0)
and then change it here?
>
> err = ext4_ext_get_access(handle, inode, path + depth);
> if (err)
> @@ -5084,6 +5087,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
> int ret = 0, depth;
> struct ext4_extent *extent;
> ext4_lblk_t stop, *iterator, ex_start, ex_end;
> + ext4_lblk_t tmp = EXT_MAX_BLOCKS;
Can you perhaps name this more descriptively than 'tmp'? Something like
restart_lblk or something like that?
> /* Let path point to the last extent */
> path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL,
> @@ -5137,11 +5141,15 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
> * till we reach stop. In case of right shift, iterator points to stop
> * and it is decreased till we reach start.
> */
> +again:
> if (SHIFT == SHIFT_LEFT)
> iterator = &start;
> else
> iterator = &stop;
>
> + if (tmp != EXT_MAX_BLOCKS)
> + *iterator = tmp;
> +
> /*
> * Its safe to start updating extents. Start and stop are unsigned, so
> * in case of right shift if extent with 0 block is reached, iterator
> @@ -5170,6 +5178,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
> }
> }
>
> + tmp = *iterator;
> if (SHIFT == SHIFT_LEFT) {
> extent = EXT_LAST_EXTENT(path[depth].p_hdr);
> *iterator = le32_to_cpu(extent->ee_block) +
> @@ -5188,6 +5197,9 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
> }
> ret = ext4_ext_shift_path_extents(path, shift, inode,
> handle, SHIFT);
> + /* iterator can be NULL which means we should break */
> + if (ret == -EAGAIN)
> + goto again;
Hum, but while we dropped i_data_sem, the extent depth may have increased
so we may need larger 'path' now?
Otherwise the patch looks good.
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 0/3] bugfix for insert/collapse fallocate
2021-09-03 6:27 [PATCH 0/3] bugfix for insert/collapse fallocate yangerkun
` (3 preceding siblings ...)
2021-09-24 9:32 ` [PATCH 0/3] bugfix for insert/collapse fallocate yangerkun
@ 2021-10-07 15:49 ` Theodore Ts'o
4 siblings, 0 replies; 10+ messages in thread
From: Theodore Ts'o @ 2021-10-07 15:49 UTC (permalink / raw)
To: yangerkun, jack; +Cc: Theodore Ts'o, yukuai3, linux-ext4
On Fri, 3 Sep 2021 14:27:45 +0800, yangerkun wrote:
> yangerkun (3):
> ext4: correct the left/middle/right debug message for binsearch
> ext4: ensure enough credits in ext4_ext_shift_path_extents
> ext4: stop use path once restart journal in
> ext4_ext_shift_path_extents
>
> fs/ext4/extents.c | 77 ++++++++++++++++++++++-------------------------
> 1 file changed, 36 insertions(+), 41 deletions(-)
>
> [...]
Applied, thanks!
[1/3] ext4: correct the left/middle/right debug message for binsearch
commit: 189487c02b3865c35be3ced27ebc33f7bfe86220
[2/3] ext4: ensure enough credits in ext4_ext_shift_path_extents
commit: 42c018ecf2bcf37c21476942bb96662fad7133c0
[3/3] ext4: stop use path once restart journal in ext4_ext_shift_path_extents
commit: d56aaa1fa17ff4b45383c8beb36bb6a1cf835e22
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] ext4: stop use path once restart journal in ext4_ext_shift_path_extents
2021-09-30 16:43 ` Jan Kara
@ 2021-10-08 2:04 ` yangerkun
0 siblings, 0 replies; 10+ messages in thread
From: yangerkun @ 2021-10-08 2:04 UTC (permalink / raw)
To: Jan Kara; +Cc: tytso, linux-ext4, yukuai3
在 2021/10/1 0:43, Jan Kara 写道:
> Let me improve English a bit:
>
> On Fri 03-09-21 14:27:48, yangerkun wrote:
>> We get a BUG as follow:
>
> We hit the following bug:
>
>>
>> [52117.465187] ------------[ cut here ]------------
>> [52117.465686] kernel BUG at fs/ext4/extents.c:1756!
>> ...
>> [52117.478306] Call Trace:
>> [52117.478565] ext4_ext_shift_extents+0x3ee/0x710
>> [52117.479020] ext4_fallocate+0x139c/0x1b40
>> [52117.479405] ? __do_sys_newfstat+0x6b/0x80
>> [52117.479805] vfs_fallocate+0x151/0x4b0
>> [52117.480177] ksys_fallocate+0x4a/0xa0
>> [52117.480533] __x64_sys_fallocate+0x22/0x30
>> [52117.480930] do_syscall_64+0x35/0x80
>> [52117.481277] entry_SYSCALL_64_after_hwframe+0x44/0xae
>> [52117.481769] RIP: 0033:0x7fa062f855ca
>>
>> static int ext4_ext_try_to_merge_right(struct inode *inode,
>> struct ext4_ext_path *path,
>> struct ext4_extent *ex)
>> {
>> struct ext4_extent_header *eh;
>> unsigned int depth, len;
>> int merge_done = 0, unwritten;
>>
>> depth = ext_depth(inode);
>> BUG_ON(path[depth].p_hdr == NULL); <=== trigger here
>> eh = path[depth].p_hdr;
>>
>> Normally, we protect extent tree with i_data_sem, and once we really
>> need drop i_data_sem, we should reload the ext4_ext_path array after we
>> recatch i_data_sem since extent tree may has changed, the 'again' in
>> ext4_ext_remove_space give us a sample. But the other case
>> ext4_ext_shift_path_extents seems forget to do this(ext4_access_path may
>> drop i_data_sem and recatch it with not enough credits), and will lead
>> the upper BUG when there is a parallel extents split which will grow the
>> extent tree.
>
> Normally, the extent tree is protected by i_data_sem and if we drop
> i_data_sem in ext4_datasem_ensure_credits(), we need to reload
> ext4_ext_path array after reacquiring i_data_sem since the extent tree may
> have changed. The 'again' label in ext4_ext_remove_space() is an example of
> this. But ext4_ext_shift_path_extents() forgets to reload ext4_ext_path and
> thus can cause the above mentioned BUG when there is a parallel extents
> split which will grow the extent tree.
>
>>
>> Fix it by introduce the again in ext4_ext_shift_extents.
>>
>> Signed-off-by: yangerkun <yangerkun@huawei.com>
>> ---
>> fs/ext4/extents.c | 14 +++++++++++++-
>> 1 file changed, 13 insertions(+), 1 deletion(-)
>>
>> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
>> index a6fb0350f062..0aa14f6ca914 100644
>> --- a/fs/ext4/extents.c
>> +++ b/fs/ext4/extents.c
>> @@ -5009,8 +5009,11 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
>> restart_credits = ext4_writepage_trans_blocks(inode);
>> err = ext4_datasem_ensure_credits(handle, inode, credits,
>> restart_credits, 0);
>> - if (err)
>> + if (err) {
>> + if (err > 0)
>> + err = -EAGAIN;
>> goto out;
>> + }
>
> Hum, I'd note that the previous patch actually broke
> ext4_ext_shift_path_extents() which could return 1 after patch 2/3 and
> probably confuse code upwards in the stack and now you fix it up in this
> patch. Can you perhaps fixup the previous patch by changing the condition
> to:
> if (err < 0)
>
> and then change it here?
Thanks for your review! Ted has fix this by add some comments in patch 2/3!
>
>>
>> err = ext4_ext_get_access(handle, inode, path + depth);
>> if (err)
>> @@ -5084,6 +5087,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
>> int ret = 0, depth;
>> struct ext4_extent *extent;
>> ext4_lblk_t stop, *iterator, ex_start, ex_end;
>> + ext4_lblk_t tmp = EXT_MAX_BLOCKS;
>
> Can you perhaps name this more descriptively than 'tmp'? Something like
> restart_lblk or something like that?
Agree. I'll pay attention next time!
>
>> /* Let path point to the last extent */
>> path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL,
>> @@ -5137,11 +5141,15 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
>> * till we reach stop. In case of right shift, iterator points to stop
>> * and it is decreased till we reach start.
>> */
>> +again:
>> if (SHIFT == SHIFT_LEFT)
>> iterator = &start;
>> else
>> iterator = &stop;
>>
>> + if (tmp != EXT_MAX_BLOCKS)
>> + *iterator = tmp;
>> +
>> /*
>> * Its safe to start updating extents. Start and stop are unsigned, so
>> * in case of right shift if extent with 0 block is reached, iterator
>> @@ -5170,6 +5178,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
>> }
>> }
>>
>> + tmp = *iterator;
>> if (SHIFT == SHIFT_LEFT) {
>> extent = EXT_LAST_EXTENT(path[depth].p_hdr);
>> *iterator = le32_to_cpu(extent->ee_block) +
>> @@ -5188,6 +5197,9 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
>> }
>> ret = ext4_ext_shift_path_extents(path, shift, inode,
>> handle, SHIFT);
>> + /* iterator can be NULL which means we should break */
>> + if (ret == -EAGAIN)
>> + goto again;
>
> Hum, but while we dropped i_data_sem, the extent depth may have increased
> so we may need larger 'path' now?
>
> Otherwise the patch looks good.
The ext4_find_extent in ext4_ext_shift_extents can handle this case. It
seems OK.
>
> Honza
>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2021-10-08 2:05 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-03 6:27 [PATCH 0/3] bugfix for insert/collapse fallocate yangerkun
2021-09-03 6:27 ` [PATCH 1/3] ext4: correct the left/middle/right debug message for binsearch yangerkun
2021-09-30 16:10 ` Jan Kara
2021-09-03 6:27 ` [PATCH 2/3] ext4: ensure enough credits in ext4_ext_shift_path_extents yangerkun
2021-09-30 16:21 ` Jan Kara
2021-09-03 6:27 ` [PATCH 3/3] ext4: stop use path once restart journal " yangerkun
2021-09-30 16:43 ` Jan Kara
2021-10-08 2:04 ` yangerkun
2021-09-24 9:32 ` [PATCH 0/3] bugfix for insert/collapse fallocate yangerkun
2021-10-07 15:49 ` Theodore Ts'o
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.