Commit 0a6ffacb authored by SeongJae Park's avatar SeongJae Park Committed by Andrew Morton
Browse files

mm/madvise: deduplicate madvise_do_behavior() skip case handlings

The logic for checking if a given madvise() request for a single memory
range can skip real work, namely madvise_do_behavior(), is duplicated in
do_madvise() and vector_madvise().  Split out the logic to a function and
reuse it.

Link: https://lkml.kernel.org/r/20250312164750.59215-4-sj@kernel.org


Signed-off-by: default avatarSeongJae Park <sj@kernel.org>
Reviewed-by: default avatarLorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: default avatarShakeel Butt <shakeel.butt@linux.dev>
Cc: David Hildenbrand <david@redhat.com>
Cc: Liam R. Howlett <howlett@gmail.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent f4a578d3
Loading
Loading
Loading
Loading
+34 −23
Original line number Diff line number Diff line
@@ -1640,6 +1640,31 @@ static bool is_valid_madvise(unsigned long start, size_t len_in, int behavior)
	return true;
}

/*
 * madvise_should_skip() - Return if the request is invalid or nothing.
 * @start:	Start address of madvise-requested address range.
 * @len_in:	Length of madvise-requested address range.
 * @behavior:	Requested madvise behavor.
 * @err:	Pointer to store an error code from the check.
 *
 * If the specified behaviour is invalid or nothing would occur, we skip the
 * operation.  This function returns true in the cases, otherwise false.  In
 * the former case we store an error on @err.
 */
static bool madvise_should_skip(unsigned long start, size_t len_in,
		int behavior, int *err)
{
	if (!is_valid_madvise(start, len_in, behavior)) {
		*err = -EINVAL;
		return true;
	}
	if (start + PAGE_ALIGN(len_in) == start) {
		*err = 0;
		return true;
	}
	return false;
}

static bool is_madvise_populate(int behavior)
{
	switch (behavior) {
@@ -1747,23 +1772,15 @@ static int madvise_do_behavior(struct mm_struct *mm,
 */
int do_madvise(struct mm_struct *mm, unsigned long start, size_t len_in, int behavior)
{
	unsigned long end;
	int error;
	size_t len;

	if (!is_valid_madvise(start, len_in, behavior))
		return -EINVAL;

	len = PAGE_ALIGN(len_in);
	end = start + len;

	if (end == start)
		return 0;

	if (madvise_should_skip(start, len_in, behavior, &error))
		return error;
	error = madvise_lock(mm, behavior);
	if (error)
		return error;
	error = madvise_do_behavior(mm, start, len_in, len, behavior);
	error = madvise_do_behavior(mm, start, len_in, PAGE_ALIGN(len_in),
			behavior);
	madvise_unlock(mm, behavior);

	return error;
@@ -1790,19 +1807,13 @@ static ssize_t vector_madvise(struct mm_struct *mm, struct iov_iter *iter,
	while (iov_iter_count(iter)) {
		unsigned long start = (unsigned long)iter_iov_addr(iter);
		size_t len_in = iter_iov_len(iter);
		size_t len;

		if (!is_valid_madvise(start, len_in, behavior)) {
			ret = -EINVAL;
			break;
		}
		int error;

		len = PAGE_ALIGN(len_in);
		if (start + len == start)
			ret = 0;
		if (madvise_should_skip(start, len_in, behavior, &error))
			ret = error;
		else
			ret = madvise_do_behavior(mm, start, len_in, len,
					behavior);
			ret = madvise_do_behavior(mm, start, len_in,
					PAGE_ALIGN(len_in), behavior);
		/*
		 * An madvise operation is attempting to restart the syscall,
		 * but we cannot proceed as it would not be correct to repeat