From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.openvz.org (mail.openvz.org [69.168.225.77]) by lore.virtuozzo.com (Postfix) with ESMTPS id 3451F80CB2 for ; Wed, 28 Oct 2026 12:23:49 +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 69SCMOPH019881; Wed, 28 Oct 2026 15:22:25 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 69SCMOPH019881 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="mHci1qg2" Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 69SCMLQO019869 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Wed, 28 Oct 2026 15:22:22 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 69SCMLQO019869 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-48c4445512dso821297f8f.2 for ; Wed, 28 Oct 2026 05:22:22 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvByTdaQO3dpYqDxuEW/yi1nWL8Wl2pdGZdABfh7MMepIdinqKSONY9QjEx7E16h1x/QA86sQzg==@openvz.org X-Gm-Message-State: AFq9FYIMRtmVrYni2ndOrNmowGdnQ53sywAUH2Fq1cH2hgbaE8D2dbyw 2L/jr/Xpz6WSnAeTjtdOUFmLGRUz9tEEi4AqSZsuOd8j7i8kbE7NCQuK4fxY3XitregIetXFd4d ZPlc8UUKQMAtaPuo7CNi/rfbwwn6P5+ATq3ETZ1BIzNZBNqJLbkSbKA== X-Gm-Gg: AYBFou2CCV3zqnPN1BKKrSW7Zd5HQUQegsehcgDjYUp85ttHaz0bRFBh/0Xyj1z9uCG JEk+/r2xmHSmbYNqlGH+G/p8VR7MMe8SPzVdz8ZQCU3pUy0qzGkQdG+prnUaIvBPfYA6EaZL65Q QRfPldaEQ5xBlcwD3qEfny8OkveC4RXNUSPk9Sf3+HChmZXMxk+ZydqQnmZsOO3H5OBLjA8lyKf ifrI4BBlDjXm3J+6srmO6BFw3U1uXieStBnxwCqOP5/lHAvsdcGRYK+O5Zp19NmoYdb5kwiIIBk 7bPj7TEV/dQJrZGpdgVhK5lIT/TIrBaPMTrPACdUbeaypIAejnj3osDHV8nJfmv2braNN/edOcW lOc5lnFUJkwNSMBLsQg== X-Received: by 2002:a05:6000:240f:b0:48e:60bf:4177 with SMTP id ffacd0b85a97d-48e60bf43demr2763199f8f.9.1793190141588; Wed, 28 Oct 2026 05:22:21 -0700 (PDT) X-Received: by 2002:a05:6000:240f:b0:48e:60bf:4177 with SMTP id ffacd0b85a97d-48e60bf43demr2763130f8f.9.1793190141010; Wed, 28 Oct 2026 05:22:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1793190141; cv=none; d=google.com; s=arc-20260327; b=M2YTcGVYA720U9deizA7b/GeqTb0AGD5m2cbpuYFCRN+GlCOiYhh+7AWKTWW3S7qjG 9A7kDlFnmJbmWhjefshlR6FK+aR26OXuZGRDD3UrTbvHi9BYpz4PQSh9YTh/zYPEj53o T8MpJRZcU9VP/5WG0VSpE+Jp3U0pgBKcPeODJ2nYbl3nC/2zywcn8PvWy0Stz8ARys3M i9i1WUNQr877IYUj0Cwu7YaSWhVPY1/lJpb/tGwc9n7v+z4xP1m0zdoPOGqo8WN58gl7 7ugyvfH1cuXuSHY6bP6H8ndSlSDjk4cLCR2WM116WnosOaX8NA6bD7LtaeLF5oKkL31b f7rw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=cc:to:content-transfer-encoding:mime-version:message-id:date :subject:from:dkim-signature; bh=T9w0h6B7jHJP2CvgKMQ9upQjcF3IAOiFugpX7kksiz4=; fh=XcqC0Cib/C4XsQyLUc3b6E9Ii37Wk0LS3yBNHj5szHI=; b=J2ePf04r24FOPLasGo3nqia6d95F8VCeCUraQ2NiwfwQIixwjXIomSJHR3HVvMag/T CRDpOSrT0NfXY77H9uVRbHoOZAuJ0AnfnlWIWUJrsktjRh0COK1+keDSheGfktXmuRMt xdRdjHyCUTaigpngFUWP+Hfi0yyflorYkIJrm0L/32K+F2VuluyJ3zrvtNrOFOM6lpCc 2SU9S47ZxPSweRDuw/fLpRZSw/XrvbkFryJKQ4hq+YIbYCWaaCvivPGUd9xRroZENWp9 eBrPxpEZcZ24fvAsEBA1IY1hUngKT+nkT0Lq7yqZeLVa/UqYCoy+zXpEAk5nuC//I8iP dcug==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=mHci1qg2; 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-48e3ecf3e34si26621839f8f.217.2026.10.28.05.22.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Oct 2026 05:22:20 -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=mHci1qg2; 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=Content-Type:MIME-Version:Message-Id:Date:Subject :From; bh=T9w0h6B7jHJP2CvgKMQ9upQjcF3IAOiFugpX7kksiz4=; b=mHci1qg2S/KnIsEnvG9 mfZtoT4KtcBOBF2aBhQvytp+RU2ehgH15OTCIrqGISLEH5NTEvF584UNEdNSyXMrZlnSUSuDEw9qA wUmZc1KrgsfiCxGB6fcxajueyIkJYMIyiQQZwvvfiGB6Z84dAnCRuw6Du+Wnv2xvPgNgTmZ5jIkAU lxMRxDJuOD0U6igY3Hw6Slj/QfAl0lMiETfCFsG9eJOa965R5dTJwFAGm5E1+L2SYj4ZBdLXkDv2W pfYxx2J1prqAVOp4mXrHMUVaDLPsc/eW4JJDQHb9joJDXuIQ2yEHdeO6Mk1qcaypAnOKHx5j4/xNT CktuwVA71InJ8EQ==; 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 1xM2bq-007ETm-0h; Wed, 28 Oct 2026 13:22:19 +0100 From: Konstantin Khorenko Date: Wed, 28 Oct 2026 13:22:16 +0100 Message-Id: <20261028-b4-prep-khorenko-vstor-151607-numa-migrate-order-v1-0-268336526677@virtuozzo.com> MIME-Version: 1.0 X-B4-Tracking: v=1; b=H4sIAPjo4WoC/yVNSw6CMBC9ipm103QqVPQqxkWB0VZjS6ZAiMa7W 2T3/u8DmSVwhvPuA8JzyCHFQmi/g867eGcMfeFgtLGkTYNthYPwgE+fhOMz4ZzHJEg1WX3EOL0 cvsJd3MiYpGfBig/O2so1p76CMlvat7D8Ly/gu4CNIrhuRp7aB3fjerhGW5cZW3Gx86u0IRRPG q0iozQaIlUbRcoYtaj5XZw0v+H7/QFYzq+y2QAAAA== X-Change-ID: 20261028-b4-prep-khorenko-vstor-151607-numa-migrate-order-4e3a664a89d4 To: Pavel Tikhomirov X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=6666; i=khorenko@virtuozzo.com; h=from:subject:message-id; bh=A+qPfTB3jLubVCtubwpszVt3U8sTecRFBmQqlY384uc=; b=owEBbQKS/ZANAwAKAVGWCkf5YVwqAcsmYgBq4ej7fJ1v/3QN6xlO0V2A6n2h/+Ff8luPwqfkD x2OW0DCo4CJAjMEAAEKAB0WIQRWD23IPcXT0GO9CCxRlgpH+WFcKgUCauHo+wAKCRBRlgpH+WFc KiXFD/wObZ9LjmaecyWHSooAPOYp27lICsINl+EjZvzf0acIOPqPcE7hiawhp8KAsv8jam0Sp0K l301qu3+vBxIgxX77e8IUdqOLK2SPgGeuYO5we6RXuwk9SNMgGObqJKscupD2V4m+VUE3NXvpxh 3NKnZX4Wpln0EZ8Paeoxu+kYR1pwEM051RJk1dEfNtlGx+dgiXsNoJ6/Sd8lVSR9/Oqzbzgti1/ l7uLsVeV4JFN0Dk466c8V3A9mnlYRQL9egzauoCPh6EWOYEZ+O2MI0/hUhOeetMe1WpiuuMKhxv 036iI+u6420VyedeFcVUWUFbNdvMXRPVH/Rxk2VhRGScAROcEXtgYk9DGW3iZL4Rdfbq9+/WO1V zKQ3MRC9PfU7GggTSMysIDsjtXyENR73vGdi6W1J2UAUxea7yeep84zq9yj/1ltkdBMzrr7RhOG wNrT2pItGYEOHiP/pJCtrrGOAzog034kU+tzsDPKOcEJqTaDBK6NaSdb/XJ0mywiuFewpTsIP+b gwn44eQWeRNpv8iToHyzgeTz2lcBDf3kklIcudkdUwgP8lhw6oCc0wd7d5EhtQ6sTx2XD8KbbGi 2pchKURe4APsicJk//LGK3sTajURPJVRow5e8MeqDxQyjrceK7H6jbmSgEImad/HIVBdfM/GXJW jFsb7fHQGahpNVA== 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 0/2] mm/memcontrol: numa_migrate destinations of the source folio order 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 memory.numa_migrate, our memcg file that vcmmd uses to move a cgroup's memory between NUMA nodes, allocates a 2 MB destination for every large folio it migrates. Page cache folios of a smaller order get a destination of the wrong size, and the page cache falls apart around it. Patch 1 is the fix, patch 2 a selftest that catches it without crashing the node. What the customer hit ===================== A two-node VMware host runs VMs with vcmmd's NUMA policy enabled, so every few minutes vcmmd writes memory.numa_migrate for a VM's cgroup. qemu writes its backup scratch file on NFS, and NFS sizes each page cache folio to the write, so that file is full of order-1 to order-5 folios. Closing the scratch file dies in nfs4_evict_inode(): kernel BUG at fs/inode.c:737! RIP: 0010:clear_inode+0x75/0x80 mapping->nrpages of the inode is negative, and the vmcore holds order-9 folios of that file with an index not aligned to 512, the refcount of a small folio, and whole xarray ranges of live folios that are no longer in the tree. Reads of the migrated ranges return garbage, so the backups taken on that host while the policy was active should be verified. The same crash was filed as VSTOR-151676. Where the 2 MB comes from ========================= memcg_numa_migrate_new_folio() is the migrate_pages() allocation callback. Its large folio branch dates from vz8 and copies the 4.18 new_page() in mm/mempolicy.c: if (thp_migration_supported() && PageTransHuge(page)) alloc ... HPAGE_PMD_ORDER A compound page on the LRU could only be a PMD-sized THP then, so the test implied the order. Upstream replaced that with folio_order() of the source when its allocators moved to folios, ffe06786b540 ("mm/migrate: Use a folio in alloc_migration_target()"). Our copy kept the shape, only PageTransHuge() became folio_test_large(), which is folio_test_head() and is true for any order from 1 up. NFS and XFS large folios, shmem and anonymous mTHP now all reach it. Why an oversized destination breaks the page cache ================================================== The two sides of the page cache size the folio differently. On insertion __folio_migrate_mapping() takes everything from the source: nr = folio_nr_pages(old), the xarray state at the old index with no xas_set_order(), newfolio->index = old->index, folio_ref_add(newfolio, nr), and xas_store() replaces exactly the slots the source occupied. folio_copy() copies the source pages only. So a 2 MB folio enters the cache as, say, a 4-page one: 4 xarray slots, 4 extra references, nrpages unchanged, 4 pages of valid data. Everything afterwards asks the folio itself, and it answers order 9: - page_cache_delete(): xas_set_order(index, 9) and nrpages -= 512. 512 slots wiped instead of 4, with the index rounded down to 512 so that other live folios lose their slots, and 512 subtracted instead of 4. That is the negative nrpages and the orphaned folios. - __remove_mapping(): expects 1 + 512 references and finds 1 + 4. Reclaim can never free the folio. - filemap_free_folio(): drops 512 references from a handful at eviction. The refcount goes negative and the folio leaks. - reads: folio_file_page() picks the page by its offset inside the folio, but only the first pages were copied. While the folio sits in the cache and is read through its own slots nothing is visible. It breaks the first time something applies folio_nr_pages() or folio_order() to it: invalidation, truncate, reclaim, inode eviction. On NFS cache invalidation is routine (an attribute change), so the bug shows up there instead of staying a silent 2 MB leak per folio. In short: inserted by the source size, removed by the destination size. That only works when the two match, which for a real THP they always did. A debug kernel says the same on the first migration, in mem_cgroup_migrate(): VM_BUG_ON_FOLIO(folio_nr_pages(old) != folio_nr_pages(new)) The patches =========== Patch 1 allocates the destination with folio_order() of the source, GFP_TRANSHUGE_LIGHT for large folios as before. The thp_migration_supported() test goes: migrate_pages() splits PMD-mappable folios itself when THP migration is unsupported, and every other large folio still needs a matching destination. Patch 2 adds tools/testing/selftests/ve/ve_numa_migrate_test.c. It binds a cgroup to one NUMA node, writes a file on a loop-mounted XFS image in 64K chunks so that the page cache holds large folios, migrates the cgroup to the other node through memory.numa_migrate and compares what reads back. memory.current cannot serve as the detector: mem_cgroup_migrate() only transfers the charge, whatever the size mismatch. On an unfixed kernel the comparison fails and the test leaves the image mounted on purpose, since evicting the inode would hit the BUG_ON. It needs root, two NUMA nodes with memory (numa=fake=2 is enough), cgroup2 with memory and cpuset, and mkfs.xfs; it skips otherwise. Testing ======= On a VM booted with numa=fake=2: - the reproducer (64K and 8K writes on XFS from a node-bound cgroup, memory.numa_migrate to the other node, unlink) kills the unfixed debug kernel on the VM_BUG_ON above and the release kernel in clear_inode(); with patch 1 migration succeeds and unlink and eviction complete; - the selftest passes on the fixed kernel and fails on the comparison on 22.11 without taking the node down. Other branches ============== The same patch applies as is to the 20.x branch (the customer's kernel) and is on pr/khorenko-VSTOR-151607-numa-migrate-order-20.x; the function is a plain callback, so it is a ReadyKernel candidate. vz9 carries the same PageTransHuge() code, but 5.14 has no non-PMD large folios on the LRU, so it is not reachable there. https://virtuozzo.atlassian.net/browse/VSTOR-151607 Assisted-by: LLM Signed-off-by: Konstantin Khorenko --- Konstantin Khorenko (2): mm/memcontrol: allocate numa_migrate targets of the source folio order selftests/ve: check memory.numa_migrate keeps the folio order mm/memcontrol.c | 11 +- tools/testing/selftests/ve/Makefile | 1 + tools/testing/selftests/ve/ve_numa_migrate_test.c | 304 ++++++++++++++++++++++ 3 files changed, 311 insertions(+), 5 deletions(-) --- base-commit: b499efa17aa9fb8f20512d1831d1cb61b22e60d3 change-id: 20261028-b4-prep-khorenko-vstor-151607-numa-migrate-order-4e3a664a89d4 Best regards, -- Konstantin Khorenko, Virtuozzo Linux Kernel Team _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel