[PATCH] maple_tree: reload mas before the second call for mas_empty_area

Liam R. Howlett Liam.Howlett at oracle.com
Mon Dec 16 09:29:37 PST 2024


* Yang Erkun <yangerkun at huaweicloud.com> [241214 04:34]:
> From: Yang Erkun <yangerkun at huawei.com>
> 
> Change the LONG_MAX in simple_offset_add to 1024, and do latter:
> 
> [root at fedora ~]# mkdir /tmp/dir
> [root at fedora ~]# for i in {1..1024}; do touch /tmp/dir/$i; done
> touch: cannot touch '/tmp/dir/1024': Device or resource busy
> [root at fedora ~]# rm /tmp/dir/123
> [root at fedora ~]# touch /tmp/dir/1024
> [root at fedora ~]# rm /tmp/dir/100
> [root at fedora ~]# touch /tmp/dir/1025
> touch: cannot touch '/tmp/dir/1025': Device or resource busy
> 
> After we delete file 100, actually this is a empty entry, but the latter
> create failed unexpected.
> 
> mas_alloc_cyclic has two chance to find empty entry. First find the
> entry with range range_lo and range_hi, if no empty entry exist, and
> range_lo > min, retry find with range min and range_hi. However, the
> first call mas_empty_area may mark mas as EBUSY, and the second call for
> mas_empty_area will return false directly. Fix this by reload mas before
> second call for mas_empty_area.

I have test cases and would like to add this as one for the
mas_alloc_cyclic() call so that we don't re-introduce this issue later.

I think this will be different than the actual roll-over as the next
entry won't be 0 and set the correct flag to detect a wrapping event.

It will allow for testing of the issue you found, just not a true
wrapping around.  I'm working on reproducing this failure so I can have
a test case.  I think we probably need a true wrapping test case too.

> 
> Fixes: 9b6713cc7522 ("maple_tree: Add mtree_alloc_cyclic()")
> Signed-off-by: Yang Erkun <yangerkun at huawei.com>
> ---
>  lib/maple_tree.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/lib/maple_tree.c b/lib/maple_tree.c
> index d0ae808f3a14..1fd02f4a05e6 100644
> --- a/lib/maple_tree.c
> +++ b/lib/maple_tree.c
> @@ -4346,6 +4346,7 @@ int mas_alloc_cyclic(struct ma_state *mas, unsigned long *startp,
>  {
>  	unsigned long min = range_lo;
>  	int ret = 0;
> +	struct ma_state m = *mas;
>  
>  	range_lo = max(min, *next);
>  	ret = mas_empty_area(mas, range_lo, range_hi, 1);
> @@ -4354,6 +4355,7 @@ int mas_alloc_cyclic(struct ma_state *mas, unsigned long *startp,
>  		ret = 1;
>  	}
>  	if (ret < 0 && range_lo > min) {
> +		*mas = m;

You want mas_reset(mas);
The copy of the state is not necessary.

On inspection, the comment on this function seems a bit incorrect in
that it's saying -EBUSY is the only other potential return - but it
could also be -EINVAL (although I don't think the libfs code will ever
hit this).

I'm also not sure mas_destroy() is necessary.

>  		ret = mas_empty_area(mas, min, range_hi, 1);
>  		if (ret == 0)
>  			ret = 1;
> -- 
> 2.39.2
> 
> 
> -- 
> maple-tree mailing list
> maple-tree at lists.infradead.org
> https://lists.infradead.org/mailman/listinfo/maple-tree



More information about the maple-tree mailing list