From nobody Sat Jul 25 20:47:02 2026 Received: from va-1-112.ptr.blmpb.com (va-1-112.ptr.blmpb.com [209.127.230.112]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6B7172773DE for ; Mon, 13 Jul 2026 17:15:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.127.230.112 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783962944; cv=none; b=AS31R7yekBTEYm9MVHSjfgqJd4sSbLl7s+UPM65KQxYYoQt8w70YlrwDm+wrY3J16gUJCC1feWW0xnkEyhAHe3kLIYeSBvrUq7D3u+Ek7ba9zpFwzOMufeqgCMnUI2I+p4afZfGpN90fAbLPfGM+V+Hzcm+K61HM4rJtmCm8J+k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783962944; c=relaxed/simple; bh=Aa8/5udmfj8TWjs9Foxa4aNvmPw6ehqBRclM4OZGM5M=; h=To:Cc:Mime-Version:References:Content-Type:Date:In-Reply-To:From: Subject:Message-Id; b=sJPEUkTCQnrNX5xwEPQRzJYZ7kOdl9BZUv1qlzMYz4uzRbot0k+aswJxXr5UrSE0TBHnzAh12/pIgm/cNNWGvEikf64p5WONNYuTa55RwsZzW5LLlxxYoy54xlFaFWlMRFrcspf3cjJ0TdVWM1sTeAifXJcRZAcvc3HtLgX7SOY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=bytedance.com; spf=pass smtp.mailfrom=bytedance.com; dkim=pass (2048-bit key) header.d=bytedance.com header.i=@bytedance.com header.b=hv1aiAcn; arc=none smtp.client-ip=209.127.230.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=bytedance.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bytedance.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bytedance.com header.i=@bytedance.com header.b="hv1aiAcn" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=2212171451; d=bytedance.com; t=1783962936; h=from:subject: mime-version:from:date:message-id:subject:to:cc:reply-to:content-type: mime-version:in-reply-to:message-id; bh=Nw+wphzpHskAbkcarmC3gNoJ47BFqLlYPBNMfUcVWJk=; b=hv1aiAcn/0yT3QSpIcP8SEh1TTNWX0ykOHopIA9NWEyADckU+Z7pcRNqQBqrjbrLG/oml5 3T63yANZU4Uuntj+OFE7MjMi7qkXxeWTo6wxP47VSrfdeWGJqOGdhQ2pbCOvO/+4uAVmZE Oc3zJC3SNbALj3I8ZZ/Dn2MecH4ybxwi0PhxG+e/kp+zGbjNc+F4mycM1ujCgREqv6Nqlc Oe+/bi/NVQWcn3ys3n6SbIeZIMq665/Jb61v5ZzMpQ19vidAU8DbeFMa40bcszYC1aFmHz PZMU1d/HC57RqWtXG/eMX3GqA5Bb4hH0AEXIS5lkMg4t5D71kCoQd7NgcVmEuA== To: , , , Cc: , , , , , , , Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 Content-Transfer-Encoding: quoted-printable References: <20260713171456.300518-1-caixiangfeng@bytedance.com> X-Original-From: Xiangfeng Cai Date: Tue, 14 Jul 2026 01:14:55 +0800 In-Reply-To: <20260713171456.300518-1-caixiangfeng@bytedance.com> From: "Xiangfeng Cai" Subject: [PATCH 1/2] mm/hugetlb: fix list corruption in allocate_file_region_entries() Message-Id: <20260713171456.300518-2-caixiangfeng@bytedance.com> X-Mailer: git-send-email 2.55.0.122.gf85a7e6620 X-Lms-Return-Path: Content-Type: text/plain; charset="utf-8" allocate_file_region_entries() tops up resv->region_cache with freshly allocated file_region descriptors. The allocation uses GFP_KERNEL, so resv->lock is dropped around it: the new entries are gathered on a stack-local list head, allocated_regions, and spliced into resv->region_cache once the lock is re-acquired. The splice used list_splice(), which moves the entries but does not re-initialize the source head, so allocated_regions is left pointing at an entry that now lives on resv->region_cache. The top-up runs in a while loop that re-checks the cache deficit after re-acquiring the lock. For a shared mapping the resv_map is shared by every mapper of the hugetlbfs inode, so a concurrent region_chg()/region_add()/region_del() on the same resv_map can consume cache entries during the unlocked window and force a second iteration. That iteration calls list_add() on the stale head and corrupts the list; with CONFIG_DEBUG_LIST the __list_add_valid() check trips: list_add corruption. next->prev should be prev (ffffc900011ff7f8), but was ffff88814c281460. (next=3Dffff88814c545640). kernel BUG at lib/list_debug.c:31! allocate_file_region_entries+0x191/0x420 region_chg+0x267/0x300 hugetlb_reserve_pages+0x387/0xc80 hugetlbfs_file_mmap+0x2ce/0x3f0 mmap_region+0x1348/0x1a80 do_mmap+0x85e/0xb90 vm_mmap_pgoff+0x18c/0x330 ksys_mmap_pgoff+0x2a1/0x3e0 do_syscall_64+0xd7/0x420 Without CONFIG_DEBUG_LIST the bad list_add() silently links a kernel-stack address into resv->region_cache, leading to later use-after-free. Use list_splice_init() so the source head is re-initialized empty after each splice, making the retry loop safe. Fixes: d3ec7b6e09e5 ("mm/hugetlb: use list_splice to merge two list at once= ") Cc: Signed-off-by: Xiangfeng Cai Reviewed-by: Muchun Song --- mm/hugetlb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 571212b80835..f9577a789fe6 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -693,7 +693,7 @@ static int allocate_file_region_entries(struct resv_map= *resv, =20 spin_lock(&resv->lock); =20 - list_splice(&allocated_regions, &resv->region_cache); + list_splice_init(&allocated_regions, &resv->region_cache); resv->region_cache_count +=3D to_allocate; } =20 --=20 2.55.0.122.gf85a7e6620 From nobody Sat Jul 25 20:47:02 2026 Received: from va-1-113.ptr.blmpb.com (va-1-113.ptr.blmpb.com [209.127.230.113]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9182A26F2B0 for ; Mon, 13 Jul 2026 17:15:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.127.230.113 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783962959; cv=none; b=Z/WKCt02fa4TX5qIT/c9Uf/46KcvyDJmTWGeqjHXmNAftvMECfzODSss35duj5W6Cke6w3POSdO57FIAOPV37VPcb448Fb9slw9WTHSlkqGCFwO4SsrFiNbMNf791dH403binbMa6tzEPAHBlOe3LwSuEHKSObnXlLlSQ3B28ys= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783962959; c=relaxed/simple; bh=lbWCACkR41uJTu9GOag7zGhGTR2jdNc+qOeSlVKSSbc=; h=Content-Type:From:Subject:Cc:Message-Id:Mime-Version:In-Reply-To: To:References:Date; b=RS2MuWC0NIeLI/xcjCtuB4w/KtbkBk33zPSXQIAe06DvRbrY3DDwOolgKRZancwtMjCfHPXW0F86yPFPnOB5tOf4yLC8bz6gHuexy9X3ZzeVg+IqWcyqsLKhKeRVqWuKsm2C/V53MYUjj6MbIp1gKieG+6dOCXPT+2TyX5uLI7A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=bytedance.com; spf=pass smtp.mailfrom=bytedance.com; dkim=pass (2048-bit key) header.d=bytedance.com header.i=@bytedance.com header.b=oZukcZ5v; arc=none smtp.client-ip=209.127.230.113 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=bytedance.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bytedance.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bytedance.com header.i=@bytedance.com header.b="oZukcZ5v" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=2212171451; d=bytedance.com; t=1783962947; h=from:subject: mime-version:from:date:message-id:subject:to:cc:reply-to:content-type: mime-version:in-reply-to:message-id; bh=FQf/qWjQhGY0dwG8Ri4r2F+VrewrSV+wxAsCOy/JUy8=; b=oZukcZ5voP5cD0olLVdsQts52lsu6o0FxT+43MJt4IJoKeHanYgl/9v/ipwcqfIMs/Zs0m oHkS26m5G6mVlzlM05IpLBgF59W9i8IBRr9q8yj9IfoLfgudIH1mdMBjqu9lJotWdF9MQF PaMHjfHr3vFphvBU/ZPtEnaDydInO/ubdR41J7Ul4C145v2vMh/8Xu4njTmYVUavtYQ3Fs qAhm1+TTPsxqcQrxgSAyIu2dw6oJAZenMTagq9ZyCwWpb7ChCctd5xtkUsWS4iDtpVbj9f nYM044hDhllTf1iTwjQICXVF2ajR8w0q3MkOWgtyPamYiKX88M1kPqlx9UkHyA== From: "Xiangfeng Cai" Subject: [PATCH 2/2] selftests/mm: add hugetlb_region_cache_race regression test Cc: , , , , , , , Message-Id: <20260713171456.300518-3-caixiangfeng@bytedance.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 In-Reply-To: <20260713171456.300518-1-caixiangfeng@bytedance.com> X-Original-From: Xiangfeng Cai X-Lms-Return-Path: To: , , , Content-Transfer-Encoding: quoted-printable X-Mailer: git-send-email 2.55.0.122.gf85a7e6620 References: <20260713171456.300518-1-caixiangfeng@bytedance.com> Date: Tue, 14 Jul 2026 01:14:56 +0800 Content-Type: text/plain; charset="utf-8" Add a regression test for the list corruption in allocate_file_region_entries() fixed by the previous patch ("mm/hugetlb: fix list corruption in allocate_file_region_entries()"). Triggering the bug requires a concurrent reservation operation to drain resv->region_cache while allocate_file_region_entries() has dropped resv->lock for its GFP_KERNEL allocation, forcing its retry loop to run again. As the mmap() and fallocate(PUNCH_HOLE) paths serialise on inode_lock, the cache has to be drained by faults from a separate address space. The test forks several processes sharing one hugetlb inode via memfd_create(MFD_HUGETLB); each mmap()s and faults ranges and punches holes to keep the shared resv_map fragmented. Two modes are provided: - default: a safe single-process functional check that exercises the buggy line without forcing a second loop iteration; safe on any kernel. - --trigger: the concurrent reproducer, which panics a vulnerable CONFIG_DEBUG_LIST=3Dy kernel and is therefore opt-in. It faults pages i= n, so it needs as many free huge pages as the file is large. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Xiangfeng Cai --- tools/testing/selftests/mm/.gitignore | 1 + tools/testing/selftests/mm/Makefile | 1 + .../selftests/mm/hugetlb_region_cache_race.c | 315 ++++++++++++++++++ tools/testing/selftests/mm/run_vmtests.sh | 1 + 4 files changed, 318 insertions(+) create mode 100644 tools/testing/selftests/mm/hugetlb_region_cache_race.c diff --git a/tools/testing/selftests/mm/.gitignore b/tools/testing/selftest= s/mm/.gitignore index 9ccd9e1447e6..7db8657960d9 100644 --- a/tools/testing/selftests/mm/.gitignore +++ b/tools/testing/selftests/mm/.gitignore @@ -59,6 +59,7 @@ hugetlb_madv_vs_map mseal_test droppable hugetlb_dio +hugetlb_region_cache_race pkey_sighandler_tests_32 pkey_sighandler_tests_64 guard-regions diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/= mm/Makefile index e6df968f0971..421a0b7fdddf 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -67,6 +67,7 @@ TEST_GEN_FILES +=3D hugetlb-read-hwpoison TEST_GEN_FILES +=3D hugetlb-shm TEST_GEN_FILES +=3D hugetlb-soft-offline TEST_GEN_FILES +=3D hugetlb-vmemmap +TEST_GEN_FILES +=3D hugetlb_region_cache_race TEST_GEN_FILES +=3D khugepaged TEST_GEN_FILES +=3D madv_populate TEST_GEN_FILES +=3D map_fixed_noreplace diff --git a/tools/testing/selftests/mm/hugetlb_region_cache_race.c b/tools= /testing/selftests/mm/hugetlb_region_cache_race.c new file mode 100644 index 000000000000..6e3f753640be --- /dev/null +++ b/tools/testing/selftests/mm/hugetlb_region_cache_race.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Regression test for list corruption in + * mm/hugetlb.c:allocate_file_region_entries(). + * + * Fork processes sharing a hugetlb inode via `memfd_create(MFD_HUGETLB)` + * and have them fault ranges and punch holes to fragment the shared + * `resv_map` while draining `resv->region_cache` from a separate address + * space. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../kselftest.h" +#include "hugepage_settings.h" + +/* Tunables (overridable via argv). */ +static unsigned long file_pages =3D 64; /* huge pages backing the shared f= ile */ +static unsigned int nr_procs; /* 0 =3D> auto (2 * nr online cpus) */ +static unsigned int duration_sec =3D 5; /* --trigger run time */ + +static unsigned long huge_page_size; /* bytes */ +static int memfd =3D -1; +static volatile int *stop; /* shared across forked children */ + +/* + * Per-process SIGBUS escape: a fault can fail (pool exhausted) and raise + * SIGBUS; jump back and abandon the rest of the current range instead of + * dying. Each child is single-threaded, so a file-scope buffer is fine. + */ +static sigjmp_buf sigbus_env; + +static void sigbus_handler(int sig) +{ + siglongjmp(sigbus_env, 1); +} + +static void install_sigbus_handler(void) +{ + struct sigaction sa =3D { + .sa_handler =3D sigbus_handler, + }; + + sigemptyset(&sa.sa_mask); + sigaction(SIGBUS, &sa, NULL); +} + +static long sys_memfd_create(const char *name, unsigned int flags) +{ + return syscall(__NR_memfd_create, name, flags); +} + +/* + * Map [start, start+len) of the shared file and fault every page in. + * + * The mmap() drives mmap-time hugetlb_reserve_pages -> region_chg (the + * wide-window victim when the range is fragmented) + region_add. The + * subsequent stores fault pages in *without* inode_lock, driving the + * lock-free region_add/region_chg that drains resv->region_cache -- the + * concurrency the buggy loop needs from *other* processes. + */ +static void map_and_fault_range(unsigned long start, unsigned long len) +{ + unsigned long i; + char *addr; + + if (!len) + return; + addr =3D mmap(NULL, len * huge_page_size, PROT_READ | PROT_WRITE, + MAP_SHARED, memfd, start * huge_page_size); + if (addr =3D=3D MAP_FAILED) + return; /* ENOMEM under pool pressure is fine */ + + for (i =3D 0; i < len; i++) { + if (sigsetjmp(sigbus_env, 1) =3D=3D 0) + *(volatile char *)(addr + i * huge_page_size) =3D (char)i; + else + break; /* SIGBUS: pool exhausted, stop faulting */ + } + munmap(addr, len * huge_page_size); +} + +/* + * Remove [start, start+len) huge pages from the shared file, driving + * hugetlbfs_punch_hole -> remove_inode_hugepages -> region_del for the pa= ges + * that were faulted in above. This frees pages back to the pool (bounding + * residency) and re-fragments the resv_map so later region_chg calls keep + * needing multiple entries. + */ +static void punch_range(unsigned long start, unsigned long len) +{ + if (!len) + return; + fallocate(memfd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + start * huge_page_size, len * huge_page_size); +} + +/* + * One forked worker. Each worker is simultaneously a victim (its wide + * mmap-time region_chg) and, for the other workers, a lock-free cache + * drainer (its faults) -- exactly the shared-inode map+fault churn seen in + * the original crash (QEMU prealloc + SPDK/Bytelight on one guest-RAM fil= e). + */ +static void child_worker(unsigned int id) +{ + unsigned int seed =3D id * 2654435761u ^ (unsigned int)time(NULL) ^ + ((unsigned int)getpid() << 1); + + install_sigbus_handler(); + + while (!*stop) { + unsigned long start =3D rand_r(&seed) % file_pages; + unsigned long len =3D 1 + rand_r(&seed) % (file_pages - start); + + /* + * Bias toward map+fault (victims and drainers); punch a + * quarter of the time to keep the map fragmented and to cap + * how many pages stay resident. + */ + if (rand_r(&seed) % 4) + map_and_fault_range(start, len); + else + punch_range(start, len); + } +} + +/* + * Safe, single-process functional check. It fragments the shared resv_map + * (reservations for a shared mapping persist on the inode after munmap) so + * that a subsequent whole-file mmap makes region_chg compute + * regions_needed > 1, forcing allocate_file_region_entries to allocate and + * splice several entries. This exercises the buggy line, but without + * concurrency it always makes exactly one loop iteration, so it cannot tr= ip + * the race and is safe on any kernel. Returns 0 on success. + */ +static int functional_check(void) +{ + unsigned long i; + void *addr; + + /* Punch everything so we start from an empty resv_map. */ + punch_range(0, file_pages); + + /* Reserve every other huge page -> ~file_pages/2 disjoint regions. */ + for (i =3D 0; i < file_pages; i +=3D 2) + map_and_fault_range(i, 1); + + /* + * One mapping spanning the whole file must fill all the holes in a + * single region_chg -> a multi-entry region_cache refill. + */ + addr =3D mmap(NULL, file_pages * huge_page_size, PROT_READ | PROT_WRITE, + MAP_SHARED, memfd, 0); + if (addr =3D=3D MAP_FAILED) { + ksft_print_msg("whole-file mmap failed: %s\n", strerror(errno)); + return -1; + } + munmap(addr, file_pages * huge_page_size); + punch_range(0, file_pages); + return 0; +} + +static int run_trigger(void) +{ + pid_t *pids; + unsigned int i, started =3D 0; + + stop =3D mmap(NULL, sizeof(*stop), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (stop =3D=3D MAP_FAILED) + ksft_exit_fail_msg("mmap(stop flag): %s\n", strerror(errno)); + *stop =3D 0; + + pids =3D calloc(nr_procs, sizeof(*pids)); + if (!pids) + ksft_exit_fail_msg("calloc: %s\n", strerror(errno)); + + ksft_print_msg("stressing %u processes for %us on %lu huge pages (%lu MiB= )\n", + nr_procs, duration_sec, file_pages, + (file_pages * huge_page_size) >> 20); + ksft_print_msg("WARNING: a vulnerable kernel will panic here\n"); + + for (i =3D 0; i < nr_procs; i++) { + pid_t pid =3D fork(); + + if (pid < 0) { + ksft_print_msg("fork: %s\n", strerror(errno)); + break; + } + if (pid =3D=3D 0) { + free(pids); + child_worker(i); + _exit(0); + } + pids[started++] =3D pid; + } + + if (!started) { + free(pids); + munmap((void *)stop, sizeof(*stop)); + ksft_exit_fail_msg("no worker processes started\n"); + } + + sleep(duration_sec); + *stop =3D 1; + + for (i =3D 0; i < started; i++) + waitpid(pids[i], NULL, 0); + free(pids); + munmap((void *)stop, sizeof(*stop)); + return 0; +} + +static void usage(const char *prog) +{ + fprintf(stderr, + "usage: %s [--trigger] [-s huge_pages] [-t procs] [-d seconds]\n" + " (default) run a safe single-process functional check\n" + " --trigger fork+fault concurrent reproducer (CAN PANIC A BUGGY HOST)\n" + " -s huge pages backing the shared file (default %lu)\n" + " -t worker processes for --trigger (default 2 * nr_cpus)\n" + " -d --trigger run time in seconds (default %u)\n", + prog, file_pages, duration_sec); +} + +int main(int argc, char *argv[]) +{ + bool trigger =3D false; + int i, ret; + + for (i =3D 1; i < argc; i++) { + if (!strcmp(argv[i], "--trigger")) { + trigger =3D true; + } else if (!strcmp(argv[i], "-s") && i + 1 < argc) { + file_pages =3D strtoul(argv[++i], NULL, 0); + } else if (!strcmp(argv[i], "-t") && i + 1 < argc) { + nr_procs =3D strtoul(argv[++i], NULL, 0); + } else if (!strcmp(argv[i], "-d") && i + 1 < argc) { + duration_sec =3D strtoul(argv[++i], NULL, 0); + } else { + usage(argv[0]); + return KSFT_FAIL; + } + } + + ksft_print_header(); + ksft_set_plan(1); + + if (file_pages < 4) + file_pages =3D 4; + if (!nr_procs) { + long cpus =3D sysconf(_SC_NPROCESSORS_ONLN); + + nr_procs =3D cpus > 0 ? (unsigned int)cpus * 2 : 4; + } + if (nr_procs < 2) + nr_procs =3D 2; + + huge_page_size =3D default_huge_page_size(); + if (!huge_page_size) + ksft_exit_skip("no hugetlbfs / huge page size available\n"); + + /* + * Both modes fault pages in (functional_check touches every page it + * maps, and --trigger's workers fault the ranges they map), so the + * whole file may become resident; require that many *free* huge pages, + * not just reservations. + */ + if (hugetlb_free_default_pages() < file_pages) + ksft_exit_skip("need %lu free huge pages, have %lu (set nr_hugepages)\n", + file_pages, hugetlb_free_default_pages()); + + memfd =3D sys_memfd_create("hugetlb_region_cache_race", + MFD_HUGETLB | + (__builtin_ctzl(huge_page_size) << MFD_HUGE_SHIFT)); + if (memfd < 0) + ksft_exit_skip("memfd_create(MFD_HUGETLB): %s\n", + strerror(errno)); + if (ftruncate(memfd, file_pages * huge_page_size)) { + close(memfd); + ksft_exit_fail_msg("ftruncate: %s\n", strerror(errno)); + } + + if (trigger) + ret =3D run_trigger(); + else + ret =3D functional_check(); + + close(memfd); + + if (ret) + ksft_test_result_fail("hugetlb region_cache race check\n"); + else if (trigger) + ksft_test_result_pass("survived concurrent region_cache churn\n"); + else + ksft_test_result_pass("multi-entry region_cache refill works\n"); + + ksft_finished(); +} diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/self= tests/mm/run_vmtests.sh index 8c296dedf047..0cb857056915 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -267,6 +267,7 @@ CATEGORY=3D"hugetlb" run_test ./hugetlb-madvise CATEGORY=3D"hugetlb" run_test ./hugetlb_dio CATEGORY=3D"hugetlb" run_test ./hugetlb_fault_after_madv CATEGORY=3D"hugetlb" run_test ./hugetlb_madv_vs_map +CATEGORY=3D"hugetlb" run_test ./hugetlb_region_cache_race =20 if test_selected "hugetlb"; then echo "NOTE: These hugetlb tests provide minimal coverage. Use" | tap_p= refix --=20 2.55.0.122.gf85a7e6620