From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4E809C71157 for ; Sat, 21 Jun 2025 11:11:04 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 423606B007B; Sat, 21 Jun 2025 07:11:03 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 3CDE46B0088; Sat, 21 Jun 2025 07:11:03 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 2BC3C6B0089; Sat, 21 Jun 2025 07:11:03 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id 0F9E86B007B for ; Sat, 21 Jun 2025 07:11:03 -0400 (EDT) Received: from smtpin26.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 76294140188 for ; Sat, 21 Jun 2025 11:11:02 +0000 (UTC) X-FDA: 83579140764.26.482C24C Received: from mail-vk1-f172.google.com (mail-vk1-f172.google.com [209.85.221.172]) by imf22.hostedemail.com (Postfix) with ESMTP id 84E5BC0017 for ; Sat, 21 Jun 2025 11:11:00 +0000 (UTC) Authentication-Results: imf22.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=BkmyJ24O; spf=pass (imf22.hostedemail.com: domain of lianux.mm@gmail.com designates 209.85.221.172 as permitted sender) smtp.mailfrom=lianux.mm@gmail.com; dmarc=pass (policy=none) header.from=gmail.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1750504260; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding:in-reply-to: references:dkim-signature; bh=t0ICuNEN8hjCmp3yEDqV1SWJn5vIvC/Zw9u6hMgL0ho=; b=N5isP2MNiH7t65HW/vOsPcAWiECAwhM9S3jYmGccLDcJ+Hdv2mnV7l81fGoRbXaeE+CRdg aLsHDN93VSa8iJyxk6Z5TSe+zwtOdCZS+D6w8q2tONAY13s8oU4iwtI2UXgmTcrEYlVq+I xS2gkeQWg//nRMII27LHtjhhazCg3pQ= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1750504260; a=rsa-sha256; cv=none; b=ts5txR2lRoPji/4GKK/4O/oB5kpzUwzu/KK/8YYa8Pwthbamhm2cQAq135YucEl+nr26P1 UVisQyd2DOpMiBfNkh6wPV3Z31gehSu9bDI3rpM0fUl3Dcj9CVJ4VO6Mm3okazXfDxOv0m E+A7tKspZUa9ei5iN3PMPwfr+YxwFbw= ARC-Authentication-Results: i=1; imf22.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=BkmyJ24O; spf=pass (imf22.hostedemail.com: domain of lianux.mm@gmail.com designates 209.85.221.172 as permitted sender) smtp.mailfrom=lianux.mm@gmail.com; dmarc=pass (policy=none) header.from=gmail.com Received: by mail-vk1-f172.google.com with SMTP id 71dfb90a1353d-531426c7139so776914e0c.2 for ; Sat, 21 Jun 2025 04:11:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1750504259; x=1751109059; darn=kvack.org; h=cc:to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=t0ICuNEN8hjCmp3yEDqV1SWJn5vIvC/Zw9u6hMgL0ho=; b=BkmyJ24Oca90pT8ExTzMbtzTzBYxrrmI0kl9RjWvywUetXTnkyoMP4NIF0Y1EEdW6y C0p2xLt2jgdESPRQ3TeUhtfYekczOG/TCHqS3173/3WLF6O8fJatez5dM+8eQyu9X7Dy lyHooi8T8P4luYRnxzxwTHzDGnn1I4RBtPBjwcmxout++ZUbFcklUrl5beprtJ6z0FC2 uHxMlfQVCM424qHIOuEIyibVk/cwTGZuE/uv+yGj1jGSLN3cnSCosqewxL8Q7PxJh3Oi rHVYxr0tZnx45nLZT1Ud2DvC21GRaNPR0rNLQBArBfWBkT2ruH2xikLRN8QaPUumJsjh jJHw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750504259; x=1751109059; h=cc:to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=t0ICuNEN8hjCmp3yEDqV1SWJn5vIvC/Zw9u6hMgL0ho=; b=JD77i8uBVaJ2agNlAgrZ0d1JMz9ZKgFItmATNanrJMgHyf4zPyUjpTvGCCS0lcy+Zc qiHCtWsrEETyTHuxUdktbX3FR6WJcuMA8Rb2uXopYEas5w+m03xH/s2SkglfRr4DdeBc n07+/WptGj7Hrg8oLlursQqQiK/f5Ma/m5HkDrSTgnFf/DOsAe7rASlRBMD0iFaayFNC gmQ6U7p3wVlH+mOzomQOH8w3nDJnRQTevT9s64I2gfJ5vokHM2MwXV2lIHuehkU1niTF mhsc7DaF40NG7EWS9W8S5Go4Iu/c2B1ueR3nmj6jD9ytPpG3XiXOeSEtXvVvxHj+HRx7 al/w== X-Forwarded-Encrypted: i=1; AJvYcCVqY5IX5w47DY/4TqcK85rOshKnDqeY1PrcQVf1f1T/aMYpwV38MTgk/qXVnkKOo6VeEp88+yo/Zg==@kvack.org X-Gm-Message-State: AOJu0YyXlmioikFzmw2ms7YIRniiqdu8O0eerVssmfCiUE6ufWLpFIIv GQwZ4uDzqzKqDSKVcOISkOwO6LbdfaR6wEjfLyGTMVO1VqoBC4Jn1eKMapSSgHMQXhyg/KGw7kg XrMhl4UlNUaIviEvcqUkiIRCz/i0L/U4= X-Gm-Gg: ASbGncvzJhuJSnkuZz7gNLAozHdYdVK0q+70yPLXh14whbfC2puOXtH4k4dZxb7DFiw MPsp3UmVSRg5sPU4JwIMuecIng31nvQ7RrAIlWgJfSPfGGnMgTI3XCVtmju72i992zGG3uydFPn sW/Mt/KX0U9m0LrIRxux7SkafRf3j/sFWQqNRo3aXWKD43ThydRs60Z/RJ X-Google-Smtp-Source: AGHT+IG/yzClFWlImwkDtN4tzxx3g46N98129wxTW7MsYAG3FvOgPIrIiGhzR1PwfyIyd1Eo8hgmuQzhMr0FvEl+tZA= X-Received: by 2002:a05:6122:d11:b0:526:720:704 with SMTP id 71dfb90a1353d-531ad75f125mr3890202e0c.7.1750504259361; Sat, 21 Jun 2025 04:10:59 -0700 (PDT) MIME-Version: 1.0 From: wang lian Date: Sat, 21 Jun 2025 19:10:52 +0800 X-Gm-Features: AX0GCFtaY3coLITmVAl2HFLvuQfD0tJup1Co6hI_HlNKx6EATYBt3thoQrPkVJ0 Message-ID: Subject: Subject: [PATCH] selftests/mm: add test for (BATCH_PROCESS)MADV_DONTNEED To: Andrew Morton , Shuah Khan Cc: Christian Brauner , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, SeongJae Park , zijing.zhang@proton.me, ryncsn@gmail.com, gkwang@linx-info.com Content-Type: multipart/alternative; boundary="0000000000008e9e5f0638130849" X-Rspamd-Server: rspam03 X-Stat-Signature: 56jzz7knud4o7hd5pxtebdm5hcoqzijn X-Rspam-User: X-Rspamd-Queue-Id: 84E5BC0017 X-HE-Tag: 1750504260-130000 X-HE-Meta: U2FsdGVkX18NiYBhdOCueHGck5SsjJN/WMeR9BAdZ258Bn9sI1wiGlsO0zj1e0qLl05+2BDiuZ1kXlQVoaWYUoUrxn9fXfdByw/HtDoXCCxK4jswbfExbVLZSGoFj2/aIHKm+XAv552dhD/hYwP0IOf6qSUcYmybQ9n8nfK1R0EIYN6qtDxo6sAguebcS0dLf3pGzh+l8kjTRCwqpsO3ksYhIP9m8zAoK0XfsscOyvVgbgWlBBHPyLSLlv07nymFQN9rWNb5jDvq83EAqSS4nc4meaJV9tahc5emGip7I2vILUe+N9Z75PdpeXogbW8Dzhg0uPeuVjF47ZycTGwpIMA+rhPuAmBgP8jYoHKH/LrUXKWr1Mg9czr7oWQ2NEv0govHd6m/K2ukxUJvzGG7GgfcoYkg8mky89XrAmHqr+vidgXtNmdX56CRmR7sJSL2c22YVcHmmMDjZ7iPsQQoQSD8PqhfnWTjSqcLO4p4WdR7+FulNLQEidGkO4KvGl3dW2uWBPlNZ/76NyKdjsaSuNd+bCEwfqfR7yOO/51q5ZydHFPoPRxGaGJ8iDcXAVAArxE2MFFnoJmNnlRLF+IJiPmIPIxiwarHVL2kuPf5iZ5SBPKso5ve1hWh3KH+cRpNbc9HSARnd9yc6fPRC23YsPXUSxQBM7zXEnshLBzgQTLaEeCu8WQJJJVYka7EGDjzlAc8LOYc+pAm4MZeekhgFsKwmCdyGtvEHcucOSXWs8Dx4nxlNiJ3knvXyYWbRjKNiTeJpTGIG4dcJcxuTM8bzYc0SQkfdUlAe4Hlkv0j6wcJvJxvrYC87HdAXAhLXamyodaqwr8wp897SWASTmMQowGLf2CW7dxaOJFtLCNVPN2a0pgpvlBMOh3JtvnH+ChFClK7JVIMY7ETGIcLfHtCUqS2akZ3xLM03q7FFXuSDZZwINz151zxna26PFx7cuS4qAFlCshE71v/A0/3DDK aPFq89UI H06ak8VSbJn23HMoZUqBJhQ2BSsxuqgXW8EFd7iH1pZ4CR+5DYGqOFgEHuHf7eT2drIMwaAIQgtp8c5qKpsBrvPRCb7EsvqWzZ+BZQuUl3nr1VIIhhnf+JZqOMsvYS/83CdKKrQlZ3nNKIBW/83u/I6BX1klJuXh0baIFd8zNyycuqDyZQoFw996BIiJg5pBuX9NSKWXh8XOceklWqMzxcvKz+4z98+fhyAuJKHMLlQZ/1tOiq1G3EBXi/GMuOZCEoHWdlzR0Ts8XeF+cGTbtKjQ9GZE9cX8lwE4+q0wTe3Ik0sW4f3AeXwrelob4UMzvmTfk0kkuvhppX0NDz0i+gk0743vqHmjeoqk4OD7XKPDNyB12dg9Nn5zrA6/YrfCdt1/BTJyFjQHQbiDhzZgqaakA0DWM062iUG1IFTLFtn4BpoFIubOWSR6kxK2N3TRma6phVxl0BgcYh7upjSZqZsYfc1IqDbfokh+9pi597CWXZNR0MfTWH0Sj0OjbO61BycXj X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: --0000000000008e9e5f0638130849 Content-Type: text/plain; charset="UTF-8" >From cb505647eb5f418d1ff5e807361f4c3a337c251f Mon Sep 17 00:00:00 2001 From: Lian Wang Date: Sat, 21 Jun 2025 18:51:49 +0800 Subject: [PATCH] selftests/mm: add test for (BATCH_PROCESS)MADV_DONTNEED Let's add a simple test for MADV_DONTNEED and PROCESS_MADV_DONTNEED, and inspired by SeongJae Park's test at GitHub[1] add batch test for PROCESS_MADV_DONTNEED,but for now it influence by workload and need add some race conditions test.We can add it later. Signed-off-by: Lian Wang References ========== [1] https://github.com/sjp38/eval_proc_madvise --- tools/testing/selftests/mm/.gitignore | 1 + tools/testing/selftests/mm/Makefile | 1 + tools/testing/selftests/mm/madv_dontneed.c | 220 +++++++++++++++++++++ tools/testing/selftests/mm/run_vmtests.sh | 5 + 4 files changed, 227 insertions(+) create mode 100644 tools/testing/selftests/mm/madv_dontneed.c diff --git a/tools/testing/selftests/mm/.gitignore b/tools/testing/selftests/mm/.gitignore index 824266982aa3..911f39d634be 100644 --- a/tools/testing/selftests/mm/.gitignore +++ b/tools/testing/selftests/mm/.gitignore @@ -25,6 +25,7 @@ pfnmap protection_keys protection_keys_32 protection_keys_64 +madv_dontneed madv_populate uffd-stress uffd-unit-tests diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile index ae6f994d3add..2352252f3914 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -67,6 +67,7 @@ TEST_GEN_FILES += hugepage-mremap TEST_GEN_FILES += hugepage-shm TEST_GEN_FILES += hugepage-vmemmap TEST_GEN_FILES += khugepaged +TEST_GEN_FILES += madv_dontneed TEST_GEN_FILES += madv_populate TEST_GEN_FILES += map_fixed_noreplace TEST_GEN_FILES += map_hugetlb diff --git a/tools/testing/selftests/mm/madv_dontneed.c b/tools/testing/selftests/mm/madv_dontneed.c new file mode 100644 index 000000000000..b88444da7f9e --- /dev/null +++ b/tools/testing/selftests/mm/madv_dontneed.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MADV_DONTNEED and PROCESS_MADV_DONTNEED tests + * + * Copyright (C) 2025, Linx Software Corp. + * + * Author(s): Lian Wang + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vm_util.h" +#include + +#include "../kselftest.h" + +/* + * For now, we're using 2 MiB of private anonymous memory for all tests. + */ +#define SIZE (256 * 1024 * 1024) + +static size_t pagesize; + +static void sense_support(void) +{ + char *addr; + int ret; + + addr = mmap(0, pagesize, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); + if (!addr) + ksft_exit_fail_msg("mmap failed\n"); + + ret = madvise(addr, pagesize, MADV_DONTNEED); + if (ret) + ksft_exit_skip("MADV_DONTNEED is not available\n"); + + munmap(addr, pagesize); +} + +/* + * Read pagemap to check page is present in mermory + */ +static bool is_page_present(void *addr) +{ + uintptr_t vaddr = (uintptr_t)addr; + uintptr_t offset = (vaddr / pagesize) * sizeof(uint64_t); + ssize_t bytes_read; + uint64_t entry; + bool ret; + int fd; + + fd = open("/proc/self/pagemap", O_RDONLY); + if (fd < 0) { + ksft_exit_fail_msg("opening pagemap failed\n"); + ret = false; + } + + if ((lseek(fd, offset, SEEK_SET)) == -1) { + close(fd); + ret = false; + } + + bytes_read = read(fd, &entry, sizeof(entry)); + close(fd); + + if (bytes_read != sizeof(entry)) { + perror("read failed"); + return false; + } + + if (entry & (1ULL << 63)) + ret = true; + + return ret; +} + +/* + * test madvsise_dontneed + */ +static void test_madv_dontneed(void) +{ + unsigned long rss_anon_before, rss_anon_after; + bool present, rss; + char *addr; + int ret; + + ksft_print_msg("[RUN] %s\n", __func__); + + addr = mmap(0, SIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); + if (!addr) + ksft_exit_fail_msg("mmap failed\n"); + + memset(addr, 0x7A, SIZE); + + rss_anon_before = rss_anon(); + if (!rss_anon_before) + ksft_exit_fail_msg("No RssAnon is allocated before dontneed\n"); + ret = madvise(addr, SIZE, MADV_DONTNEED); + ksft_test_result(!ret, "MADV_DONTNEED\n"); + + rss_anon_after = rss_anon(); + if (rss_anon_after < rss_anon_before) + rss = true; + ksft_test_result(rss, "MADV_DONTNEED rss is correct\n"); + + for (size_t i = 0; i < SIZE; i += pagesize) { + present = is_page_present(addr + i); + if (present) { + ksft_print_msg("Page not zero at offset %zu\n", + (size_t)i); + } + } + + ksft_test_result(!present, "MADV_DONTNEED page is present\n"); + munmap(addr, SIZE); +} + +/* + * Measure performance of batched process_madvise vs madvise + */ +static int measure_process_madvise_batching(int hint, int total_size, + int single_unit, int batch_size) +{ + struct iovec *vec = malloc(sizeof(*vec) * batch_size); + struct timespec start, end; + unsigned long elapsed_ns = 0; + unsigned long nr_measures = 0; + pid_t pid = getpid(); + char *buf; + int pidfd; + + pidfd = syscall(SYS_pidfd_open, pid, 0); + if (pidfd == -1) { + perror("pidfd_open fail"); + return -1; + } + + buf = mmap(NULL, total_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (buf == MAP_FAILED) { + perror("mmap fail"); + goto out; + } + + if (!vec) { + perror("malloc vec failed"); + goto unmap_out; + } + + while (elapsed_ns < 5UL * 1000 * 1000 * 1000) { + memset(buf, 0x7A, total_size); + + clock_gettime(CLOCK_MONOTONIC, &start); + + for (int off = 0; off < total_size; + off += single_unit * batch_size) { + for (int i = 0; i < batch_size; i++) { + vec[i].iov_base = buf + off + i * single_unit; + vec[i].iov_len = single_unit; + } + syscall(SYS_process_madvise, pidfd, vec, batch_size, + hint, 0); + } + + clock_gettime(CLOCK_MONOTONIC, &end); + elapsed_ns += (end.tv_sec - start.tv_sec) * 1e9 + + (end.tv_nsec - start.tv_nsec); + nr_measures++; + } + + ksft_print_msg("[RESULT] batch=%d time=%.3f us/op\n", batch_size, + (double)(elapsed_ns / nr_measures) / + (total_size / single_unit)); + + free(vec); +unmap_out: + munmap(buf, total_size); +out: + close(pidfd); + return 0; +} + +static void test_perf_batch_process(void) +{ + ksft_print_msg("[RUN] %s\n", __func__); + measure_process_madvise_batching(MADV_DONTNEED, SIZE, pagesize, 1); + measure_process_madvise_batching(MADV_DONTNEED, SIZE, pagesize, 2); + measure_process_madvise_batching(MADV_DONTNEED, SIZE, pagesize, 4); + ksft_test_result(1, "All test were done\n"); +} + +int main(int argc, char **argv) +{ + int err; + + pagesize = getpagesize(); + + ksft_print_header(); + ksft_set_plan(4); + + sense_support(); + test_madv_dontneed(); + test_perf_batch_process(); + + err = ksft_get_fail_cnt(); + if (err) + ksft_exit_fail_msg("%d out of %d tests failed\n", err, + ksft_test_num()); + ksft_exit_pass(); +} diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh index dddd1dd8af14..f96d43153fc0 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -47,6 +47,8 @@ separated by spaces: hmm smoke tests - madv_guard test madvise(2) MADV_GUARD_INSTALL and MADV_GUARD_REMOVE options +- madv_dontneed + test memadvise(2) MADV_DONTNEED and PROCESS_MADV_DONTNEED options - madv_populate test memadvise(2) MADV_POPULATE_{READ,WRITE} options - memfd_secret @@ -422,6 +424,9 @@ CATEGORY="hmm" run_test bash ./test_hmm.sh smoke # MADV_GUARD_INSTALL and MADV_GUARD_REMOVE tests CATEGORY="madv_guard" run_test ./guard-regions +# MADV_DONTNEED and PROCESS_DONTNEED tests +CATEGORY="madv_dontneed" run_test ./madv_dontneed + # MADV_POPULATE_READ and MADV_POPULATE_WRITE tests CATEGORY="madv_populate" run_test ./madv_populate -- 2.43.0 --0000000000008e9e5f0638130849 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
From cb505647eb5f418d1ff5e807361f4c3a337c251f Mon Sep 17 0= 0:00:00 2001
From: Lian Wang <= lianux.mm@gmail.com>
Date: Sat, 21 Jun 2025 18:51:49 +0800
Sub= ject: [PATCH] selftests/mm: add test for (BATCH_PROCESS)MADV_DONTNEED
Let's add a simple test for MADV_DONTNEED and PROCESS_MADV_DONTNEED,<= br>and inspired by SeongJae Park's test at GitHub[1] add batch test
= for PROCESS_MADV_DONTNEED,but for now it influence by workload and
need = add some race conditions test.We can add it later.

