@@ -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