From: Konstantin Khorenko <khorenko@virtuozzo.com>
To: "David Hildenbrand (Arm)" <david@kernel.org>,
Andrew Morton <akpm@linux-foundation.org>,
Zi Yan <ziy@nvidia.com>, Lorenzo Stoakes <ljs@kernel.org>,
Alistair Popple <apopple@nvidia.com>,
Dan Williams <djbw@kernel.org>
Cc: linux-mm@kvack.org, nvdimm@lists.linux.dev,
linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 2/2] selftests/mm: test fork of a device DAX PUD
Date: Fri, 6 Nov 2026 17:26:04 +0100 [thread overview]
Message-ID: <18d49173-60f8-48b8-af1a-2ac435aecc79@virtuozzo.com> (raw)
In-Reply-To: <eb5e8a1c-a654-4d68-92b1-db0128fa8752@kernel.org>
On 11/5/26 20:30, David Hildenbrand (Arm) wrote:
> On 11/5/26 18:00, Konstantin Khorenko wrote:
>> Fork a process that maps a device DAX instance with a PUD, in a VMA
>> whose page tables fork copies because it has a guard region. The child
>> must account the copied PUD in its RssFile, which a new rss_file() in
>> vm_util reads as rss_anon() reads RssAnon.
>>
>> Without a reference, an rmap and a counter for the copied PUD, the
>> child's RssFile misses the PUD, and its exit leaves the child's file
>> counter negative: "Bad rss-counter state".
>>
>> It runs only on a device named in argv[1] or $FORK_DAX_PUD_DEVICE: on
>> a kernel without the fix it leaves the device folio's mapcount below
>> zero.
>>
>> Signed-off-by: Konstantin Khorenko <khorenko@virtuozzo.com>
>> ---
>> MAINTAINERS | 1 +
>> tools/testing/selftests/mm/Makefile | 1 +
>> tools/testing/selftests/mm/fork_dax_pud.c | 114 ++++++++++++++++++++++++++++++
>> tools/testing/selftests/mm/run_vmtests.sh | 1 +
>> tools/testing/selftests/mm/vm_util.c | 21 ++++++
>> tools/testing/selftests/mm/vm_util.h | 1 +
>> 6 files changed, 139 insertions(+)
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index d63d8b2152773..247e16f3276f4 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -17931,6 +17931,7 @@ F: mm/huge_memory.c
>> F: mm/khugepaged.c
>> F: mm/mm_slot.h
>> F: tools/mm/thpmaps
>> +F: tools/testing/selftests/mm/fork_dax_pud.c
>> F: tools/testing/selftests/mm/khugepaged.c
>> F: tools/testing/selftests/mm/split_huge_page_test.c
>> F: tools/testing/selftests/mm/transhuge-stress.c
>> diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile
>> index 0ea72e9979347..130500f5f6e0a 100644
>> --- a/tools/testing/selftests/mm/Makefile
>> +++ b/tools/testing/selftests/mm/Makefile
>> @@ -108,6 +108,7 @@ TEST_GEN_FILES += folio_split_race_test
>> TEST_GEN_FILES += folio_order_check
>> TEST_GEN_FILES += khugepaged_sync_check
>> TEST_GEN_FILES += khugepaged_race
>> +TEST_GEN_FILES += fork_dax_pud
>> TEST_GEN_FILES += soft-dirty
>>
>> ifeq ($(ARCH),x86_64)
>> diff --git a/tools/testing/selftests/mm/fork_dax_pud.c b/tools/testing/selftests/mm/fork_dax_pud.c
>> new file mode 100644
>> index 0000000000000..0d19c30b1dc6f
>> --- /dev/null
>> +++ b/tools/testing/selftests/mm/fork_dax_pud.c
>> @@ -0,0 +1,114 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * fork() of a process that maps a device DAX instance with a PUD, in a VMA
>> + * whose page tables fork copies because it has a guard region. The child
>> + * must account the copied PUD in its RssFile.
>> + *
>> + * Runs only on a device named in argv[1] or $FORK_DAX_PUD_DEVICE that
>> + * nothing else maps, with 1 GiB alignment and at least 2 GiB. To make one
>> + * on pmem emulated in RAM, with CONFIG_X86_PMEM_LEGACY and
>> + * CONFIG_DEV_DAX_PMEM:
>> + *
>> + * boot with memmap=3G!4G
>> + * ndctl create-namespace -f -e namespace0.0 -m devdax -a 1G
>> + * FORK_DAX_PUD_DEVICE=/dev/dax0.0 ./fork_dax_pud
>> + */
>> +#define _GNU_SOURCE
>> +#include <asm-generic/mman.h> /* Force the import of the tools version. */
>> +#include <errno.h>
>> +#include <fcntl.h>
>> +#include <limits.h>
>> +#include <setjmp.h>
>> +#include <signal.h>
>> +#include <stdbool.h>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <unistd.h>
>> +#include <sys/mman.h>
>> +#include <sys/wait.h>
>> +
>> +#include "kselftest.h"
>> +#include "vm_util.h"
>> +
>> +#define SZ_1G (1UL << 30)
>> +#define DAX_SYSFS "/sys/bus/dax/devices"
>> +
>> +static sigjmp_buf sigbus_jmp;
>> +
>> +static void sigbus_handler(int sig)
>> +{
>> + siglongjmp(sigbus_jmp, 1);
>> +}
>> +
>> +static bool dax_attr(const char *dev, const char *attr, unsigned long *val)
>> +{
>> + char path[PATH_MAX];
>> +
>> + snprintf(path, sizeof(path), DAX_SYSFS "/%s/%s", dev, attr);
>> + return !read_sysfs(path, val);
>> +}
>> +
>> +static bool dax_dev_ok(const char *path)
>> +{
>> + const char *name = strrchr(path, '/');
>> + unsigned long align, size;
>> +
>> + name = name ? name + 1 : path;
>> + return dax_attr(name, "align", &align) && align == SZ_1G &&
>> + dax_attr(name, "size", &size) && size >= 2 * SZ_1G;
>> +}
>> +
>> +int main(int argc, char **argv)
>> +{
>> + const char *path = argc > 1 ? argv[1] : getenv("FORK_DAX_PUD_DEVICE");
>> + char *area, *mem;
>> + int fd, status;
>> + pid_t pid;
>> +
>> + ksft_print_header();
>> + if (!path)
>> + ksft_exit_skip("no devdax device given\n");
>> + if (!dax_dev_ok(path))
>> + ksft_exit_skip("%s: needs 1 GiB alignment and 2 GiB\n", path);
>> +
>> + fd = open(path, O_RDONLY);
>> + if (fd < 0)
>> + ksft_exit_skip("%s: %s\n", path, strerror(errno));
>> + area = mmap(NULL, 3 * SZ_1G, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
>> + if (area == MAP_FAILED)
>> + ksft_exit_fail_perror("mmap");
>> + mem = (char *)(((unsigned long)area + SZ_1G - 1) & ~(SZ_1G - 1));
>> + mem = mmap(mem, 2 * SZ_1G, PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0);
>> + if (mem == MAP_FAILED)
>> + ksft_exit_skip("mmap %s: %s\n", path, strerror(errno));
>> +
>> + /* A PUD in the first GiB, a guard page at the end of the second. */
>> + signal(SIGBUS, sigbus_handler);
>> + if (sigsetjmp(sigbus_jmp, 1))
>> + ksft_exit_skip("%s cannot be mapped with a PUD\n", path);
>> + FORCE_READ(mem[0]);
>> + signal(SIGBUS, SIG_DFL);
>> + if (madvise(mem + 2 * SZ_1G - getpagesize(), getpagesize(),
>> + MADV_GUARD_INSTALL))
>> + ksft_exit_skip("MADV_GUARD_INSTALL: %s\n", strerror(errno));
>> +
>> + ksft_set_plan(1);
>> + fflush(stdout);
>> + pid = fork();
>> + if (pid < 0)
>> + ksft_exit_fail_perror("fork");
>> + if (!pid)
>> + _exit(rss_file() < (SZ_1G >> 10) ? 10 : 0);
>> + if (waitpid(pid, &status, 0) != pid)
>> + ksft_exit_fail_perror("waitpid");
>> +
>> + if (!WIFEXITED(status) || WEXITSTATUS(status))
>> + ksft_test_result_fail("child does not account the copied PUD\n");
>> + else
>> + ksft_test_result_pass("devdax PUD copied by fork\n");
>> +
>> + munmap(area, 3 * SZ_1G);
>> + close(fd);
>> + ksft_finished();
>> +}
>
> I prefer to not merge this. It requires an actual dax device, so it's not very
> applicable on CI systems, and we don't want selftests to take parameters in one
> form or the other.
Sure, i will drop the test in v3 and just put a link to this test in the
cover letter and that's it.
--
Cheers,
Konstantin
prev parent reply other threads:[~2026-11-06 16:26 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 17:00 [PATCH v2 0/2] mm/huge_memory: take a reference on a device DAX PUD copied by fork Konstantin Khorenko
2026-11-05 17:00 ` [PATCH v2 1/2] mm/huge_memory: take a reference on a folio " Konstantin Khorenko
2026-11-05 19:28 ` David Hildenbrand (Arm)
2026-11-05 20:19 ` Zi Yan
2026-11-05 20:31 ` David Hildenbrand (Arm)
2026-11-06 16:32 ` Konstantin Khorenko
2026-11-05 17:00 ` [PATCH v2 2/2] selftests/mm: test fork of a device DAX PUD Konstantin Khorenko
2026-11-05 19:30 ` David Hildenbrand (Arm)
2026-11-06 16:26 ` Konstantin Khorenko [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=18d49173-60f8-48b8-af1a-2ac435aecc79@virtuozzo.com \
--to=khorenko@virtuozzo.com \
--cc=akpm@linux-foundation.org \
--cc=apopple@nvidia.com \
--cc=david@kernel.org \
--cc=djbw@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=nvdimm@lists.linux.dev \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®