Signed-off-by: Li= an Wang <lianux.mm@gmail.com&= gt;
References
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

[1] https://github.com/sjp38/eval_pr= oc_madvise

---
=C2=A0tools/testing/selftests/mm/.gitignore = =C2=A0 =C2=A0 =C2=A0| =C2=A0 1 +
=C2=A0tools/testing/selftests/mm/Makefi= le =C2=A0 =C2=A0 =C2=A0 =C2=A0| =C2=A0 1 +
=C2=A0tools/testing/selftests= /mm/madv_dontneed.c | 220 +++++++++++++++++++++
=C2=A0tools/testing/self= tests/mm/run_vmtests.sh =C2=A0| =C2=A0 5 +
=C2=A04 files changed, 227 in= sertions(+)
=C2=A0create mode 100644 tools/testing/selftests/mm/madv_don= tneed.c

diff --git a/tools/testing/selftests/mm/.gitignore b/tools/t= esting/selftests/mm/.gitignore
index 824266982aa3..911f39d634be 100644--- a/tools/testing/selftests/mm/.gitignore
+++ b/tools/testing/selfte= sts/mm/.gitignore
@@ -25,6 +25,7 @@ pfnmap
=C2=A0protection_keys
= =C2=A0protection_keys_32
=C2=A0protection_keys_64
+madv_dontneed
= =C2=A0madv_populate
=C2=A0uffd-stress
=C2=A0uffd-unit-tests
diff -= -git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Mak= efile
index ae6f994d3add..2352252f3914 100644
--- a/tools/testing/sel= ftests/mm/Makefile
+++ b/tools/testing/selftests/mm/Makefile
@@ -67,6= +67,7 @@ TEST_GEN_FILES +=3D hugepage-mremap
=C2=A0TEST_GEN_FILES +=3D = hugepage-shm
=C2=A0TEST_GEN_FILES +=3D hugepage-vmemmap
=C2=A0TEST_GE= N_FILES +=3D khugepaged
+TEST_GEN_FILES +=3D madv_dontneed
=C2=A0TEST= _GEN_FILES +=3D madv_populate
=C2=A0TEST_GEN_FILES +=3D map_fixed_norepl= ace
=C2=A0TEST_GEN_FILES +=3D map_hugetlb
diff --git a/tools/testing/= selftests/mm/madv_dontneed.c b/tools/testing/selftests/mm/madv_dontneed.cnew file mode 100644
index 000000000000..b88444da7f9e
--- /dev/null=
+++ b/tools/testing/selftests/mm/madv_dontneed.c
@@ -0,0 +1,220 @@+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MADV_DONTNEED and= PROCESS_MADV_DONTNEED tests
+ *
+ * Copyright (C) 2025, Linx Softwar= e Corp.
+ *
+ * Author(s): Lian Wang <lianux.mm@gmail.com>
+ */
+#define _GNU_SOURCE
+= #include <stdlib.h>
+#include <string.h>
+#include <st= dbool.h>
+#include <stdint.h>
+#include <unistd.h>
= +#include <errno.h>
+#include <fcntl.h>
+#include <lin= ux/mman.h>
+#include <sys/mman.h>
+#include <sys/syscall.= h>
+#include "vm_util.h"
+#include <time.h>
++#include "../kselftest.h"
+
+/*
+ * For now, we'r= e using 2 MiB of private anonymous memory for all tests.
+ */
+#defin= e SIZE (256 * 1024 * 1024)
+
+static size_t pagesize;
+
+static= void sense_support(void)
+{
+ char *addr;
+ int ret;
+
+ ad= dr =3D mmap(0, pagesize, PROT_READ | PROT_WRITE,
+ =C2=A0 =C2=A0MAP_AN= ONYMOUS | MAP_PRIVATE, 0, 0);
+ if (!addr)
+ ksft_exit_fail_msg(&quo= t;mmap failed\n");
+
+ ret =3D madvise(addr, pagesize, MADV_DONT= NEED);
+ if (ret)
+ ksft_exit_skip("MADV_DONTNEED is not availa= ble\n");
+
+ munmap(addr, pagesize);
+}
+
+/*
+ * Re= ad pagemap to check page is present in mermory
+ */
+static bool is_p= age_present(void *addr)
+{
+ uintptr_t vaddr =3D (uintptr_t)addr;
= + uintptr_t offset =3D (vaddr / pagesize) * sizeof(uint64_t);
+ ssize_t = bytes_read;
+ uint64_t entry;
+ bool ret;
+ int fd;
+
+ fd = =3D open("/proc/self/pagemap", O_RDONLY);
+ if (fd < 0) {+ ksft_exit_fail_msg("opening pagemap failed\n");
+ ret = =3D false;
+ }
+
+ if ((lseek(fd, offset, SEEK_SET)) =3D=3D -1) {<= br>+ close(fd);
+ ret =3D false;
+ }
+
+ bytes_read =3D read(= fd, &entry, sizeof(entry));
+ close(fd);
+
+ if (bytes_read != =3D sizeof(entry)) {
+ perror("read failed");
+ return fa= lse;
+ }
+
+ if (entry & (1ULL << 63))
+ ret =3D tru= e;
+
+ return ret;
+}
+
+/*
+ * test madvsise_dontneed+ */
+static void test_madv_dontneed(void)
+{
+ unsigned long rss= _anon_before, rss_anon_after;
+ bool present, rss;
+ char *addr;
+= int ret;
+
+ ksft_print_msg("[RUN] %s\n", __func__);
+<= br>+ addr =3D mmap(0, SIZE, PROT_READ | PROT_WRITE,
+ =C2=A0 =C2=A0MAP= _ANONYMOUS | MAP_PRIVATE, 0, 0);
+ if (!addr)
+ ksft_exit_fail_msg(&= quot;mmap failed\n");
+
+ memset(addr, 0x7A, SIZE);
+
+ rs= s_anon_before =3D rss_anon();
+ if (!rss_anon_before)
+ ksft_exit_fa= il_msg("No RssAnon is allocated before dontneed\n");
+ ret =3D= madvise(addr, SIZE, MADV_DONTNEED);
+ ksft_test_result(!ret, "MADV= _DONTNEED\n");
+
+ rss_anon_after =3D rss_anon();
+ if (rss_a= non_after < rss_anon_before)
+ rss =3D true;
+ ksft_test_result(r= ss, "MADV_DONTNEED rss is correct\n");
+
+ for (size_t i = =3D 0; i < SIZE; i +=3D pagesize) {
+ present =3D is_page_present(ad= dr + i);
+ if (present) {
+ ksft_print_msg("Page not zero at = offset %zu\n",
+ =C2=A0 =C2=A0 =C2=A0 (size_t)i);
+ }
+ = }
+
+ ksft_test_result(!present, "MADV_DONTNEED page is present\= n");
+ munmap(addr, SIZE);
+}
+
+/*
+ * Measure perform= ance of batched process_madvise vs madvise
+ */
+static int measure_p= rocess_madvise_batching(int hint, int total_size,
+ =C2=A0 =C2=A0in= t single_unit, int batch_size)
+{
+ struct iovec *vec =3D malloc(size= of(*vec) * batch_size);
+ struct timespec start, end;
+ unsigned long= elapsed_ns =3D 0;
+ unsigned long nr_measures =3D 0;
+ pid_t pid =3D= getpid();
+ char *buf;
+ int pidfd;
+
+ pidfd =3D syscall(SYS_= pidfd_open, pid, 0);
+ if (pidfd =3D=3D -1) {
+ perror("pidfd_o= pen fail");
+ return -1;
+ }
+
+ buf =3D mmap(NULL, total= _size, PROT_READ | PROT_WRITE,
+ =C2=A0 MAP_PRIVATE | MAP_ANONYMOUS, -= 1, 0);
+ if (buf =3D=3D MAP_FAILED) {
+ perror("mmap fail"= );
+ goto out;
+ }
+
+ if (!vec) {
+ perror("malloc v= ec failed");
+ goto unmap_out;
+ }
+
+ while (elapsed_ns = < 5UL * 1000 * 1000 * 1000) {
+ memset(buf, 0x7A, total_size);
+<= br>+ clock_gettime(CLOCK_MONOTONIC, &start);
+
+ for (int off = =3D 0; off < total_size;
+ =C2=A0 =C2=A0 off +=3D single_unit * bat= ch_size) {
+ for (int i =3D 0; i < batch_size; i++) {
+ vec[i= ].iov_base =3D buf + off + i * single_unit;
+ vec[i].iov_len =3D sing= le_unit;
+ }
+ syscall(SYS_process_madvise, pidfd, vec, batch_siz= e,
+ hint, 0);
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &= ;end);
+ elapsed_ns +=3D (end.tv_sec - start.tv_sec) * 1e9 +
+ = =C2=A0 =C2=A0 =C2=A0(end.tv_nsec - start.tv_nsec);
+ nr_measures++;
= + }
+
+ ksft_print_msg("[RESULT] batch=3D%d time=3D%.3f us/op\n&= quot;, batch_size,
+ =C2=A0 =C2=A0 =C2=A0 (double)(elapsed_ns / nr_mea= sures) /
+ =C2=A0 =C2=A0 =C2=A0 (total_size / single_unit));
+
= + free(vec);
+unmap_out:
+ munmap(buf, total_size);
+out:
+ clo= se(pidfd);
+ return 0;
+}
+
+static void test_perf_batch_proces= s(void)
+{
+ ksft_print_msg("[RUN] %s\n", __func__);
+ m= easure_process_madvise_batching(MADV_DONTNEED, SIZE, pagesize, 1);
+ mea= sure_process_madvise_batching(MADV_DONTNEED, SIZE, pagesize, 2);
+ measu= re_process_madvise_batching(MADV_DONTNEED, SIZE, pagesize, 4);
+ ksft_te= st_result(1, "All test were done\n");
+}
+
+int main(int= argc, char **argv)
+{
+ int err;
+
+ pagesize =3D getpagesize(= );
+
+ ksft_print_header();
+ ksft_set_plan(4);
+
+ sense_su= pport();
+ test_madv_dontneed();
+ test_perf_batch_process();
++ err =3D ksft_get_fail_cnt();
+ if (err)
+ ksft_exit_fail_msg(&quo= t;%d out of %d tests failed\n", err,
+ =C2=A0 ksft_test_num());=
+ ksft_exit_pass();
+}
diff --git a/tools/testing/selftests/mm/ru= n_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh
index dddd1dd8a= f14..f96d43153fc0 100755
--- a/tools/testing/selftests/mm/run_vmtests.sh=
+++ b/tools/testing/selftests/mm/run_vmtests.sh
@@ -47,6 +47,8 @@ se= parated by spaces:
=C2=A0 hmm smoke tests
=C2=A0- madv_guard
=C2= =A0 test madvise(2) MADV_GUARD_INSTALL and MADV_GUARD_REMOVE options
+- = madv_dontneed
+ test memadvise(2) MADV_DONTNEED and PROCESS_MADV_DONTNEE= D options
=C2=A0- madv_populate
=C2=A0 test memadvise(2) MADV_POPULAT= E_{READ,WRITE} options
=C2=A0- memfd_secret
@@ -422,6 +424,9 @@ CATEG= ORY=3D"hmm" run_test bash ./test_hmm.sh smoke
=C2=A0# MADV_GUA= RD_INSTALL and MADV_GUARD_REMOVE tests
=C2=A0CATEGORY=3D"madv_guard= " run_test ./guard-regions
=C2=A0
+# MADV_DONTNEED and PROCESS_D= ONTNEED tests
+CATEGORY=3D"madv_dontneed" run_test ./madv_dont= need
+
=C2=A0# MADV_POPULATE_READ and MADV_POPULATE_WRITE tests
= =C2=A0CATEGORY=3D"madv_populate" run_test ./madv_populate
=C2= =A0
--
2.43.0

--0000000000008e9e5f0638130849--