From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.openvz.org (unknown [69.168.225.77]) by lore.virtuozzo.com (Postfix) with ESMTPS id E0EB48017D for ; Wed, 21 Oct 2026 16:59:54 +0000 (UTC) Received: from mail.openvz.org (localhost [127.0.0.1]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 69LGvdQR023019; Wed, 21 Oct 2026 19:57:39 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 69LGvdQR023019 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="Hk85qU3Z" Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 69LGvN7K022948 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Wed, 21 Oct 2026 19:57:23 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 69LGvN7K022948 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-48c415561aaso628994f8f.1 for ; Wed, 21 Oct 2026 09:57:23 -0700 (PDT) X-Gm-Message-State: AFq9FYK/nHSG2+q89wJQm7lAy2ubJEYPF5q1OXetX5QZWzCIMoxLrSIX fCSuHQTJG7oJtsuNkbYHOHW0hXNNJi9VZtTMK3QunuPbmQEY/XON+NhLmwBJQmv4JFynm3LclRT O7VzU9NlQTW+FFv6q5KDgeS+DtqPVaWz53V+btQdxT0/1WEQ75b6WeA== X-Gm-Gg: AYBFou0IRVUudC+d2+4yCb8Sr/Jdz0BjNogI9D7IU2R1Eg8cZj6heMuyd6EaWV+UlUA EoLd6KvrPPtS9zvA4CvhmzQYGuz4ekOEEy0cNaREm5o/ALA/lPQsAsp6u2sfzqDvZHeZaPsn/BF AAO5V8rzNU/q2C51xZzdqYGJLGvPSaFjQbKDCguoqgSOPHMqAHGYdj1PtrYeaeU47DdDO3rt9nP SDgE125H2IY/dDoCX1l3nxQIFAb4Eg0azPwTb1HaXKCwbrNPg6atOstFVcZr0/eurGxaORr5KZ6 2RzDRjjWYywb/2dWiD77UIesv1OA8PKqHBcaeFXMOiTumafiqr+osIgNI9fa/tDyUp5TvFQOMei 7+xB0UdtuPU00ve9Q X-Received: by 2002:a5d:5f06:0:b0:487:1575:ebef with SMTP id ffacd0b85a97d-48e264df44fmr5141360f8f.47.1792601842859; Wed, 21 Oct 2026 09:57:22 -0700 (PDT) X-Received: by 2002:a5d:5f06:0:b0:487:1575:ebef with SMTP id ffacd0b85a97d-48e264df44fmr5141315f8f.47.1792601842239; Wed, 21 Oct 2026 09:57:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1792601842; cv=none; d=google.com; s=arc-20260327; b=PjwQNipE6fCaDveH3ZuDy04/YOH1VBtTBb9t+jFfB9FD8pYUXAfsK7XDrtVSVLAa/R V3yVa3RdpRNtd0mKSMZSyxMPOAfmI3mZNeaKCE0tk9OplqQ6sN6NzZK6AOTkcrdn8P5u lvqpMMABmUgChpE2Xswr9BjLWtcy6RkX+POJfSjZRkozMey+PD9dJNSYDzwCI0IV9qul Re7kluo+Qdd1s/4fP8yB3zol17R/yBS9RB/I5VAtl7sKydQkJIt72qZFpl0+1FBhYt4X AmqMG4W0oPBXZTy0u1DBA/29cgkEU4Otw4Zj/jS/iBonN9U2GJUSBUgkrYd+cpIDyX2I WGtg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:dkim-signature; bh=xCODv7Iyk+RYze+uNPSiXSYris1vuxe04Zf/PUzWrKQ=; fh=ORqO450YHYjnAvQVnHrQRoSXc/Ljts4WdUx12SqEe+w=; b=rzUq7eD6Vgi1emQXDCSI6GBpcGtoFdyy004ndQz3uxZeG26cGFI8BQOamlRR0c7mjm ZDsjsg7XnPO9sDxRWXNeEVSLaE6Klb/gPjbaYXt+TB1rcfnIYxfkhRXCtRrTIA2/8tm4 sK2GL2IPyRDpKz6J9fu0OR/ZJh6aH8vDtbCpnV0H/jDdwt1jIB2aqlzF5Gqxyhp8U9rd 8zxMVTA3u+AUYHMaiQzS5j3CWPaElOqtL2g6VYfL/rf+I/AZsNBx7iKBcvkNH+PBYMNv iH1Blia1ak1yIa3dwh5+hCBhGyRYFcmDE6BPqT2IQ6SxRcDwlbvR5MNkx5/5nBH7n+rP WK6Q==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=Hk85qU3Z; spf=pass (google.com: domain of khorenko@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=khorenko@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com Received: from relay.virtuozzo.com (relay.virtuozzo.com. [130.117.225.111]) by mx.google.com with ESMTPS id ffacd0b85a97d-48e25855143si6087672f8f.172.2026.10.21.09.57.21 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 21 Oct 2026 09:57:21 -0700 (PDT) Received-SPF: pass (google.com: domain of khorenko@virtuozzo.com designates 130.117.225.111 as permitted sender) client-ip=130.117.225.111; Authentication-Results: mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=Hk85qU3Z; spf=pass (google.com: domain of khorenko@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=khorenko@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=Message-Id:Content-Type:MIME-Version:Subject:Date :From; bh=xCODv7Iyk+RYze+uNPSiXSYris1vuxe04Zf/PUzWrKQ=; b=Hk85qU3ZoSBlA6LyCcG WsLEwKBUNASm2Th4nVArv2ei01T6SE3NPkqORudnHBT0U/3aq7smlQU7tu5hsJXzMMTfhGBseSLvv 4fAA/wj98WhFwEfVMtxw/g5D3RoSeG1xJ7AV747wzO1JUbSO6tOCzAHv5a7MfaI4jihAM1Z+PRzgl BYCDtFsRVd7YKH8/LTsOR/MqmNSjgY4l9+xcdoLxjc56/wdjZspeHtib8oN5lzK7jj8ziuLsQ6c5H 3pdwI3vbW9X7I2U6hd++z6oWpTnR4522PB2M79Rar2FVN3t7wYyg8cUiJvR15Wzde/9O0jp8bFKKz GVayNojltipVZOw==; Received: from ch-demo-asa.virtuozzo.com ([130.117.225.8] helo=f0.sw.ru) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1xJZZJ-008y7H-27; Wed, 21 Oct 2026 18:57:20 +0200 From: Konstantin Khorenko Date: Wed, 21 Oct 2026 18:57:16 +0200 MIME-Version: 1.0 Message-Id: <20261021-b4-prep-khorenko-vstor-149847-5-doexec-selftests-v2-3-97dbb5c6e0ab@virtuozzo.com> References: <20261021-b4-prep-khorenko-vstor-149847-5-doexec-selftests-v2-0-97dbb5c6e0ab@virtuozzo.com> In-Reply-To: <20261021-b4-prep-khorenko-vstor-149847-5-doexec-selftests-v2-0-97dbb5c6e0ab@virtuozzo.com> To: Andrey Drobyshev , Pavel Tikhomirov , Vasileios Almpanis X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=6963; i=khorenko@virtuozzo.com; h=from:subject:message-id; bh=drjXnMrt50kD6m7Df/XkpKm9pioDe0VsNXMKIgytBPM=; b=owEBbQKS/ZANAwAKAVGWCkf5YVwqAcsmYgBq2O7uukx0kB9apdmtOVg1LJ3wgVy5CJRahZF1c 0UCu38NlDiJAjMEAAEKAB0WIQRWD23IPcXT0GO9CCxRlgpH+WFcKgUCatju7gAKCRBRlgpH+WFc KnERD/9QjnGv5SdN/myBoKDpXpoWpOE7o9OxNvwRXXUe5rs7xikqCoxCN2GuzL4gwXBNFVNUzD4 5qvJeMAOy8Mpys3nySG/es/J7fn8OLELqCBeHQcVu4wNUjx3Jmrcj4pz2qhC21uhaF+JMNaco8M RD9whVdBZ4mn3Hgeti0Vdq/Pr+90QYFekVU9LHhocGoXVfVOWGHiRPg0Qk6XMmxVsy1y03sGd8Q eLH8t7fTpqw8oiYwyIxjOT/6IYAy1c8DOLluKDiv9wzWsArbn1GUd3TmiOZv3w9ysJoZH8xEzXW OlrWx5h1vOl5waCp0CMCupElgnlFCFAsmnfpdr63HNvz+ycdjNT0Fg52E4LqQk2r++l205q1rtt RXf2oxdGBTk66ApWTZaxEipkuejDN0e0cmTW0Gl0PAclyNJD5ANYJ0mhOonVaQPWDKXhl/IWvHW GnVUam3AqNt+ydzSRiBP/VLVKQ6WJ76UsunPRklDBcc+IsfzkRNWvKmuR2Lhasy7RqJivRRT3J+ SdbINY/QIzQmUxA6koaFV6yzs7skwzVpBuf4i52TWsiPEoSB4zv7M3WD/5+qrpy9/lJEZdceZAQ r1QPVgzmxO0nBEOuRjLSTE1RtL7IiWJfivm+WaxazTlYfsPLq01RWrWDWHv3arkqmkZeYaCupGq bkYX8bkyqU3P9+A== X-Developer-Key: i=khorenko@virtuozzo.com; a=openpgp; fpr=560F6DC83DC5D3D063BD082C51960A47F9615C2A X-OZ-Fwd: true Cc: devel@openvz.org Subject: [Devel] [PATCH hci-8.1 v2 3/9] selftests/mm: cover large, swapped and partly marked THP ranges X-BeenThere: devel@openvz.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: OpenVZ development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: devel-bounces@openvz.org Errors-To: devel-bounces@openvz.org Add cases for the kinds of memory a preserved range can hold: - A 1 GB range touched every 2 MB, large enough for vma_dup() to split the copy into several padata jobs with CONFIG_PADATA. - A range pushed to swap with MADV_PAGEOUT, so that the copy takes swap entries and the new image swaps the pages back in. Skipped when none of the pages reaches swap. - A THP of which only the first half is marked, which splits its PMD and makes the copy batch PTEs of a large folio. Every page of the second half must be absent in the new image. Skipped unless smaps shows the range mapped by a THP before marking. Both base page cases tolerate EINVAL from MADV_NOHUGEPAGE, which a kernel without THP returns. https://virtuozzo.atlassian.net/browse/VSTOR-150234 Feature: oracle/mm: MADV_DOEXEC madvise() flag Assisted-by: LLM Signed-off-by: Konstantin Khorenko --- tools/testing/selftests/mm/doexec.c | 132 +++++++++++++++++++++++++++++++++--- 1 file changed, 124 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/mm/doexec.c b/tools/testing/selftests/mm/doexec.c index 261cc57afa1da..fbba87c7033ef 100644 --- a/tools/testing/selftests/mm/doexec.c +++ b/tools/testing/selftests/mm/doexec.c @@ -56,6 +56,9 @@ #ifndef MADV_WIPEONFORK #define MADV_WIPEONFORK 18 #endif +#ifndef MADV_PAGEOUT +#define MADV_PAGEOUT 21 +#endif /* The downstream ELF loader requires this opt-in in a PT_NOTE segment. */ asm(".pushsection .note.doexec,\"a\",%note\n" @@ -642,29 +645,35 @@ static int doexec_noexec(void) return ret; } -static bool smaps_has_flag(char *addr, const char *flag) +/* Copy the line of the smaps entry of the VMA at @addr that starts with @prefix. */ +static bool smaps_line(char *addr, const char *prefix, char *line, size_t len) { FILE *file = fopen("/proc/self/smaps", "r"); - char line[256], want[32]; bool in_vma = false, found = false; + char want[32]; if (!file) return false; snprintf(want, sizeof(want), "%lx-", (unsigned long)addr); - while (fgets(line, sizeof(line), file)) { + while (!found && fgets(line, len, file)) { char *space = strchr(line, ' '); - if (!space) - continue; - if (memchr(line, '-', space - line) && !memchr(line, ':', space - line)) + if (space && memchr(line, '-', space - line) && !memchr(line, ':', space - line)) in_vma = !strncmp(line, want, strlen(want)); - else if (in_vma && !strncmp(line, "VmFlags:", 8)) - found = strstr(line, flag) != NULL; + else if (in_vma) + found = !strncmp(line, prefix, strlen(prefix)); } fclose(file); return found; } +static bool smaps_has_flag(char *addr, const char *flag) +{ + char line[512]; + + return smaps_line(addr, "VmFlags:", line, sizeof(line)) && strstr(line, flag); +} + static int after_pfnmap_exec(char *bar, size_t size) { size_t page = sysconf(_SC_PAGESIZE), i; @@ -1716,6 +1725,109 @@ static int stack_overlap_exec(void) } #endif +/* Large enough for vma_dup() to split the copy between several threads. */ +static int sparse_exec(void) +{ + const size_t size = 1ul << 30, stride = 2ul << 20; + char *ram = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); + size_t i; + + if (ram == MAP_FAILED) + return KSFT_SKIP; + /* EINVAL: no THP support, the range is mapped with base pages anyway. */ + if (madvise(ram, size, MADV_NOHUGEPAGE) && errno != EINVAL) + return KSFT_FAIL; + for (i = 0; i < size; i += stride) + ram[i] = 0x31; + if (madvise(ram, size, MADV_DOEXEC)) + return unsupported(); + check_exec(ram, size, stride, false); + return KSFT_FAIL; +} + +static bool page_swapped(char *addr) +{ + size_t page = sysconf(_SC_PAGESIZE); + int fd = open("/proc/self/pagemap", O_RDONLY); + uint64_t entry = 0; + + if (fd < 0) + return false; + if (pread(fd, &entry, sizeof(entry), (uintptr_t)addr / page * sizeof(entry)) != + sizeof(entry)) + entry = 0; + close(fd); + return entry & (1ull << 62); +} + +/* Swap entries are copied, and the new image swaps the pages back in. */ +static int swapped_exec(void) +{ + size_t page = sysconf(_SC_PAGESIZE), size = 64 * page, i; + char *ram = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (ram == MAP_FAILED || + (madvise(ram, size, MADV_NOHUGEPAGE) && errno != EINVAL)) + return KSFT_FAIL; + memset(ram, 0x31, size); + if (madvise(ram, size, MADV_PAGEOUT)) + return KSFT_SKIP; + for (i = 0; i < size && !page_swapped(ram + i); i += page) + ; + if (i == size) + return KSFT_SKIP; + if (madvise(ram, size, MADV_DOEXEC)) + return unsupported(); + check_exec(ram, size, page, false); + return KSFT_FAIL; +} + +static unsigned long smaps_kb(char *addr, const char *field) +{ + char line[256]; + + if (!smaps_line(addr, field, line, sizeof(line))) + return 0; + return strtoul(line + strlen(field), NULL, 10); +} + +/* Marking half of a THP splits its PMD; the PTE-mapped half carries over. */ +static int thp_half_exec(void) +{ + size_t size = huge_page_size(); + char *area, *ram; + + if (!size) + return KSFT_SKIP; + area = mmap(NULL, 2 * size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (area == MAP_FAILED) + return KSFT_FAIL; + ram = (char *)(((uintptr_t)area + size - 1) & ~(size - 1)); + if (madvise(ram, size, MADV_HUGEPAGE)) + return KSFT_SKIP; + memset(ram, 0x31, size); + madvise(ram, size, MADV_COLLAPSE); + if (smaps_kb(ram, "AnonHugePages:") < size >> 10) + return KSFT_SKIP; + if (madvise(ram, size / 2, MADV_DOEXEC)) + return unsupported(); + exec_mode("/proc/self/exe", "--thp-half", ram, size); + return KSFT_FAIL; +} + +static int after_thp_half(char *ram, size_t size) +{ + size_t page = sysconf(_SC_PAGESIZE), off; + + for (off = size / 2; off < size; off += page) + if (range_mapped(ram + off, page)) + return fail("unmarked half preserved"); + return check_contents(ram, size / 2, 0x31); +} + struct after_mode { const char *mode; int (*fn)(char *ram, size_t size); @@ -1731,6 +1843,7 @@ static const struct after_mode after_modes[] = { { "--wipeonfork", after_wipeonfork }, { "--no-uffd", after_no_uffd }, { "--mempolicy", after_mempolicy }, + { "--thp-half", after_thp_half }, }; struct more_case { @@ -1754,6 +1867,9 @@ static const struct more_case more_cases[] = { { "opt-in note not in the last PT_NOTE: preserved", note_not_last_exec }, { "malformed opt-in note not in the last PT_NOTE: skipped", bad_note_not_last_exec }, { "preserved range under the new stack: exec kills the task", stack_overlap_exec }, + { "1 GB sparse range: preserved", sparse_exec }, + { "swapped out pages: preserved", swapped_exec }, + { "half of a THP: preserved", thp_half_exec }, }; int main(int argc, char **argv) -- 2.43.0 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel