Commit 29ad6bb3 authored by Peng Zhang's avatar Peng Zhang Committed by Andrew Morton
Browse files

maple_tree: fix allocation in mas_sparse_area()

In the case of reverse allocation, mas->index and mas->last do not point
to the correct allocation range, which will cause users to get incorrect
allocation results, so fix it.  If the user does not use it in a specific
way, this bug will not be triggered.

This is a bug, but only VMA uses it now, the way VMA is used now will
not trigger it.  There is a possibility that a user will trigger it in
the future.

Also re-check whether the size is still satisfied after the lower bound
was increased, which is a corner case and is incorrect in previous
versions.

Link: https://lkml.kernel.org/r/20230419093625.99201-1-zhangpeng.00@bytedance.com


Fixes: 54a611b6 ("Maple Tree: add new data structure")
Signed-off-by: default avatarPeng Zhang <zhangpeng.00@bytedance.com>
Cc: Liam R. Howlett <Liam.Howlett@Oracle.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 53156443
Loading
Loading
Loading
Loading
+20 −21
Original line number Diff line number Diff line
@@ -5250,25 +5250,28 @@ static inline void mas_fill_gap(struct ma_state *mas, void *entry,
 * @size: The size of the gap
 * @fwd: Searching forward or back
 */
static inline void mas_sparse_area(struct ma_state *mas, unsigned long min,
static inline int mas_sparse_area(struct ma_state *mas, unsigned long min,
				unsigned long max, unsigned long size, bool fwd)
{
	unsigned long start = 0;

	if (!unlikely(mas_is_none(mas)))
		start++;
	if (!unlikely(mas_is_none(mas)) && min == 0) {
		min++;
		/*
		 * At this time, min is increased, we need to recheck whether
		 * the size is satisfied.
		 */
		if (min > max || max - min + 1 < size)
			return -EBUSY;
	}
	/* mas_is_ptr */

	if (start < min)
		start = min;

	if (fwd) {
		mas->index = start;
		mas->last = start + size - 1;
		return;
		mas->index = min;
		mas->last = min + size - 1;
	} else {
		mas->last = max;
		mas->index = max - size + 1;
	}

	mas->index = max;
	return 0;
}

/*
@@ -5297,10 +5300,8 @@ int mas_empty_area(struct ma_state *mas, unsigned long min,
		return -EBUSY;

	/* Empty set */
	if (mas_is_none(mas) || mas_is_ptr(mas)) {
		mas_sparse_area(mas, min, max, size, true);
		return 0;
	}
	if (mas_is_none(mas) || mas_is_ptr(mas))
		return mas_sparse_area(mas, min, max, size, true);

	/* The start of the window can only be within these values */
	mas->index = min;
@@ -5356,10 +5357,8 @@ int mas_empty_area_rev(struct ma_state *mas, unsigned long min,
	}

	/* Empty set. */
	if (mas_is_none(mas) || mas_is_ptr(mas)) {
		mas_sparse_area(mas, min, max, size, false);
		return 0;
	}
	if (mas_is_none(mas) || mas_is_ptr(mas))
		return mas_sparse_area(mas, min, max, size, false);

	/* The start of the window can only be within these values. */
	mas->index = min;