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: SeongJae Park <sj@kernel.org>
Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Shakeel 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: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
SeongJae Park
2025-03-12 09:47:49 -07:00
committed by Andrew Morton
parent f4a578d345
commit 0a6ffacb3b

View File

@@ -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;
int error;
if (!is_valid_madvise(start, len_in, behavior)) {
ret = -EINVAL;
break;
}
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