From nobody Mon Jun 8 08:32:27 2026 Received: from mail-qv1-f53.google.com (mail-qv1-f53.google.com [209.85.219.53]) (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 4941E3D7D8D for ; Fri, 5 Jun 2026 03:32:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630373; cv=none; b=APstAapNB1+u31WgeydjJW7M9vKRXWSodLfTZEv8KHZB6aAlr6VTdCYRwNnmaONc4cns4kmNET2W7GXCRw/8ol3RMlKSTyEuiWyGlAHLPmnPWIvns+OW++hDAbAq5IEzA0DXfP2yhu/fYy+E/qOZGPgmukiOC3MIvkJ9ps0C1Uo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630373; c=relaxed/simple; bh=ft+wyW4GqM/deZoY1vJq5/OZpWt7HwaEkyGNLoOUcic=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XIJ5OrBHreB8n2abE1viVQ48MsfhXEGcTunL2eQrWDzq2ubS04GCkT/GBqKqXJeNY8IvwBNWiI5KzI+pfwu3eeRKGDhF4LO9s7kl6HGzZWaHFYHOosYSGZDSbAF3MS1V1w1fwCwLMbVsPzAwINWRzQB31lhHozLXtKBGsW3rYh4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com; spf=pass smtp.mailfrom=soleen.com; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b=EpYEa1eU; arc=none smtp.client-ip=209.85.219.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=soleen.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b="EpYEa1eU" Received: by mail-qv1-f53.google.com with SMTP id 6a1803df08f44-8ce0f17a69cso10268876d6.0 for ; Thu, 04 Jun 2026 20:32:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1780630369; x=1781235169; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=nDO8BVEQ+LamNUz1+nh7qBThLycTY6eROvRfwZKn/hY=; b=EpYEa1eUvroW4xdOjlSWqVDzgMV3BttJaPzEaExgr3yPuFWJMrkee90zRMF7d+1Fj9 spipmIgJ7BpFrQQa1DzapHZwMhwVnSMT35dH9eGPQYTE5T/QkmIbyH+4w1jhu+sjxT5w Mh6oek5VgHk37jbnnlANI4m2lSO9emv+Kxf/+Z+hXLkmBxWBZ4yWP6xSFu7yxOqU247c UyxZuJljgql4CVL5ZXG9IMzxHpOvfzSVKUxyyqsPcJYSqA/kOYJ8lkZ6kY1fVkkg+TVL 1bzQ7jV3fx8Heo5sDkpnC9ozOQ1WKbcaTAY2fxmmiG+OkliMVJ2G5dXTjvtFGo6HnIaO Ix9w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780630369; x=1781235169; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=nDO8BVEQ+LamNUz1+nh7qBThLycTY6eROvRfwZKn/hY=; b=gNEpMhn0VDdo6GuN2JhnkHOObGhvXLev55IMmXEV2StRWve6fiFKzHMVAOyDPlgPBZ a5FT9V56bzHcBaWNiHYVe6VcuVgiitc7d97g3kHiYwiV82rugyGvbespE/wJNcKQYKIz BQrzjxMOgT7p2r3g4vSoDDbPEFECYAwNS38zYQaOFJ+KigsHcyiaV9mWNxuJe0j3FpgK qo3QsEQz0ZeRNW0qGOSDzM0FJJ7n40N39fgs1OyeuprglrA8Frww97jOQpc51hglfHGH aOmTRz0SiEblKBYnOVbkKF0ZVYXHAlcEU4KiaZR3qYXArGY9MGbBqOU9ROYMCGuuVOY3 QW6w== X-Forwarded-Encrypted: i=1; AFNElJ+s13RAjhM/u87p/NGxmyp2qWKp7zAj1cFy3Bwp+U/VVGEFSHXOo31a33rxFytaVGyBxWyy/x3r6XCh6VM=@vger.kernel.org X-Gm-Message-State: AOJu0Yzkmh8iktv82h9NnDJu3c6BI0+UcJ4G+cssfaZiBswT5pvkwRU6 PrXcZVXuEOLPmeCILQf4sJBDJ45jstnC270XWiSbz5TGovIF2Cwh/w8amvOlRfV4/9o= X-Gm-Gg: Acq92OEK5E1tD92mdQvL9vSHGVHIGcFXK0GokfxjZR7fV477ytF1//srl7FkKEEptpY q4aoYeh01vNpwzwcLJnRx+f9tgEWeQHnBNFJYoLWEdRRnJ/oL6p5/FUpcxse6YT3dd2MmNlrCwO DJgeIZzX5oRDIDI+EMk/gjxU9FMEkW3mZl82WYdluT1PVWiU6oYFNGrrOxlxJlRBGJr/XaS5Q5K utdpKGNG7/icZJJzC3zBjrobwhYZcgwsZLT6nbEZgLeqp71dSENpnxGTJIB8j3pSNWhgNeQ7xwu bQ6vGiwyT6b47cuoPXTYB4D7WbPsozSou9m2RzkDZbYWx8e4yShG2wj5lVtxRo1kgnTwQlSBzUZ z2gnUlpqhmpBrA6fxBG1E/qKKSv/m24idck3pAp2Fu8z5nTIYbzqvoxLIqfppsy3URk9hN1xnB8 zjvyeBolABl6Ree1rdXeioof8RDdCEsFY/jBCxipLw4NutJ2GBOK3GFU0D7iXhBw== X-Received: by 2002:a05:6214:6017:b0:8cc:cf1e:1fde with SMTP id 6a1803df08f44-8cee611fb96mr32665706d6.26.1780630369028; Thu, 04 Jun 2026 20:32:49 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8ceccdb9fc0sm70805926d6.17.2026.06.04.20.32.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jun 2026 20:32:48 -0700 (PDT) From: Pasha Tatashin To: linux-kselftest@vger.kernel.org, rppt@kernel.org, shuah@kernel.org, akpm@linux-foundation.org, linux-mm@kvack.org, skhan@linuxfoundation.org, linux-doc@vger.kernel.org, jasonmiu@google.com, linux-kernel@vger.kernel.org, corbet@lwn.net, ran.xiaokai@zte.com.cn, pasha.tatashin@soleen.com, kexec@lists.infradead.org, pratyush@kernel.org, graf@amazon.com Subject: [RFC v1 1/9] kho: split out radix tree tracker into kho_radix.c Date: Fri, 5 Jun 2026 03:32:27 +0000 Message-ID: <20260605033235.717351-2-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260605033235.717351-1-pasha.tatashin@soleen.com> References: <20260605033235.717351-1-pasha.tatashin@soleen.com> 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 Content-Type: text/plain; charset="utf-8" Move the radix tree tracker implementation from the core KHO code into its own dedicated file (kho_radix.c). This is a pure code movement patch; no logic or functional changes are introduced. Signed-off-by: Pasha Tatashin --- Documentation/core-api/kho/index.rst | 3 + kernel/liveupdate/Makefile | 6 +- kernel/liveupdate/kexec_handover.c | 273 ------------------------- kernel/liveupdate/kho_radix.c | 290 +++++++++++++++++++++++++++ 4 files changed, 298 insertions(+), 274 deletions(-) create mode 100644 kernel/liveupdate/kho_radix.c diff --git a/Documentation/core-api/kho/index.rst b/Documentation/core-api/= kho/index.rst index 320914a42178..a9892c671ec3 100644 --- a/Documentation/core-api/kho/index.rst +++ b/Documentation/core-api/kho/index.rst @@ -83,6 +83,9 @@ Public API .. kernel-doc:: kernel/liveupdate/kexec_handover.c :export: =20 +.. kernel-doc:: kernel/liveupdate/kho_radix.c + :export: + KHO Serialization Blocks API =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D =20 diff --git a/kernel/liveupdate/Makefile b/kernel/liveupdate/Makefile index eec9d3ae07eb..a3ee8a5c27a2 100644 --- a/kernel/liveupdate/Makefile +++ b/kernel/liveupdate/Makefile @@ -7,7 +7,11 @@ luo-y :=3D \ luo_flb.o \ luo_session.o =20 -obj-$(CONFIG_KEXEC_HANDOVER) +=3D kexec_handover.o +kho-y :=3D \ + kexec_handover.o \ + kho_radix.o + +obj-$(CONFIG_KEXEC_HANDOVER) +=3D kho.o obj-$(CONFIG_KEXEC_HANDOVER_DEBUG) +=3D kexec_handover_debug.o obj-$(CONFIG_KEXEC_HANDOVER_DEBUGFS) +=3D kexec_handover_debugfs.o =20 diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_h= andover.c index 4834a809985a..041efff7ca11 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -5,7 +5,6 @@ * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport * Copyright (C) 2025 Google LLC, Changyuan Lyu * Copyright (C) 2025 Pasha Tatashin - * Copyright (C) 2026 Google LLC, Jason Miu */ =20 #define pr_fmt(fmt) "KHO: " fmt @@ -84,278 +83,6 @@ static struct kho_out kho_out =3D { }, }; =20 -/** - * kho_radix_encode_key - Encodes a physical address and order into a radi= x key. - * @phys: The physical address of the page. - * @order: The order of the page. - * - * This function combines a page's physical address and its order into a - * single unsigned long, which is used as a key for all radix tree - * operations. - * - * Return: The encoded unsigned long radix key. - */ -static unsigned long kho_radix_encode_key(phys_addr_t phys, unsigned int o= rder) -{ - /* Order bits part */ - unsigned long h =3D 1UL << (KHO_ORDER_0_LOG2 - order); - /* Shifted physical address part */ - unsigned long l =3D phys >> (PAGE_SHIFT + order); - - return h | l; -} - -/** - * kho_radix_decode_key - Decodes a radix key back into a physical address= and order. - * @key: The unsigned long key to decode. - * @order: An output parameter, a pointer to an unsigned int where the dec= oded - * page order will be stored. - * - * This function reverses the encoding performed by kho_radix_encode_key(), - * extracting the original physical address and page order from a given ke= y. - * - * Return: The decoded physical address. - */ -static phys_addr_t kho_radix_decode_key(unsigned long key, unsigned int *o= rder) -{ - unsigned int order_bit =3D fls64(key); - phys_addr_t phys; - - /* order_bit is numbered starting at 1 from fls64 */ - *order =3D KHO_ORDER_0_LOG2 - order_bit + 1; - /* The order is discarded by the shift */ - phys =3D key << (PAGE_SHIFT + *order); - - return phys; -} - -static unsigned long kho_radix_get_bitmap_index(unsigned long key) -{ - return key % (1 << KHO_BITMAP_SIZE_LOG2); -} - -static unsigned long kho_radix_get_table_index(unsigned long key, - unsigned int level) -{ - int s; - - s =3D ((level - 1) * KHO_TABLE_SIZE_LOG2) + KHO_BITMAP_SIZE_LOG2; - return (key >> s) % (1 << KHO_TABLE_SIZE_LOG2); -} - -/** - * kho_radix_add_page - Marks a page as preserved in the radix tree. - * @tree: The KHO radix tree. - * @pfn: The page frame number of the page to preserve. - * @order: The order of the page. - * - * This function traverses the radix tree based on the key derived from @p= fn - * and @order. It sets the corresponding bit in the leaf bitmap to mark the - * page for preservation. If intermediate nodes do not exist along the pat= h, - * they are allocated and added to the tree. - * - * Return: 0 on success, or a negative error code on failure. - */ -int kho_radix_add_page(struct kho_radix_tree *tree, - unsigned long pfn, unsigned int order) -{ - /* Newly allocated nodes for error cleanup */ - struct kho_radix_node *intermediate_nodes[KHO_TREE_MAX_DEPTH] =3D { 0 }; - unsigned long key =3D kho_radix_encode_key(PFN_PHYS(pfn), order); - struct kho_radix_node *anchor_node =3D NULL; - struct kho_radix_node *node =3D tree->root; - struct kho_radix_node *new_node; - unsigned int i, idx, anchor_idx; - struct kho_radix_leaf *leaf; - int err =3D 0; - - if (WARN_ON_ONCE(!tree->root)) - return -EINVAL; - - might_sleep(); - - guard(mutex)(&tree->lock); - - /* Go from high levels to low levels */ - for (i =3D KHO_TREE_MAX_DEPTH - 1; i > 0; i--) { - idx =3D kho_radix_get_table_index(key, i); - - if (node->table[idx]) { - node =3D phys_to_virt(node->table[idx]); - continue; - } - - /* Next node is empty, create a new node for it */ - new_node =3D (struct kho_radix_node *)get_zeroed_page(GFP_KERNEL); - if (!new_node) { - err =3D -ENOMEM; - goto err_free_nodes; - } - - node->table[idx] =3D virt_to_phys(new_node); - - /* - * Capture the node where the new branch starts for cleanup - * if allocation fails. - */ - if (!anchor_node) { - anchor_node =3D node; - anchor_idx =3D idx; - } - intermediate_nodes[i] =3D new_node; - - node =3D new_node; - } - - /* Handle the leaf level bitmap (level 0) */ - idx =3D kho_radix_get_bitmap_index(key); - leaf =3D (struct kho_radix_leaf *)node; - __set_bit(idx, leaf->bitmap); - - return 0; - -err_free_nodes: - for (i =3D KHO_TREE_MAX_DEPTH - 1; i > 0; i--) { - if (intermediate_nodes[i]) - free_page((unsigned long)intermediate_nodes[i]); - } - if (anchor_node) - anchor_node->table[anchor_idx] =3D 0; - - return err; -} -EXPORT_SYMBOL_GPL(kho_radix_add_page); - -/** - * kho_radix_del_page - Removes a page's preservation status from the radi= x tree. - * @tree: The KHO radix tree. - * @pfn: The page frame number of the page to unpreserve. - * @order: The order of the page. - * - * This function traverses the radix tree and clears the bit corresponding= to - * the page, effectively removing its "preserved" status. It does not free - * the tree's intermediate nodes, even if they become empty. - */ -void kho_radix_del_page(struct kho_radix_tree *tree, unsigned long pfn, - unsigned int order) -{ - unsigned long key =3D kho_radix_encode_key(PFN_PHYS(pfn), order); - struct kho_radix_node *node =3D tree->root; - struct kho_radix_leaf *leaf; - unsigned int i, idx; - - if (WARN_ON_ONCE(!tree->root)) - return; - - might_sleep(); - - guard(mutex)(&tree->lock); - - /* Go from high levels to low levels */ - for (i =3D KHO_TREE_MAX_DEPTH - 1; i > 0; i--) { - idx =3D kho_radix_get_table_index(key, i); - - /* - * Attempting to delete a page that has not been preserved, - * return with a warning. - */ - if (WARN_ON(!node->table[idx])) - return; - - node =3D phys_to_virt(node->table[idx]); - } - - /* Handle the leaf level bitmap (level 0) */ - leaf =3D (struct kho_radix_leaf *)node; - idx =3D kho_radix_get_bitmap_index(key); - __clear_bit(idx, leaf->bitmap); -} -EXPORT_SYMBOL_GPL(kho_radix_del_page); - -static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, - unsigned long key, - kho_radix_tree_walk_callback_t cb) -{ - unsigned long *bitmap =3D (unsigned long *)leaf; - unsigned int order; - phys_addr_t phys; - unsigned int i; - int err; - - for_each_set_bit(i, bitmap, PAGE_SIZE * BITS_PER_BYTE) { - phys =3D kho_radix_decode_key(key | i, &order); - err =3D cb(phys, order); - if (err) - return err; - } - - return 0; -} - -static int __kho_radix_walk_tree(struct kho_radix_node *root, - unsigned int level, unsigned long start, - kho_radix_tree_walk_callback_t cb) -{ - struct kho_radix_node *node; - struct kho_radix_leaf *leaf; - unsigned long key, i; - unsigned int shift; - int err; - - for (i =3D 0; i < PAGE_SIZE / sizeof(phys_addr_t); i++) { - if (!root->table[i]) - continue; - - shift =3D ((level - 1) * KHO_TABLE_SIZE_LOG2) + - KHO_BITMAP_SIZE_LOG2; - key =3D start | (i << shift); - - node =3D phys_to_virt(root->table[i]); - - if (level =3D=3D 1) { - /* - * we are at level 1, - * node is pointing to the level 0 bitmap. - */ - leaf =3D (struct kho_radix_leaf *)node; - err =3D kho_radix_walk_leaf(leaf, key, cb); - } else { - err =3D __kho_radix_walk_tree(node, level - 1, - key, cb); - } - - if (err) - return err; - } - - return 0; -} - -/** - * kho_radix_walk_tree - Traverses the radix tree and calls a callback for= each preserved page. - * @tree: A pointer to the KHO radix tree to walk. - * @cb: A callback function of type kho_radix_tree_walk_callback_t that wi= ll be - * invoked for each preserved page found in the tree. The callback re= ceives - * the physical address and order of the preserved page. - * - * This function walks the radix tree, searching from the specified top le= vel - * down to the lowest level (level 0). For each preserved page found, it i= nvokes - * the provided callback, passing the page's physical address and order. - * - * Return: 0 if the walk completed the specified tree, or the non-zero ret= urn - * value from the callback that stopped the walk. - */ -int kho_radix_walk_tree(struct kho_radix_tree *tree, - kho_radix_tree_walk_callback_t cb) -{ - if (WARN_ON_ONCE(!tree->root)) - return -EINVAL; - - guard(mutex)(&tree->lock); - - return __kho_radix_walk_tree(tree->root, KHO_TREE_MAX_DEPTH - 1, 0, cb); -} -EXPORT_SYMBOL_GPL(kho_radix_walk_tree); =20 /* For physically contiguous 0-order pages. */ static void kho_init_pages(struct page *page, unsigned long nr_pages) diff --git a/kernel/liveupdate/kho_radix.c b/kernel/liveupdate/kho_radix.c new file mode 100644 index 000000000000..c836783a1376 --- /dev/null +++ b/kernel/liveupdate/kho_radix.c @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * kho_radix.c - KHO radix tree tracker for preserved memory pages + * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport + * Copyright (C) 2025 Pasha Tatashin + * Copyright (C) 2026 Google LLC, Jason Miu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * kho_radix_encode_key - Encodes a physical address and order into a radi= x key. + * @phys: The physical address of the page. + * @order: The order of the page. + * + * This function combines a page's physical address and its order into a + * single unsigned long, which is used as a key for all radix tree + * operations. + * + * Return: The encoded unsigned long radix key. + */ +static unsigned long kho_radix_encode_key(phys_addr_t phys, unsigned int o= rder) +{ + /* Order bits part */ + unsigned long h =3D 1UL << (KHO_ORDER_0_LOG2 - order); + /* Shifted physical address part */ + unsigned long l =3D phys >> (PAGE_SHIFT + order); + + return h | l; +} + +/** + * kho_radix_decode_key - Decodes a radix key back into a physical address= and order. + * @key: The unsigned long key to decode. + * @order: An output parameter, a pointer to an unsigned int where the dec= oded + * page order will be stored. + * + * This function reverses the encoding performed by kho_radix_encode_key(), + * extracting the original physical address and page order from a given ke= y. + * + * Return: The decoded physical address. + */ +static phys_addr_t kho_radix_decode_key(unsigned long key, unsigned int *o= rder) +{ + unsigned int order_bit =3D fls64(key); + phys_addr_t phys; + + /* order_bit is numbered starting at 1 from fls64 */ + *order =3D KHO_ORDER_0_LOG2 - order_bit + 1; + /* The order is discarded by the shift */ + phys =3D key << (PAGE_SHIFT + *order); + + return phys; +} + +static unsigned long kho_radix_get_bitmap_index(unsigned long key) +{ + return key % (1 << KHO_BITMAP_SIZE_LOG2); +} + +static unsigned long kho_radix_get_table_index(unsigned long key, + unsigned int level) +{ + int s; + + s =3D ((level - 1) * KHO_TABLE_SIZE_LOG2) + KHO_BITMAP_SIZE_LOG2; + return (key >> s) % (1 << KHO_TABLE_SIZE_LOG2); +} + +/** + * kho_radix_add_page - Marks a page as preserved in the radix tree. + * @tree: The KHO radix tree. + * @pfn: The page frame number of the page to preserve. + * @order: The order of the page. + * + * This function traverses the radix tree based on the key derived from @p= fn + * and @order. It sets the corresponding bit in the leaf bitmap to mark the + * page for preservation. If intermediate nodes do not exist along the pat= h, + * they are allocated and added to the tree. + * + * Return: 0 on success, or a negative error code on failure. + */ +int kho_radix_add_page(struct kho_radix_tree *tree, + unsigned long pfn, unsigned int order) +{ + /* Newly allocated nodes for error cleanup */ + struct kho_radix_node *intermediate_nodes[KHO_TREE_MAX_DEPTH] =3D { 0 }; + unsigned long key =3D kho_radix_encode_key(PFN_PHYS(pfn), order); + struct kho_radix_node *anchor_node =3D NULL; + struct kho_radix_node *node =3D tree->root; + struct kho_radix_node *new_node; + unsigned int i, idx, anchor_idx; + struct kho_radix_leaf *leaf; + int err =3D 0; + + if (WARN_ON_ONCE(!tree->root)) + return -EINVAL; + + might_sleep(); + + guard(mutex)(&tree->lock); + + /* Go from high levels to low levels */ + for (i =3D KHO_TREE_MAX_DEPTH - 1; i > 0; i--) { + idx =3D kho_radix_get_table_index(key, i); + + if (node->table[idx]) { + node =3D phys_to_virt(node->table[idx]); + continue; + } + + /* Next node is empty, create a new node for it */ + new_node =3D (struct kho_radix_node *)get_zeroed_page(GFP_KERNEL); + if (!new_node) { + err =3D -ENOMEM; + goto err_free_nodes; + } + + node->table[idx] =3D virt_to_phys(new_node); + + /* + * Capture the node where the new branch starts for cleanup + * if allocation fails. + */ + if (!anchor_node) { + anchor_node =3D node; + anchor_idx =3D idx; + } + intermediate_nodes[i] =3D new_node; + + node =3D new_node; + } + + /* Handle the leaf level bitmap (level 0) */ + idx =3D kho_radix_get_bitmap_index(key); + leaf =3D (struct kho_radix_leaf *)node; + __set_bit(idx, leaf->bitmap); + + return 0; + +err_free_nodes: + for (i =3D KHO_TREE_MAX_DEPTH - 1; i > 0; i--) { + if (intermediate_nodes[i]) + free_page((unsigned long)intermediate_nodes[i]); + } + if (anchor_node) + anchor_node->table[anchor_idx] =3D 0; + + return err; +} +EXPORT_SYMBOL_GPL(kho_radix_add_page); + +/** + * kho_radix_del_page - Removes a page's preservation status from the radi= x tree. + * @tree: The KHO radix tree. + * @pfn: The page frame number of the page to unpreserve. + * @order: The order of the page. + * + * This function traverses the radix tree and clears the bit corresponding= to + * the page, effectively removing its "preserved" status. It does not free + * the tree's intermediate nodes, even if they become empty. + */ +void kho_radix_del_page(struct kho_radix_tree *tree, unsigned long pfn, + unsigned int order) +{ + unsigned long key =3D kho_radix_encode_key(PFN_PHYS(pfn), order); + struct kho_radix_node *node =3D tree->root; + struct kho_radix_leaf *leaf; + unsigned int i, idx; + + if (WARN_ON_ONCE(!tree->root)) + return; + + might_sleep(); + + guard(mutex)(&tree->lock); + + /* Go from high levels to low levels */ + for (i =3D KHO_TREE_MAX_DEPTH - 1; i > 0; i--) { + idx =3D kho_radix_get_table_index(key, i); + + /* + * Attempting to delete a page that has not been preserved, + * return with a warning. + */ + if (WARN_ON(!node->table[idx])) + return; + + node =3D phys_to_virt(node->table[idx]); + } + + /* Handle the leaf level bitmap (level 0) */ + leaf =3D (struct kho_radix_leaf *)node; + idx =3D kho_radix_get_bitmap_index(key); + __clear_bit(idx, leaf->bitmap); +} +EXPORT_SYMBOL_GPL(kho_radix_del_page); + +static int kho_radix_walk_leaf(struct kho_radix_leaf *leaf, + unsigned long key, + kho_radix_tree_walk_callback_t cb) +{ + unsigned long *bitmap =3D (unsigned long *)leaf; + unsigned int order; + phys_addr_t phys; + unsigned int i; + int err; + + for_each_set_bit(i, bitmap, PAGE_SIZE * BITS_PER_BYTE) { + phys =3D kho_radix_decode_key(key | i, &order); + err =3D cb(phys, order); + if (err) + return err; + } + + return 0; +} + +static int __kho_radix_walk_tree(struct kho_radix_node *root, + unsigned int level, unsigned long start, + kho_radix_tree_walk_callback_t cb) +{ + struct kho_radix_node *node; + struct kho_radix_leaf *leaf; + unsigned long key, i; + unsigned int shift; + int err; + + for (i =3D 0; i < PAGE_SIZE / sizeof(phys_addr_t); i++) { + if (!root->table[i]) + continue; + + shift =3D ((level - 1) * KHO_TABLE_SIZE_LOG2) + + KHO_BITMAP_SIZE_LOG2; + key =3D start | (i << shift); + + node =3D phys_to_virt(root->table[i]); + + if (level =3D=3D 1) { + /* + * we are at level 1, + * node is pointing to the level 0 bitmap. + */ + leaf =3D (struct kho_radix_leaf *)node; + err =3D kho_radix_walk_leaf(leaf, key, cb); + } else { + err =3D __kho_radix_walk_tree(node, level - 1, + key, cb); + } + + if (err) + return err; + } + + return 0; +} + +/** + * kho_radix_walk_tree - Traverses the radix tree and calls a callback for= each preserved page. + * @tree: A pointer to the KHO radix tree to walk. + * @cb: A callback function of type kho_radix_tree_walk_callback_t that wi= ll be + * invoked for each preserved page found in the tree. The callback re= ceives + * the physical address and order of the preserved page. + * + * This function walks the radix tree, searching from the specified top le= vel + * down to the lowest level (level 0). For each preserved page found, it i= nvokes + * the provided callback, passing the page's physical address and order. + * + * Return: 0 if the walk completed the specified tree, or the non-zero ret= urn + * value from the callback that stopped the walk. + */ +int kho_radix_walk_tree(struct kho_radix_tree *tree, + kho_radix_tree_walk_callback_t cb) +{ + if (WARN_ON_ONCE(!tree->root)) + return -EINVAL; + + guard(mutex)(&tree->lock); + + return __kho_radix_walk_tree(tree->root, KHO_TREE_MAX_DEPTH - 1, 0, cb); +} +EXPORT_SYMBOL_GPL(kho_radix_walk_tree); --=20 2.53.0 From nobody Mon Jun 8 08:32:27 2026 Received: from mail-qk1-f175.google.com (mail-qk1-f175.google.com [209.85.222.175]) (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 B73FD285CB3 for ; Fri, 5 Jun 2026 03:33:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630383; cv=none; b=QCrZMkQR71cv2JwEZEmb8ItWURvJf3kBOUaWyqheTFKXvTMLHJtJjviv0vVxvCDbH3Vk55YAaXEtWlJnvoMsZobfkIxVMQn0a9RX8S4147GiCuzRdNPT89k7So6YTFBBc78hbUXSMnwce2sMz0XXnjyvUxY7dGcyE/OEHFhkhyQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630383; c=relaxed/simple; bh=rOeFjgPk4CSLdGSn9QYgjdyrytAmThRn/Tq/NmxTwLk=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=f+AjD5g6kL/rXtg7RCu0yD7YYlDBiLqj6t0A9htgpzSHxUb9XWPIDyPwN1rWrtUW00OxEB23nIWi9qx6D9LZlp4/oxlkKxHLtF4Qi/J9NN2ZTX/wo2oApmW0W5zc558pnWYmdN6bEeKU9Xnbk67GiyPpCMhvZodwmc0txaA0W2I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com; spf=pass smtp.mailfrom=soleen.com; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b=H54a2VnC; arc=none smtp.client-ip=209.85.222.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=soleen.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b="H54a2VnC" Received: by mail-qk1-f175.google.com with SMTP id af79cd13be357-9156ceb55ffso127653685a.0 for ; Thu, 04 Jun 2026 20:33:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1780630381; x=1781235181; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=CGemO6oM+fzlXtG0xc8ivWmdV7Y8sG7GsOK7Le1P9V4=; b=H54a2VnCcll/IkIjcldyF/LfJ0ciFsYvFXJ4yLzXqyyvWG42jhtx/FjFIz3UeO0d7b 1BcfRUs1JWWayUPW0PbbofKXK+ecm0mjlfQUqO0eU3fgAv+faCBCfW/3tgidIKJ7xcNq WJcJCSVMxrTdom7EgbaR2NnafZ2396p/AefXsTu9SHvcZaikuOdcQSJrr4QVYBWTuxZA hneDTQDjFRAUGDy2KRHzGfTCGmus1F8bdqzMAwq7vf2ze2fSNUIm62URkcXAo2UdVkuw 2UHj70IkQ4BhDxIJrYrviFtMWMQ6FvvoLZf/wxgp+FWjrcV0AWiIJ8qK1rIynXupBDuY 1byw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780630381; x=1781235181; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=CGemO6oM+fzlXtG0xc8ivWmdV7Y8sG7GsOK7Le1P9V4=; b=qH4BNWToOpcRbhbGDg2wUHDoLPgUBIuCnZsGg5GvZk7Bqn4HKOZnyEqFxi4lv7pyR+ RIRVmnE37WXkattsZTi3WLI2kRS4qJp7znFGzAzzxTLXd4KWvm+eiq1duKn/AUeOVma4 jJOIX5U9i/7nRyTqqu3InA+aENiB3X7qZxpQ9tHF7+jLitlC05KoS6Lam2Q5cJLDMDNi 29QB63RT7cnTu/8l3mCrMGNXnPv4MfYV58E/XuID6WyINTzK1xt18bsXLTACL9J35Gby X/qj//NrYt449wZSOhGr/nzR1ofyKmdv0h4oKa6zRZCz677iUw528v1qZyNK4iscPpjJ 2Ljg== X-Forwarded-Encrypted: i=1; AFNElJ+wHOSMNlhed8hwzQdD3t0slzMlmW+E7/DzxgmUqW/oXnkGYZ648rq6IO1h6/ETJp6G48rqYBNcwIvYWRk=@vger.kernel.org X-Gm-Message-State: AOJu0Yx6fPjOEHI/Z1BajDluFWGGnOo/UK7kM7UA//4y6yrwZLfb0DL/ wDLQw88Tc308rGiZ5PR+ZaY+3iPYQ7LO/tEh3oqBmwRRVeU1QDnhFopBtQTcZea93I0= X-Gm-Gg: Acq92OH3WpnSr3LbXaniTTgmf+E/F5fLFq1xbKJwBZfUIvh21lSrbs0WBL6jp/WE5Q8 5RzYPnjt+91opwA3owqLZeUWvzi4q5pqZeT4+BYUIDbnJHxTssHjDF9Mr72Bwu1CMIVAST/0Krt GMzQ+BajDd21kyR6sdeVFMHga5QTS2f24pC0vZiMDw946SkWF6UcoSGlBk5YkL1VzdBgYUvxuDH HKwp96QcWjp7rF6jSb58bxvbaXsb4At7EbwEKsObCdOcg7D6+RpmLaUCF6eMiE2pkWLJxtj7GuJ k93MCjNykPusifVO5dCOw1h4AnHRDzeFA1aKCS6edvupv+SdgPrOI0IlwgqOcL311bOAromS7+y NCMKw3/9ELpwCvGzm67nwZKEHtFSGhLl0PA2twOfgR0hFQ/4agsQ+7OL7YVpT37wVOm5KnbEbDM BHoYr8GjBQSyJJhfeyyh7TTkdDB8X91JEHqRhBw6ezHeQ9WSNQxKuBU4LbahjNAA== X-Received: by 2002:a05:620a:1709:b0:914:cc9d:e29 with SMTP id af79cd13be357-915a9cadf6fmr346442685a.21.1780630380676; Thu, 04 Jun 2026 20:33:00 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8ceccdb915csm70807166d6.14.2026.06.04.20.32.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jun 2026 20:33:00 -0700 (PDT) From: Pasha Tatashin To: linux-kselftest@vger.kernel.org, rppt@kernel.org, shuah@kernel.org, akpm@linux-foundation.org, linux-mm@kvack.org, skhan@linuxfoundation.org, linux-doc@vger.kernel.org, jasonmiu@google.com, linux-kernel@vger.kernel.org, corbet@lwn.net, ran.xiaokai@zte.com.cn, pasha.tatashin@soleen.com, kexec@lists.infradead.org, pratyush@kernel.org, graf@amazon.com Subject: [RFC v1 2/9] kho: split radix tree headers out of kexec_handover.h Date: Fri, 5 Jun 2026 03:32:28 +0000 Message-ID: <20260605033235.717351-3-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260605033235.717351-1-pasha.tatashin@soleen.com> References: <20260605033235.717351-1-pasha.tatashin@soleen.com> 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 Content-Type: text/plain; charset="utf-8" Split the radix tree tracker-related ABI definitions and header declarations out of the monolithic kexec_handover.h header into a dedicated header file (radix_tree.h). Additionally, rename kho_radix_tree.h to kho/radix_tree.h, organizing it within the existing kho directory structure as more KHO data structures are introduced. This is a pure code movement patch; no logic or functional changes are introduced. Signed-off-by: Pasha Tatashin --- Documentation/core-api/kho/abi.rst | 3 +- Documentation/core-api/kho/index.rst | 2 +- include/linux/kho/abi/kexec_handover.h | 114 --------------- include/linux/kho/abi/radix_tree.h | 131 ++++++++++++++++++ .../{kho_radix_tree.h =3D> kho/radix_tree.h} | 5 +- kernel/liveupdate/kexec_handover.c | 2 +- kernel/liveupdate/kho_radix.c | 2 +- 7 files changed, 137 insertions(+), 122 deletions(-) create mode 100644 include/linux/kho/abi/radix_tree.h rename include/linux/{kho_radix_tree.h =3D> kho/radix_tree.h} (96%) diff --git a/Documentation/core-api/kho/abi.rst b/Documentation/core-api/kh= o/abi.rst index edeb5b311963..da5c6636bb17 100644 --- a/Documentation/core-api/kho/abi.rst +++ b/Documentation/core-api/kho/abi.rst @@ -25,8 +25,7 @@ memblock preservation ABI KHO persistent memory tracker ABI =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D =20 -.. kernel-doc:: include/linux/kho/abi/kexec_handover.h - :doc: KHO persistent memory tracker +.. kernel-doc:: include/linux/kho/abi/radix_tree.h =20 KHO serialization block ABI =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D diff --git a/Documentation/core-api/kho/index.rst b/Documentation/core-api/= kho/index.rst index a9892c671ec3..f69367d217cf 100644 --- a/Documentation/core-api/kho/index.rst +++ b/Documentation/core-api/kho/index.rst @@ -74,7 +74,7 @@ the next KHO, because kexec can overwrite even the origin= al kernel. Kexec Handover Radix Tree =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D =20 -.. kernel-doc:: include/linux/kho_radix_tree.h +.. kernel-doc:: include/linux/kho/radix_tree.h :doc: Kexec Handover Radix Tree =20 Public API diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi= /kexec_handover.h index 5e2eb8519bda..99e4a53d4e35 100644 --- a/include/linux/kho/abi/kexec_handover.h +++ b/include/linux/kho/abi/kexec_handover.h @@ -4,15 +4,10 @@ * Copyright (C) 2023 Alexander Graf * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport * Copyright (C) 2025 Google LLC, Changyuan Lyu - * Copyright (C) 2025 Google LLC, Jason Miu */ =20 #ifndef _LINUX_KHO_ABI_KEXEC_HANDOVER_H #define _LINUX_KHO_ABI_KEXEC_HANDOVER_H - -#include -#include -#include #include =20 #include @@ -177,113 +172,4 @@ struct kho_vmalloc { unsigned short order; }; =20 -/** - * DOC: KHO persistent memory tracker - * - * KHO tracks preserved memory using a radix tree data structure. Each nod= e of - * the tree is exactly a single page. The leaf nodes are bitmaps where eac= h set - * bit is a preserved page of any order. The intermediate nodes are tables= of - * physical addresses that point to a lower level node. - * - * The tree hierarchy is shown below:: - * - * root - * +-------------------+ - * | Level 5 | (struct kho_radix_node) - * +-------------------+ - * | - * v - * +-------------------+ - * | Level 4 | (struct kho_radix_node) - * +-------------------+ - * | - * | ... (intermediate levels) - * | - * v - * +-------------------+ - * | Level 0 | (struct kho_radix_leaf) - * +-------------------+ - * - * The tree is traversed using a key that encodes the page's physical addr= ess - * (pa) and its order into a single unsigned long value. The encoded key v= alue - * is composed of two parts: the 'order bit' in the upper part and the - * 'shifted physical address' in the lower part.:: - * - * +------------+-----------------------------+-------------------------= -+ - * | Page Order | Order Bit | Shifted Physical Address= | - * +------------+-----------------------------+-------------------------= -+ - * | 0 | ...000100 ... (at bit 52) | pa >> (PAGE_SHIFT + 0) = | - * | 1 | ...000010 ... (at bit 51) | pa >> (PAGE_SHIFT + 1) = | - * | 2 | ...000001 ... (at bit 50) | pa >> (PAGE_SHIFT + 2) = | - * | ... | ... | ... = | - * +------------+-----------------------------+-------------------------= -+ - * - * Shifted Physical Address: - * The 'shifted physical address' is the physical address normalized for i= ts - * order. It effectively represents the PFN shifted right by the order. - * - * Order Bit: - * The 'order bit' encodes the page order by setting a single bit at a - * specific position. The position of this bit itself represents the order. - * - * For instance, on a 64-bit system with 4KB pages (PAGE_SHIFT =3D 12), the - * maximum range for the shifted physical address (for order 0) is 52 bits - * (64 - 12). This address occupies bits [0-51]. For order 0, the order bi= t is - * set at position 52. - * - * The following diagram illustrates how the encoded key value is split in= to - * indices for the tree levels, with PAGE_SIZE of 4KB:: - * - * 63:60 59:51 50:42 41:33 32:24 23:15 14:0 - * +---------+--------+--------+--------+--------+--------+-------------= ----+ - * | 0 | Lv 5 | Lv 4 | Lv 3 | Lv 2 | Lv 1 | Lv 0 (bitma= p) | - * +---------+--------+--------+--------+--------+--------+-------------= ----+ - * - * The radix tree stores pages of all orders in a single 6-level hierarchy= . It - * efficiently shares higher tree levels, especially due to common zero top - * address bits, allowing a single, efficient algorithm to manage all - * pages. This bitmap approach also offers memory efficiency; for example,= a - * 512KB bitmap can cover a 16GB memory range for 0-order pages with PAGE_= SIZE =3D - * 4KB. - * - * The data structures defined here are part of the KHO ABI. Any modificat= ion - * to these structures that breaks backward compatibility must be accompan= ied by - * an update to the "compatible" string. This ensures that a newer kernel = can - * correctly interpret the data passed by an older kernel. - */ - -/* - * Defines constants for the KHO radix tree structure, used to track prese= rved - * memory. These constants govern the indexing, sizing, and depth of the t= ree. - */ -enum kho_radix_consts { - /* - * The bit position of the order bit (and also the length of the - * shifted physical address) for an order-0 page. - */ - KHO_ORDER_0_LOG2 =3D 64 - PAGE_SHIFT, - - /* Size of the table in kho_radix_node, in log2 */ - KHO_TABLE_SIZE_LOG2 =3D const_ilog2(PAGE_SIZE / sizeof(phys_addr_t)), - - /* Number of bits in the kho_radix_leaf bitmap, in log2 */ - KHO_BITMAP_SIZE_LOG2 =3D PAGE_SHIFT + const_ilog2(BITS_PER_BYTE), - - /* - * The total tree depth is the number of intermediate levels - * and 1 bitmap level. - */ - KHO_TREE_MAX_DEPTH =3D - DIV_ROUND_UP(KHO_ORDER_0_LOG2 - KHO_BITMAP_SIZE_LOG2 + 1, - KHO_TABLE_SIZE_LOG2) + 1, -}; - -struct kho_radix_node { - u64 table[1 << KHO_TABLE_SIZE_LOG2]; -}; - -struct kho_radix_leaf { - DECLARE_BITMAP(bitmap, 1 << KHO_BITMAP_SIZE_LOG2); -}; - #endif /* _LINUX_KHO_ABI_KEXEC_HANDOVER_H */ diff --git a/include/linux/kho/abi/radix_tree.h b/include/linux/kho/abi/rad= ix_tree.h new file mode 100644 index 000000000000..f4cc5c02f37a --- /dev/null +++ b/include/linux/kho/abi/radix_tree.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Google LLC, Jason Miu + * Copyright (C) 2026 Pasha Tatashin + */ + +#ifndef _LINUX_KHO_ABI_RADIX_TREE_H +#define _LINUX_KHO_ABI_RADIX_TREE_H + +#include +#include + +/** + * DOC: KHO persistent memory tracker + * + * Subsystems using the KHO persistent memory tracker rely on the stable + * Application Binary Interface defined below to pass serialized state fro= m a + * pre-update kernel to a post-update kernel. + * + * This interface is a contract. Any modification to the structure fields, + * compatible strings, or the layout of the serialization structures defin= ed + * here constitutes a breaking change. Such changes require incrementing t= he + * version number in the `KHO_FDT_COMPATIBLE` string to prevent a new kern= el + * from misinterpreting data from an old kernel. + * + * Changes are allowed provided the compatibility version is incremented; + * however, backward/forward compatibility is only guaranteed for kernels + * supporting the same ABI version. + * + * KHO tracks preserved memory using a radix tree data structure. Each nod= e of + * the tree is exactly a single page. The leaf nodes are bitmaps where eac= h set + * bit is a preserved page of any order. The intermediate nodes are tables= of + * physical addresses that point to a lower level node. + * + * The tree hierarchy is shown below:: + * + * root + * +-------------------+ + * | Level 5 | (struct kho_radix_node) + * +-------------------+ + * | + * v + * +-------------------+ + * | Level 4 | (struct kho_radix_node) + * +-------------------+ + * | + * | ... (intermediate levels) + * | + * v + * +-------------------+ + * | Level 0 | (struct kho_radix_leaf) + * +-------------------+ + * + * The tree is traversed using a key that encodes the page's physical addr= ess + * (pa) and its order into a single unsigned long value. The encoded key v= alue + * is composed of two parts: the 'order bit' in the upper part and the + * 'shifted physical address' in the lower part.:: + * + * +------------+-----------------------------+-------------------------= -+ + * | Page Order | Order Bit | Shifted Physical Address= | + * +------------+-----------------------------+-------------------------= -+ + * | 0 | ...000100 ... (at bit 52) | pa >> (PAGE_SHIFT + 0) = | + * | 1 | ...000010 ... (at bit 51) | pa >> (PAGE_SHIFT + 1) = | + * | 2 | ...000001 ... (at bit 50) | pa >> (PAGE_SHIFT + 2) = | + * | ... | ... | ... = | + * +------------+-----------------------------+-------------------------= -+ + * + * Shifted Physical Address: + * The 'shifted physical address' is the physical address normalized for i= ts + * order. It effectively represents the PFN shifted right by the order. + * + * Order Bit: + * The 'order bit' encodes the page order by setting a single bit at a + * specific position. The position of this bit itself represents the order. + * + * For instance, on a 64-bit system with 4KB pages (PAGE_SHIFT =3D 12), the + * maximum range for the shifted physical address (for order 0) is 52 bits + * (64 - 12). This address occupies bits [0-51]. For order 0, the order bi= t is + * set at position 52. + * + * The following diagram illustrates how the encoded key value is split in= to + * indices for the tree levels, with PAGE_SIZE of 4KB:: + * + * 63:60 59:51 50:42 41:33 32:24 23:15 14:0 + * +---------+--------+--------+--------+--------+--------+-------------= ----+ + * | 0 | Lv 5 | Lv 4 | Lv 3 | Lv 2 | Lv 1 | Lv 0 (bitma= p) | + * +---------+--------+--------+--------+--------+--------+-------------= ----+ + * + * The radix tree stores pages of all orders in a single 6-level hierarchy= . It + * efficiently shares higher tree levels, especially due to common zero top + * address bits, allowing a single, efficient algorithm to manage all + * pages. This bitmap approach also offers memory efficiency; for example,= a + * 512KB bitmap can cover a 16GB memory range for 0-order pages with PAGE_= SIZE =3D + * 4KB. + */ + +/* + * Defines constants for the KHO radix tree structure, used to track prese= rved + * memory. These constants govern the indexing, sizing, and depth of the t= ree. + */ +enum kho_radix_consts { + /* + * The bit position of the order bit (and also the length of the + * shifted physical address) for an order-0 page. + */ + KHO_ORDER_0_LOG2 =3D 64 - PAGE_SHIFT, + + /* Size of the table in kho_radix_node, in log2 */ + KHO_TABLE_SIZE_LOG2 =3D const_ilog2(PAGE_SIZE / sizeof(phys_addr_t)), + + /* Number of bits in the kho_radix_leaf bitmap, in log2 */ + KHO_BITMAP_SIZE_LOG2 =3D PAGE_SHIFT + const_ilog2(BITS_PER_BYTE), + + /* + * The total tree depth is the number of intermediate levels + * and 1 bitmap level. + */ + KHO_TREE_MAX_DEPTH =3D + DIV_ROUND_UP(KHO_ORDER_0_LOG2 - KHO_BITMAP_SIZE_LOG2 + 1, + KHO_TABLE_SIZE_LOG2) + 1, +}; + +struct kho_radix_node { + u64 table[1 << KHO_TABLE_SIZE_LOG2]; +}; + +struct kho_radix_leaf { + DECLARE_BITMAP(bitmap, 1 << KHO_BITMAP_SIZE_LOG2); +}; + +#endif /* _LINUX_KHO_ABI_RADIX_TREE_H */ diff --git a/include/linux/kho_radix_tree.h b/include/linux/kho/radix_tree.h similarity index 96% rename from include/linux/kho_radix_tree.h rename to include/linux/kho/radix_tree.h index 84e918b96e53..1e337e73deba 100644 --- a/include/linux/kho_radix_tree.h +++ b/include/linux/kho/radix_tree.h @@ -5,6 +5,7 @@ =20 #include #include +#include #include #include =20 @@ -24,11 +25,9 @@ * Client code is responsible for allocating the root node of the tree, * initializing the mutex lock, and managing its lifecycle. It must use the * tree data structures defined in the KHO ABI, - * `include/linux/kho/abi/kexec_handover.h`. + * `include/linux/kho/abi/radix_tree.h`. */ =20 -struct kho_radix_node; - struct kho_radix_tree { struct kho_radix_node *root; struct mutex lock; /* protects the tree's structure and root pointer */ diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_h= andover.c index 041efff7ca11..4a3d6a54a17f 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/kernel/liveupdate/kho_radix.c b/kernel/liveupdate/kho_radix.c index c836783a1376..f48088847264 100644 --- a/kernel/liveupdate/kho_radix.c +++ b/kernel/liveupdate/kho_radix.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include --=20 2.53.0 From nobody Mon Jun 8 08:32:27 2026 Received: from mail-qt1-f180.google.com (mail-qt1-f180.google.com [209.85.160.180]) (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 942841FECBA for ; Fri, 5 Jun 2026 03:33:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630395; cv=none; b=RTwXhHDF0nmgIjflg20t381pA68njxHfazh1e8G4vpcUOPFXkonQGGOguEgckelK0glW9l2b8aBPmxJdgX6gMaZ7z1FGRQjsb6zWFhvT9+OP488Cbc1quVwzM9EKTP5EqZwBTNt/7ktja/oTmkwN8wu8QeIH4j+zC6hAVytXT0A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630395; c=relaxed/simple; bh=ngf8SP5Ocgafy8+MlZxC0RHUJkp9Her7xeokwHpvyaQ=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mUdTqnrfA9I5ygpdjiLbpJX4EUpXZIRGke+bYKb0w5vKLEzA85K2kYAA53npMttN2knYwPl4um5Glz5vjGaDOsKrdw3sLML40hN7wmtsRc2hbKkrAXblbNj3uFt3b/pE7wSL4yci14hiui6H/ELxS5rouvbfiMmm9k+MaCVuXnI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com; spf=pass smtp.mailfrom=soleen.com; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b=SYBZoYTE; arc=none smtp.client-ip=209.85.160.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=soleen.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b="SYBZoYTE" Received: by mail-qt1-f180.google.com with SMTP id d75a77b69052e-51784eb2ba0so11217001cf.2 for ; Thu, 04 Jun 2026 20:33:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1780630393; x=1781235193; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=gH8mRD7OHBJqm1quLMa7hgev2fQ64GiB6Pr4Gxty2sM=; b=SYBZoYTEqaR9vGuO4vaSlalMXlDscLl28sPXhMeJ+mjFtEF74+QDP4Hp+T7HstAVfu 4/leNaZGkDO+/CDjdOR6ezc1no+bWDDEwxoWUScPSFdEMaZwAQEqnJERdxohynlY1Shz mV5ci4MkLr9Vt7EFrmOvWQlFjy+LhVKIzXifL0XzsCK1S3cDPNItqpdBZnNoMD/BDyJa GRG+pp3rT/Ll33yI5zxW/+oAvfTGxhhv8/fz2ARNhfTOBvT1rVNVigI3vpDsfJJhuG1n +Lumvd/kZimeYjmcE0AiRYCAqYFv59WCu+OQI8QMieaQZ9biCk2ipNiL4sUY+nMg+rVJ fubg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780630393; x=1781235193; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=gH8mRD7OHBJqm1quLMa7hgev2fQ64GiB6Pr4Gxty2sM=; b=fQ6qwdB8Dd6455KXEHJuf3tCpgV5voogjNvz/+J0XiCoF9r7QnDobxpnJ7t+Ax4GNW VmIwSr0f9YzkpDBsyCkIo6xC2RbE5k2CFk23B6AhhSkkENBIGKQ4UiWPusVVXdf9NzXt hCe9Hs2EixkgxK4T3o/ylWLSDi2U4rXCUQMD0RYb5d12eEa/f806joP9q7/46fNtzS/c 8iuPzCDWlfdFNI863rT7zeGDF53Je7Lo/G9V1QzU4hdTRmr4hhqOo7F4+3vJtUXEYu2X T+JjnWTmwNjm71Apf4r6tON6AIeE9o4jVcFvdWjv1v5LptrjHQfhHJsKV5UV8ex3jYzL zR+Q== X-Forwarded-Encrypted: i=1; AFNElJ8dN9LjUoxsCj3zViyFu5gmRuEh3fa8Y7G8WX1p1y+jbmO0Pj4OoQ8p+uYmz1EiK4o2Tz6hHuMNNwvbBmo=@vger.kernel.org X-Gm-Message-State: AOJu0Yw5CXSahFPUfVWbGMRAfgEYxxKLJP8KXjSm0Sf0m4wp3LPntDXO feuZiDsjq7GhTcfyqT5ZO6/hvC2h71C/udqXT3zwF6RlDRb2awR4v/oJX3dx7rVNZm8= X-Gm-Gg: Acq92OEDH6z3tEcJuY3vxbmmu/+TovIjUUQpMZODg1CkcS6Ai/okthWmrw5yLo1eazp EU5tlzkUNVJ99W6HIndAo+qb1e7F0HxSMr5KEORIAQH8rclmVcZv4drgqc9RmKajju20KJZTMek 9NkPslVHG8JxtOhufblPqo6dLNy6yelQFgVgAYH/8nPE2QDtxjTZG+/0P35B0w/61pOn7zZvkSL 6B5xi4aQkmT6XmwtSbvZQDDZNMiDU9lE4ovK/b19kWGWuWGETMy0XQRp2+2afqxdb7Icj0Dp+m6 bx9uQxTXSYyFexrd7SNw/i3EovBahyYoWrnGL+tG8EL6tuYP7L0VLkLLuc+PYRg6P+RNFjDDkjc 9hBiyYxDACLK6eGwe11uUjXYxrXE8ywHB2muAE/RH1ZC/+mqX3oXcqPhTldD6lpnDs05AeMNGcf vrqWluuHliXPNs8jNGApeI27uO5HnNZpBZf6DzeWwLba758oPjbs6yyoUeB2ultQ== X-Received: by 2002:a05:622a:4390:b0:517:7b11:70ea with SMTP id d75a77b69052e-51795bbf9bbmr20136841cf.31.1780630392493; Thu, 04 Jun 2026 20:33:12 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51775dcf367sm70258631cf.25.2026.06.04.20.33.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jun 2026 20:33:12 -0700 (PDT) From: Pasha Tatashin To: linux-kselftest@vger.kernel.org, rppt@kernel.org, shuah@kernel.org, akpm@linux-foundation.org, linux-mm@kvack.org, skhan@linuxfoundation.org, linux-doc@vger.kernel.org, jasonmiu@google.com, linux-kernel@vger.kernel.org, corbet@lwn.net, ran.xiaokai@zte.com.cn, pasha.tatashin@soleen.com, kexec@lists.infradead.org, pratyush@kernel.org, graf@amazon.com Subject: [RFC v1 3/9] kho: split out vmalloc preservation into kho_vmalloc.c Date: Fri, 5 Jun 2026 03:32:29 +0000 Message-ID: <20260605033235.717351-4-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260605033235.717351-1-pasha.tatashin@soleen.com> References: <20260605033235.717351-1-pasha.tatashin@soleen.com> 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 Content-Type: text/plain; charset="utf-8" Move the vmalloc serialization and preservation implementation out of the core KHO code into its own dedicated file (kho_vmalloc.c). This is a pure code movement patch; no logic or functional changes are introduced. Signed-off-by: Pasha Tatashin --- Documentation/core-api/kho/index.rst | 3 + kernel/liveupdate/Makefile | 3 +- kernel/liveupdate/kexec_handover.c | 258 +------------------------ kernel/liveupdate/kho_vmalloc.c | 274 +++++++++++++++++++++++++++ lib/test_kho.c | 1 + mm/memfd_luo.c | 1 + 6 files changed, 282 insertions(+), 258 deletions(-) create mode 100644 kernel/liveupdate/kho_vmalloc.c diff --git a/Documentation/core-api/kho/index.rst b/Documentation/core-api/= kho/index.rst index f69367d217cf..a10b10700fb9 100644 --- a/Documentation/core-api/kho/index.rst +++ b/Documentation/core-api/kho/index.rst @@ -86,6 +86,9 @@ Public API .. kernel-doc:: kernel/liveupdate/kho_radix.c :export: =20 +.. kernel-doc:: kernel/liveupdate/kho_vmalloc.c + :export: + KHO Serialization Blocks API =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D =20 diff --git a/kernel/liveupdate/Makefile b/kernel/liveupdate/Makefile index a3ee8a5c27a2..b481e21a311a 100644 --- a/kernel/liveupdate/Makefile +++ b/kernel/liveupdate/Makefile @@ -9,7 +9,8 @@ luo-y :=3D \ =20 kho-y :=3D \ kexec_handover.o \ - kho_radix.o + kho_radix.o \ + kho_vmalloc.o =20 obj-$(CONFIG_KEXEC_HANDOVER) +=3D kho.o obj-$(CONFIG_KEXEC_HANDOVER_DEBUG) +=3D kexec_handover_debug.o diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_h= andover.c index 4a3d6a54a17f..6672bc168e57 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -23,11 +22,7 @@ #include #include #include -#include #include -#include - -#include =20 /* * KHO is tightly coupled with mm init and needs access to some of mm @@ -84,6 +79,7 @@ static struct kho_out kho_out =3D { }; =20 =20 + /* For physically contiguous 0-order pages. */ static void kho_init_pages(struct page *page, unsigned long nr_pages) { @@ -702,259 +698,7 @@ void kho_unpreserve_pages(struct page *page, unsigned= long nr_pages) } EXPORT_SYMBOL_GPL(kho_unpreserve_pages); =20 -/* vmalloc flags KHO supports */ -#define KHO_VMALLOC_SUPPORTED_FLAGS (VM_ALLOC | VM_ALLOW_HUGE_VMAP) - -/* KHO internal flags for vmalloc preservations */ -#define KHO_VMALLOC_ALLOC 0x0001 -#define KHO_VMALLOC_HUGE_VMAP 0x0002 - -static unsigned short vmalloc_flags_to_kho(unsigned int vm_flags) -{ - unsigned short kho_flags =3D 0; - - if (vm_flags & VM_ALLOC) - kho_flags |=3D KHO_VMALLOC_ALLOC; - if (vm_flags & VM_ALLOW_HUGE_VMAP) - kho_flags |=3D KHO_VMALLOC_HUGE_VMAP; - - return kho_flags; -} - -static unsigned int kho_flags_to_vmalloc(unsigned short kho_flags) -{ - unsigned int vm_flags =3D 0; - - if (kho_flags & KHO_VMALLOC_ALLOC) - vm_flags |=3D VM_ALLOC; - if (kho_flags & KHO_VMALLOC_HUGE_VMAP) - vm_flags |=3D VM_ALLOW_HUGE_VMAP; - - return vm_flags; -} - -static struct kho_vmalloc_chunk *new_vmalloc_chunk(struct kho_vmalloc_chun= k *cur) -{ - struct kho_vmalloc_chunk *chunk; - int err; - - chunk =3D (struct kho_vmalloc_chunk *)get_zeroed_page(GFP_KERNEL); - if (!chunk) - return NULL; - - err =3D kho_preserve_pages(virt_to_page(chunk), 1); - if (err) - goto err_free; - if (cur) - KHOSER_STORE_PTR(cur->hdr.next, chunk); - return chunk; - -err_free: - free_page((unsigned long)chunk); - return NULL; -} - -static void kho_vmalloc_unpreserve_chunk(struct kho_vmalloc_chunk *chunk, - unsigned short order) -{ - struct kho_radix_tree *tree =3D &kho_out.radix_tree; - unsigned long pfn =3D PHYS_PFN(virt_to_phys(chunk)); - - __kho_unpreserve(tree, pfn, pfn + 1); - - for (int i =3D 0; i < ARRAY_SIZE(chunk->phys) && chunk->phys[i]; i++) { - pfn =3D PHYS_PFN(chunk->phys[i]); - __kho_unpreserve(tree, pfn, pfn + (1 << order)); - } -} - -/** - * kho_preserve_vmalloc - preserve memory allocated with vmalloc() across = kexec - * @ptr: pointer to the area in vmalloc address space - * @preservation: placeholder for preservation metadata - * - * Instructs KHO to preserve the area in vmalloc address space at @ptr. The - * physical pages mapped at @ptr will be preserved and on successful return - * @preservation will hold the physical address of a structure that descri= bes - * the preservation. - * - * NOTE: The memory allocated with vmalloc_node() variants cannot be relia= bly - * restored on the same node - * - * Return: 0 on success, error code on failure - */ -int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation) -{ - struct kho_vmalloc_chunk *chunk; - struct vm_struct *vm =3D find_vm_area(ptr); - unsigned int order, flags, nr_contig_pages; - unsigned int idx =3D 0; - int err; - - if (!vm) - return -EINVAL; - - if (vm->flags & ~KHO_VMALLOC_SUPPORTED_FLAGS) - return -EOPNOTSUPP; - - flags =3D vmalloc_flags_to_kho(vm->flags); - order =3D get_vm_area_page_order(vm); - - chunk =3D new_vmalloc_chunk(NULL); - if (!chunk) - return -ENOMEM; - KHOSER_STORE_PTR(preservation->first, chunk); - - nr_contig_pages =3D (1 << order); - for (int i =3D 0; i < vm->nr_pages; i +=3D nr_contig_pages) { - phys_addr_t phys =3D page_to_phys(vm->pages[i]); - - err =3D kho_preserve_pages(vm->pages[i], nr_contig_pages); - if (err) - goto err_free; - - chunk->phys[idx++] =3D phys; - if (idx =3D=3D ARRAY_SIZE(chunk->phys)) { - chunk =3D new_vmalloc_chunk(chunk); - if (!chunk) { - err =3D -ENOMEM; - goto err_free; - } - idx =3D 0; - } - } - - preservation->total_pages =3D vm->nr_pages; - preservation->flags =3D flags; - preservation->order =3D order; - - return 0; - -err_free: - kho_unpreserve_vmalloc(preservation); - return err; -} -EXPORT_SYMBOL_GPL(kho_preserve_vmalloc); - -/** - * kho_unpreserve_vmalloc - unpreserve memory allocated with vmalloc() - * @preservation: preservation metadata returned by kho_preserve_vmalloc() - * - * Instructs KHO to unpreserve the area in vmalloc address space that was - * previously preserved with kho_preserve_vmalloc(). - */ -void kho_unpreserve_vmalloc(struct kho_vmalloc *preservation) -{ - struct kho_vmalloc_chunk *chunk =3D KHOSER_LOAD_PTR(preservation->first); - - while (chunk) { - struct kho_vmalloc_chunk *tmp =3D chunk; - - kho_vmalloc_unpreserve_chunk(chunk, preservation->order); - - chunk =3D KHOSER_LOAD_PTR(chunk->hdr.next); - free_page((unsigned long)tmp); - } -} -EXPORT_SYMBOL_GPL(kho_unpreserve_vmalloc); - -/** - * kho_restore_vmalloc - recreates and populates an area in vmalloc address - * space from the preserved memory. - * @preservation: preservation metadata. - * - * Recreates an area in vmalloc address space and populates it with memory= that - * was preserved using kho_preserve_vmalloc(). - * - * Return: pointer to the area in the vmalloc address space, NULL on failu= re. - */ -void *kho_restore_vmalloc(const struct kho_vmalloc *preservation) -{ - struct kho_vmalloc_chunk *chunk =3D KHOSER_LOAD_PTR(preservation->first); - kasan_vmalloc_flags_t kasan_flags =3D KASAN_VMALLOC_PROT_NORMAL; - unsigned int align, order, shift, vm_flags; - unsigned long total_pages, contig_pages; - unsigned long addr, size; - struct vm_struct *area; - struct page **pages; - unsigned int idx =3D 0; - int err; - - vm_flags =3D kho_flags_to_vmalloc(preservation->flags); - if (vm_flags & ~KHO_VMALLOC_SUPPORTED_FLAGS) - return NULL; - - total_pages =3D preservation->total_pages; - pages =3D kvmalloc_objs(*pages, total_pages); - if (!pages) - return NULL; - order =3D preservation->order; - contig_pages =3D (1 << order); - shift =3D PAGE_SHIFT + order; - align =3D 1 << shift; - - while (chunk) { - struct page *page; - - for (int i =3D 0; i < ARRAY_SIZE(chunk->phys) && chunk->phys[i]; i++) { - phys_addr_t phys =3D chunk->phys[i]; - - if (idx + contig_pages > total_pages) - goto err_free_pages_array; - - page =3D kho_restore_pages(phys, contig_pages); - if (!page) - goto err_free_pages_array; - - for (int j =3D 0; j < contig_pages; j++) - pages[idx++] =3D page + j; - - phys +=3D contig_pages * PAGE_SIZE; - } - - page =3D kho_restore_pages(virt_to_phys(chunk), 1); - if (!page) - goto err_free_pages_array; - chunk =3D KHOSER_LOAD_PTR(chunk->hdr.next); - __free_page(page); - } - - if (idx !=3D total_pages) - goto err_free_pages_array; - - area =3D __get_vm_area_node(total_pages * PAGE_SIZE, align, shift, - vm_flags | VM_UNINITIALIZED, - VMALLOC_START, VMALLOC_END, - NUMA_NO_NODE, GFP_KERNEL, - __builtin_return_address(0)); - if (!area) - goto err_free_pages_array; - - addr =3D (unsigned long)area->addr; - size =3D get_vm_area_size(area); - err =3D vmap_pages_range(addr, addr + size, PAGE_KERNEL, pages, shift); - if (err) - goto err_free_vm_area; =20 - area->nr_pages =3D total_pages; - area->pages =3D pages; - - if (vm_flags & VM_ALLOC) - kasan_flags |=3D KASAN_VMALLOC_VM_ALLOC; - - area->addr =3D kasan_unpoison_vmalloc(area->addr, total_pages * PAGE_SIZE, - kasan_flags); - clear_vm_uninitialized_flag(area); - - return area->addr; - -err_free_vm_area: - free_vm_area(area); -err_free_pages_array: - kvfree(pages); - return NULL; -} -EXPORT_SYMBOL_GPL(kho_restore_vmalloc); =20 /** * kho_alloc_preserve - Allocate, zero, and preserve memory. diff --git a/kernel/liveupdate/kho_vmalloc.c b/kernel/liveupdate/kho_vmallo= c.c new file mode 100644 index 000000000000..84c17b7a81ae --- /dev/null +++ b/kernel/liveupdate/kho_vmalloc.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * kho_vmalloc.c - KHO vmalloc space serialization/preservation + * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport + * Copyright (C) 2025 Pasha Tatashin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "../../mm/internal.h" +#include "kexec_handover_internal.h" + +/* vmalloc flags KHO supports */ +#define KHO_VMALLOC_SUPPORTED_FLAGS (VM_ALLOC | VM_ALLOW_HUGE_VMAP) + +/* KHO internal flags for vmalloc preservations */ +#define KHO_VMALLOC_ALLOC 0x0001 +#define KHO_VMALLOC_HUGE_VMAP 0x0002 + +static unsigned short vmalloc_flags_to_kho(unsigned int vm_flags) +{ + unsigned short kho_flags =3D 0; + + if (vm_flags & VM_ALLOC) + kho_flags |=3D KHO_VMALLOC_ALLOC; + if (vm_flags & VM_ALLOW_HUGE_VMAP) + kho_flags |=3D KHO_VMALLOC_HUGE_VMAP; + + return kho_flags; +} + +static unsigned int kho_flags_to_vmalloc(unsigned short kho_flags) +{ + unsigned int vm_flags =3D 0; + + if (kho_flags & KHO_VMALLOC_ALLOC) + vm_flags |=3D VM_ALLOC; + if (kho_flags & KHO_VMALLOC_HUGE_VMAP) + vm_flags |=3D VM_ALLOW_HUGE_VMAP; + + return vm_flags; +} + +static struct kho_vmalloc_chunk *new_vmalloc_chunk(struct kho_vmalloc_chun= k *cur) +{ + struct kho_vmalloc_chunk *chunk; + int err; + + chunk =3D (struct kho_vmalloc_chunk *)get_zeroed_page(GFP_KERNEL); + if (!chunk) + return NULL; + + err =3D kho_preserve_pages(virt_to_page(chunk), 1); + if (err) + goto err_free; + if (cur) + KHOSER_STORE_PTR(cur->hdr.next, chunk); + return chunk; + +err_free: + free_page((unsigned long)chunk); + return NULL; +} + +static void kho_vmalloc_unpreserve_chunk(struct kho_vmalloc_chunk *chunk, + unsigned short order) +{ + unsigned long pfn =3D PHYS_PFN(virt_to_phys(chunk)); + + kho_unpreserve_pages(pfn_to_page(pfn), 1); + + for (int i =3D 0; i < ARRAY_SIZE(chunk->phys) && chunk->phys[i]; i++) { + pfn =3D PHYS_PFN(chunk->phys[i]); + kho_unpreserve_pages(pfn_to_page(pfn), 1 << order); + } +} + +/** + * kho_preserve_vmalloc - preserve memory allocated with vmalloc() across = kexec + * @ptr: pointer to the area in vmalloc address space + * @preservation: placeholder for preservation metadata + * + * Instructs KHO to preserve the area in vmalloc address space at @ptr. The + * physical pages mapped at @ptr will be preserved and on successful return + * @preservation will hold the physical address of a structure that descri= bes + * the preservation. + * + * NOTE: The memory allocated with vmalloc_node() variants cannot be relia= bly + * restored on the same node + * + * Return: 0 on success, error code on failure + */ +int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation) +{ + struct kho_vmalloc_chunk *chunk; + struct vm_struct *vm =3D find_vm_area(ptr); + unsigned int order, flags, nr_contig_pages; + unsigned int idx =3D 0; + int err; + + if (!vm) + return -EINVAL; + + if (vm->flags & ~KHO_VMALLOC_SUPPORTED_FLAGS) + return -EOPNOTSUPP; + + flags =3D vmalloc_flags_to_kho(vm->flags); + order =3D get_vm_area_page_order(vm); + + chunk =3D new_vmalloc_chunk(NULL); + if (!chunk) + return -ENOMEM; + KHOSER_STORE_PTR(preservation->first, chunk); + + nr_contig_pages =3D (1 << order); + for (int i =3D 0; i < vm->nr_pages; i +=3D nr_contig_pages) { + phys_addr_t phys =3D page_to_phys(vm->pages[i]); + + err =3D kho_preserve_pages(vm->pages[i], nr_contig_pages); + if (err) + goto err_free; + + chunk->phys[idx++] =3D phys; + if (idx =3D=3D ARRAY_SIZE(chunk->phys)) { + chunk =3D new_vmalloc_chunk(chunk); + if (!chunk) { + err =3D -ENOMEM; + goto err_free; + } + idx =3D 0; + } + } + + preservation->total_pages =3D vm->nr_pages; + preservation->flags =3D flags; + preservation->order =3D order; + + return 0; + +err_free: + kho_unpreserve_vmalloc(preservation); + return err; +} +EXPORT_SYMBOL_GPL(kho_preserve_vmalloc); + +/** + * kho_unpreserve_vmalloc - unpreserve memory allocated with vmalloc() + * @preservation: preservation metadata returned by kho_preserve_vmalloc() + * + * Instructs KHO to unpreserve the area in vmalloc address space that was + * previously preserved with kho_preserve_vmalloc(). + */ +void kho_unpreserve_vmalloc(struct kho_vmalloc *preservation) +{ + struct kho_vmalloc_chunk *chunk =3D KHOSER_LOAD_PTR(preservation->first); + + while (chunk) { + struct kho_vmalloc_chunk *tmp =3D chunk; + + kho_vmalloc_unpreserve_chunk(chunk, preservation->order); + + chunk =3D KHOSER_LOAD_PTR(chunk->hdr.next); + free_page((unsigned long)tmp); + } +} +EXPORT_SYMBOL_GPL(kho_unpreserve_vmalloc); + +/** + * kho_restore_vmalloc - recreates and populates an area in vmalloc address + * space from the preserved memory. + * @preservation: preservation metadata. + * + * Recreates an area in vmalloc address space and populates it with memory= that + * was preserved using kho_preserve_vmalloc(). + * + * Return: pointer to the area in the vmalloc address space, NULL on failu= re. + */ +void *kho_restore_vmalloc(const struct kho_vmalloc *preservation) +{ + struct kho_vmalloc_chunk *chunk =3D KHOSER_LOAD_PTR(preservation->first); + kasan_vmalloc_flags_t kasan_flags =3D KASAN_VMALLOC_PROT_NORMAL; + unsigned int align, order, shift, vm_flags; + unsigned long total_pages, contig_pages; + unsigned long addr, size; + struct vm_struct *area; + struct page **pages; + unsigned int idx =3D 0; + int err; + + vm_flags =3D kho_flags_to_vmalloc(preservation->flags); + if (vm_flags & ~KHO_VMALLOC_SUPPORTED_FLAGS) + return NULL; + + total_pages =3D preservation->total_pages; + pages =3D kvmalloc_objs(*pages, total_pages); + if (!pages) + return NULL; + order =3D preservation->order; + contig_pages =3D (1 << order); + shift =3D PAGE_SHIFT + order; + align =3D 1 << shift; + + while (chunk) { + struct page *page; + + for (int i =3D 0; i < ARRAY_SIZE(chunk->phys) && chunk->phys[i]; i++) { + phys_addr_t phys =3D chunk->phys[i]; + + if (idx + contig_pages > total_pages) + goto err_free_pages_array; + + page =3D kho_restore_pages(phys, contig_pages); + if (!page) + goto err_free_pages_array; + + for (int j =3D 0; j < contig_pages; j++) + pages[idx++] =3D page + j; + + phys +=3D contig_pages * PAGE_SIZE; + } + + page =3D kho_restore_pages(virt_to_phys(chunk), 1); + if (!page) + goto err_free_pages_array; + chunk =3D KHOSER_LOAD_PTR(chunk->hdr.next); + __free_page(page); + } + + if (idx !=3D total_pages) + goto err_free_pages_array; + + area =3D __get_vm_area_node(total_pages * PAGE_SIZE, align, shift, + vm_flags | VM_UNINITIALIZED, + VMALLOC_START, VMALLOC_END, + NUMA_NO_NODE, GFP_KERNEL, + __builtin_return_address(0)); + if (!area) + goto err_free_pages_array; + + addr =3D (unsigned long)area->addr; + size =3D get_vm_area_size(area); + err =3D vmap_pages_range(addr, addr + size, PAGE_KERNEL, pages, shift); + if (err) + goto err_free_vm_area; + + area->nr_pages =3D total_pages; + area->pages =3D pages; + + if (vm_flags & VM_ALLOC) + kasan_flags |=3D KASAN_VMALLOC_VM_ALLOC; + + area->addr =3D kasan_unpoison_vmalloc(area->addr, total_pages * PAGE_SIZE, + kasan_flags); + clear_vm_uninitialized_flag(area); + + return area->addr; + +err_free_vm_area: + free_vm_area(area); +err_free_pages_array: + kvfree(pages); + return NULL; +} +EXPORT_SYMBOL_GPL(kho_restore_vmalloc); diff --git a/lib/test_kho.c b/lib/test_kho.c index aa6a0956bb8b..6907e09688dd 100644 --- a/lib/test_kho.c +++ b/lib/test_kho.c @@ -20,6 +20,7 @@ #include #include #include +#include =20 #include =20 diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c index 59de210bee5f..ade2aa24c7b8 100644 --- a/mm/memfd_luo.c +++ b/mm/memfd_luo.c @@ -76,6 +76,7 @@ #include #include #include +#include #include #include #include --=20 2.53.0 From nobody Mon Jun 8 08:32:27 2026 Received: from mail-qv1-f54.google.com (mail-qv1-f54.google.com [209.85.219.54]) (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 37F1F379ED5 for ; Fri, 5 Jun 2026 03:33:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630406; cv=none; b=NIlG3XYlfWAUXpH/qsFUsfF+OP2z7WFUBpZkRDTKeP6o6TYEfKgtAt39k2ZnSiiuZnwATgEV9N2latFWoxYR2bDX9m4rtjZA+J6Lxx14kGuGdfl9Sl9ItZ3kCteVR6heFxUq+wZSPFKNsEpnK2hle+UpS0Pw52OnLcsyT55npr0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630406; c=relaxed/simple; bh=4VnGiJfrZQCqXxaU6ZsqSy06u9XeMGJXWufGnIgPPj8=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OOKbeBBOANQ5TEftx6AehSCD/L4c2YAxk/oLyCaWZrpKU1AQz92AyD45BbIHskXwT287xx8CNWvIw6vVbq7Fej26TM0P6Wu2mWZPLZGThrT7ihEdJAFfA/6r0SgHxqZqE0WldjHat27gTgPpgkHpNt3WY74YpyZ4dg9q5aZj9G0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com; spf=pass smtp.mailfrom=soleen.com; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b=IG7dbthv; arc=none smtp.client-ip=209.85.219.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=soleen.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b="IG7dbthv" Received: by mail-qv1-f54.google.com with SMTP id 6a1803df08f44-8ce9df48e1bso12639796d6.1 for ; Thu, 04 Jun 2026 20:33:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1780630404; x=1781235204; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=burVgKt+U0bNdZ+S4i+8PCamSBgPUcyGmVaC5AfN7II=; b=IG7dbthvtwOgTcsbdpqQD5BzOVj/s4prSAq675YXZ6lx4ZNX8+9F93OHKf/RmcQrs2 MZuodwKBSXSLYTphbsRsx6hesWi2uf55VDfYQBCvX9FDydGCs4aR3DOqwwuRfyEWnA57 4wWbdW/AwhoykqZw8Fv7egOO8vjfSdkPF1ajQysCo27tzUHAUaiiIXgQZUr15oM1bucE LxvF8i8bRnUlc6QWOpvX3K4bjkY7jOPOlNash4ykwm28Y0ISGnS6Yxv8AVRrSn4c75wM 04DahOvYN7QHiSgWHF5flM9kSHDzElbvhDXfQCuh5YbQvoIjVIykizUMNrgrQVIRhJcB ebDg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780630404; x=1781235204; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=burVgKt+U0bNdZ+S4i+8PCamSBgPUcyGmVaC5AfN7II=; b=ISiLSRXvEJD6y33omlCvMTx0qQFzel2leCbOZtwKCi7/TYSOBJWEp6NmzgZonlyeWz 4p2QWYLE1WeOstvsBmtP2RdgifdkeFKKnSn+QxSHrwZeEbqORszCyaUQAaWjWtqSOcs6 vqU9Qd07uaSLGl72zGtsLBPkhdx+KBuD9gpR23Sns3TkY6v44hM1AisQbFY6R9PxJflE sKypFIpzUbrLRweY2vcU/wx4LYSCBxzBfzURN/mqHIKxQmCUaS2rzVp2FBx3JP4VY2sY 2cdKKdXzw72kJF/rIavM7WRAbBnBOMpJcoVE9jm9RrhRIIKRRcIOdbdaP5sHTaQ5kfLN Fllw== X-Forwarded-Encrypted: i=1; AFNElJ9Ajv+krIYzOD1Vul8YHmeKBJ9fM+kYym5AGOR/RqSPLvw+lpx4HI9J43Dtu954mxnqv9v5w8uY8JZI/Xw=@vger.kernel.org X-Gm-Message-State: AOJu0YysVO6JBmY3wfYrqdGH1mA3TuZuzBdeNlTlbJfZe0X+iXmeaEze nbDlG4mVbzyAFLI/QGAMcrgH5CqIkdTqlF5lX54YJJOg8LlbEvZXpx/w07Jy39SYqOk= X-Gm-Gg: Acq92OHjEwxvAnt/3svyF4k76kh/GyHrRtqR74SOeb8Nfmb40cZCmpqYX3X+/1r8C9H iLCghWYUgSbqSMx+y8u5BLy0oSD+uYi5oIisPPYlIdfO2DdG2dU4puSP2wA8w6PLONfrKZSPr52 /eR0fmciWf0aIT66OInfMaMaLmx2nmScZyQlHK0DNIBdDTFiYP+78mQzA/m5y3YsI+CQSozxW0w XxrT5ZFUKmC4v+3s96E+Uoxskm9jtEWFde41+mvVF2Qrj7G4l/OFaGGiYOyttCk4hBtAyjgUj83 Cb+8gFw0iQ7GYZ8MKjUWa7kDXPHkOeXoFp/p2Ebx/DM2sRxgcr81UZKf/hOTJCFN/O2VeBtq7xV Qw4m9ab0oFT/x3zlkmsfkyFoeurIhpD8jfveyWNT/gv2jMV5deU5oklEIjiVccDDCgDp571CUbz mhn0kALRt2tYxdrgUMBcrI6AAVsA+aj1pQwXuzEv10cUUGEvI1mNm5EsXu/A4RgLa8jorDh5yG X-Received: by 2002:a05:6214:2d07:b0:8cc:f882:2562 with SMTP id 6a1803df08f44-8cee61497cdmr30262576d6.39.1780630404187; Thu, 04 Jun 2026 20:33:24 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8cecd263003sm71383816d6.42.2026.06.04.20.33.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jun 2026 20:33:23 -0700 (PDT) From: Pasha Tatashin To: linux-kselftest@vger.kernel.org, rppt@kernel.org, shuah@kernel.org, akpm@linux-foundation.org, linux-mm@kvack.org, skhan@linuxfoundation.org, linux-doc@vger.kernel.org, jasonmiu@google.com, linux-kernel@vger.kernel.org, corbet@lwn.net, ran.xiaokai@zte.com.cn, pasha.tatashin@soleen.com, kexec@lists.infradead.org, pratyush@kernel.org, graf@amazon.com Subject: [RFC v1 4/9] kho: split vmalloc headers out of kexec_handover.h Date: Fri, 5 Jun 2026 03:32:30 +0000 Message-ID: <20260605033235.717351-5-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260605033235.717351-1-pasha.tatashin@soleen.com> References: <20260605033235.717351-1-pasha.tatashin@soleen.com> 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 Content-Type: text/plain; charset="utf-8" Split the vmalloc-related ABI definitions and header declarations out of the monolithic kexec_handover.h header into a dedicated header file (vmalloc.h). This is a pure code movement patch; no logic or functional changes are introduced. Signed-off-by: Pasha Tatashin --- Documentation/core-api/kho/abi.rst | 3 +- include/linux/kexec_handover.h | 18 ----- include/linux/kho/abi/kexec_handover.h | 77 +------------------- include/linux/kho/abi/memfd.h | 3 +- include/linux/kho/abi/vmalloc.h | 99 ++++++++++++++++++++++++++ include/linux/kho/vmalloc.h | 34 +++++++++ 6 files changed, 137 insertions(+), 97 deletions(-) create mode 100644 include/linux/kho/abi/vmalloc.h create mode 100644 include/linux/kho/vmalloc.h diff --git a/Documentation/core-api/kho/abi.rst b/Documentation/core-api/kh= o/abi.rst index da5c6636bb17..b61363679829 100644 --- a/Documentation/core-api/kho/abi.rst +++ b/Documentation/core-api/kho/abi.rst @@ -13,8 +13,7 @@ Core Kexec Handover ABI vmalloc preservation ABI =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 -.. kernel-doc:: include/linux/kho/abi/kexec_handover.h - :doc: Kexec Handover ABI for vmalloc Preservation +.. kernel-doc:: include/linux/kho/abi/vmalloc.h =20 memblock preservation ABI =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h index 8968c56d2d73..518fdab2a4d1 100644 --- a/include/linux/kexec_handover.h +++ b/include/linux/kexec_handover.h @@ -11,8 +11,6 @@ struct kho_scratch { phys_addr_t size; }; =20 -struct kho_vmalloc; - struct folio; struct page; =20 @@ -24,14 +22,11 @@ int kho_preserve_folio(struct folio *folio); void kho_unpreserve_folio(struct folio *folio); int kho_preserve_pages(struct page *page, unsigned long nr_pages); void kho_unpreserve_pages(struct page *page, unsigned long nr_pages); -int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation); -void kho_unpreserve_vmalloc(struct kho_vmalloc *preservation); void *kho_alloc_preserve(size_t size); void kho_unpreserve_free(void *mem); void kho_restore_free(void *mem); struct folio *kho_restore_folio(phys_addr_t phys); struct page *kho_restore_pages(phys_addr_t phys, unsigned long nr_pages); -void *kho_restore_vmalloc(const struct kho_vmalloc *preservation); int kho_add_subtree(const char *name, void *blob, size_t size); void kho_remove_subtree(void *blob); int kho_retrieve_subtree(const char *name, phys_addr_t *phys, size_t *size= ); @@ -65,14 +60,6 @@ static inline int kho_preserve_pages(struct page *page, = unsigned int nr_pages) =20 static inline void kho_unpreserve_pages(struct page *page, unsigned int nr= _pages) { } =20 -static inline int kho_preserve_vmalloc(void *ptr, - struct kho_vmalloc *preservation) -{ - return -EOPNOTSUPP; -} - -static inline void kho_unpreserve_vmalloc(struct kho_vmalloc *preservation= ) { } - static inline void *kho_alloc_preserve(size_t size) { return ERR_PTR(-EOPNOTSUPP); @@ -92,11 +79,6 @@ static inline struct page *kho_restore_pages(phys_addr_t= phys, return NULL; } =20 -static inline void *kho_restore_vmalloc(const struct kho_vmalloc *preserva= tion) -{ - return NULL; -} - static inline int kho_add_subtree(const char *name, void *blob, size_t siz= e) { return -EOPNOTSUPP; diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi= /kexec_handover.h index 99e4a53d4e35..c893b5045078 100644 --- a/include/linux/kho/abi/kexec_handover.h +++ b/include/linux/kho/abi/kexec_handover.h @@ -96,80 +96,5 @@ /* The FDT property for the size of preserved data blobs. */ #define KHO_SUB_TREE_SIZE_PROP_NAME "blob-size" =20 -/** - * DOC: Kexec Handover ABI for vmalloc Preservation - * - * The Kexec Handover ABI for preserving vmalloc'ed memory is defined by - * a set of structures and helper macros. The layout of these structures i= s a - * stable contract between kernels and is versioned by the KHO_FDT_COMPATI= BLE - * string. - * - * The preservation is managed through a main descriptor &struct kho_vmall= oc, - * which points to a linked list of &struct kho_vmalloc_chunk structures. = These - * chunks contain the physical addresses of the preserved pages, allowing = the - * next kernel to reconstruct the vmalloc area with the same content and l= ayout. - * Helper macros are also defined for storing and loading pointers within - * these structures. - */ - -/* Helper macro to define a union for a serializable pointer. */ -#define DECLARE_KHOSER_PTR(name, type) \ - union { \ - u64 phys; \ - type ptr; \ - } name - -/* Stores the physical address of a serializable pointer. */ -#define KHOSER_STORE_PTR(dest, val) \ - ({ \ - typeof(val) v =3D val; \ - typecheck(typeof((dest).ptr), v); \ - (dest).phys =3D virt_to_phys(v); \ - }) - -/* Loads the stored physical address back to a pointer. */ -#define KHOSER_LOAD_PTR(src) \ - ({ \ - typeof(src) s =3D src; \ - (typeof((s).ptr))((s).phys ? phys_to_virt((s).phys) : NULL); \ - }) - -/* - * This header is embedded at the beginning of each `kho_vmalloc_chunk` - * and contains a pointer to the next chunk in the linked list, - * stored as a physical address for handover. - */ -struct kho_vmalloc_hdr { - DECLARE_KHOSER_PTR(next, struct kho_vmalloc_chunk *); -}; - -#define KHO_VMALLOC_SIZE \ - ((PAGE_SIZE - sizeof(struct kho_vmalloc_hdr)) / \ - sizeof(u64)) - -/* - * Each chunk is a single page and is part of a linked list that describes - * a preserved vmalloc area. It contains the header with the link to the n= ext - * chunk and a zero terminated array of physical addresses of the pages th= at - * make up the preserved vmalloc area. - */ -struct kho_vmalloc_chunk { - struct kho_vmalloc_hdr hdr; - u64 phys[KHO_VMALLOC_SIZE]; -}; - -static_assert(sizeof(struct kho_vmalloc_chunk) =3D=3D PAGE_SIZE); - -/* - * Describes a preserved vmalloc memory area, including the - * total number of pages, allocation flags, page order, and a pointer to t= he - * first chunk of physical page addresses. - */ -struct kho_vmalloc { - DECLARE_KHOSER_PTR(first, struct kho_vmalloc_chunk *); - unsigned int total_pages; - unsigned short flags; - unsigned short order; -}; - #endif /* _LINUX_KHO_ABI_KEXEC_HANDOVER_H */ + diff --git a/include/linux/kho/abi/memfd.h b/include/linux/kho/abi/memfd.h index 08b10fea2afc..af310c0c9fdf 100644 --- a/include/linux/kho/abi/memfd.h +++ b/include/linux/kho/abi/memfd.h @@ -11,8 +11,9 @@ #ifndef _LINUX_KHO_ABI_MEMFD_H #define _LINUX_KHO_ABI_MEMFD_H =20 -#include #include +#include +#include =20 /** * DOC: memfd Live Update ABI diff --git a/include/linux/kho/abi/vmalloc.h b/include/linux/kho/abi/vmallo= c.h new file mode 100644 index 000000000000..87650e1dd774 --- /dev/null +++ b/include/linux/kho/abi/vmalloc.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport + * Copyright (C) 2025 Pasha Tatashin + */ + +/** + * DOC: Kexec Handover ABI for vmalloc Preservation + * + * The Kexec Handover ABI for preserving vmalloc'ed memory is defined by + * a set of structures and helper macros. The layout of these structures i= s a + * stable contract between kernels and is versioned by the KHO_FDT_COMPATI= BLE + * string. + * + * This interface is a contract. Any modification to the structure fields, + * compatible strings, or the layout of the serialization structures defin= ed + * here constitutes a breaking change. Such changes require incrementing t= he + * version number in the `KHO_FDT_COMPATIBLE` string to prevent a new kern= el + * from misinterpreting data from an old kernel. + * + * Changes are allowed provided the compatibility version is incremented; + * however, backward/forward compatibility is only guaranteed for kernels + * supporting the same ABI version. + * + * The preservation is managed through a main descriptor &struct kho_vmall= oc, + * which points to a linked list of &struct kho_vmalloc_chunk structures. = These + * chunks contain the physical addresses of the preserved pages, allowing = the + * next kernel to reconstruct the vmalloc area with the same content and l= ayout. + * Helper macros are also defined for storing and loading pointers within + * these structures. + */ + +#ifndef _LINUX_KHO_ABI_VMALLOC_H +#define _LINUX_KHO_ABI_VMALLOC_H + +#include +#include + +/* Helper macro to define a union for a serializable pointer. */ +#define DECLARE_KHOSER_PTR(name, type) \ + union { \ + u64 phys; \ + type ptr; \ + } name + +/* Stores the physical address of a serializable pointer. */ +#define KHOSER_STORE_PTR(dest, val) \ + ({ \ + typeof(val) v =3D val; \ + typecheck(typeof((dest).ptr), v); \ + (dest).phys =3D virt_to_phys(v); \ + }) + +/* Loads the stored physical address back to a pointer. */ +#define KHOSER_LOAD_PTR(src) \ + ({ \ + typeof(src) s =3D src; \ + (typeof((s).ptr))((s).phys ? phys_to_virt((s).phys) : NULL); \ + }) + +/* + * This header is embedded at the beginning of each `kho_vmalloc_chunk` + * and contains a pointer to the next chunk in the linked list, + * stored as a physical address for handover. + */ +struct kho_vmalloc_hdr { + DECLARE_KHOSER_PTR(next, struct kho_vmalloc_chunk *); +}; + +#define KHO_VMALLOC_SIZE \ + ((PAGE_SIZE - sizeof(struct kho_vmalloc_hdr)) / \ + sizeof(u64)) + +/* + * Each chunk is a single page and is part of a linked list that describes + * a preserved vmalloc area. It contains the header with the link to the n= ext + * chunk and a zero terminated array of physical addresses of the pages th= at + * make up the preserved vmalloc area. + */ +struct kho_vmalloc_chunk { + struct kho_vmalloc_hdr hdr; + u64 phys[KHO_VMALLOC_SIZE]; +}; + +static_assert(sizeof(struct kho_vmalloc_chunk) =3D=3D PAGE_SIZE); + +/* + * Describes a preserved vmalloc memory area, including the + * total number of pages, allocation flags, page order, and a pointer to t= he + * first chunk of physical page addresses. + */ +struct kho_vmalloc { + DECLARE_KHOSER_PTR(first, struct kho_vmalloc_chunk *); + unsigned int total_pages; + unsigned short flags; + unsigned short order; +}; + +#endif /* _LINUX_KHO_ABI_VMALLOC_H */ diff --git a/include/linux/kho/vmalloc.h b/include/linux/kho/vmalloc.h new file mode 100644 index 000000000000..2d1b5d282a93 --- /dev/null +++ b/include/linux/kho/vmalloc.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_KHO_VMALLOC_H +#define _LINUX_KHO_VMALLOC_H + +#include +#include +#include + +struct page; + +#ifdef CONFIG_KEXEC_HANDOVER + +int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation); +void kho_unpreserve_vmalloc(struct kho_vmalloc *preservation); +void *kho_restore_vmalloc(const struct kho_vmalloc *preservation); + +#else /* CONFIG_KEXEC_HANDOVER */ + +static inline int kho_preserve_vmalloc(void *ptr, + struct kho_vmalloc *preservation) +{ + return -EOPNOTSUPP; +} + +static inline void kho_unpreserve_vmalloc(struct kho_vmalloc *preservation= ) { } + +static inline void *kho_restore_vmalloc(const struct kho_vmalloc *preserva= tion) +{ + return NULL; +} + +#endif /* CONFIG_KEXEC_HANDOVER */ + +#endif /* _LINUX_KHO_VMALLOC_H */ --=20 2.53.0 From nobody Mon Jun 8 08:32:27 2026 Received: from mail-qk1-f174.google.com (mail-qk1-f174.google.com [209.85.222.174]) (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 D06AA3988E0 for ; Fri, 5 Jun 2026 03:33:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630418; cv=none; b=EKI1cpENBWYJkVsWwRI+XUzXMrZuj7sIN4ME2ozi24uKMTVMIBNyCOfvDQ1On8XHl6pYNmBXmDJE7koVtSyfyZcadgXAU1kZZ13kgELLApWD2vbrlxO4CJlEIQkQO+iIUqg6xcC0jxhXnzxK8h4ibN2hLH+zFbi2QPN1NpofKB4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630418; c=relaxed/simple; bh=DtZ9V8MH8JsGyHu6CF1ttsD49Zp4ajpPdH0dtGBNsU4=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JCsbYq/NKEORltQhy9BWKOxAqRQNjmevWoG0D5Xftm/EpawYZ9s/g+pCyQrp9ZntwfhmTnGofX3QYKrdMPbdwhbfQPY9Wc+dOebwnwbpwjdlor6SAEH5vhtDW2KRdLNJSVnODkAHa7vVJrMcdUHoqLPPF9vKVmD3zOEgJ7nOOs4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com; spf=pass smtp.mailfrom=soleen.com; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b=FxvLg3S9; arc=none smtp.client-ip=209.85.222.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=soleen.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b="FxvLg3S9" Received: by mail-qk1-f174.google.com with SMTP id af79cd13be357-9158fbaa4bbso184760085a.1 for ; Thu, 04 Jun 2026 20:33:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1780630416; x=1781235216; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=J9VRMQ5Ef8ulqUN7FHiGBWdV1K/iIYqxWaAhgeSwRK0=; b=FxvLg3S9vw3x4H+gYi6tndasKxlu+a/73bv82RhwcMtzPyTrvG6tJgjLDQTRs0k+1L rnKnxSUupV4jDW2OalnjkH+evs0mBBOdYE2OvkeriJMvJlA7CD+sW8t4A/FLmHQT1Fvq DCgCr/dmmu9YkqRbLo4KCB/dvPxw9vAWt9RtqQshMqXpr99ux+XZ0oVPia+fkGXzS4Ef qAEWO9+lcCBs6zAOdUyYW9IBbrCJWQz6nBhIHwOu8RlSjK/l6EtnkjzNHAZZ693wL7qH +owZzr0A7a800rgIRLNhdDFY4wluap92g8dp7h6iXDazGzguAtQT1KqEnkizCD8NkedQ NhBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780630416; x=1781235216; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=J9VRMQ5Ef8ulqUN7FHiGBWdV1K/iIYqxWaAhgeSwRK0=; b=YFpt9fNb5np4AaMjLzehizeaYJFvVcgjjhWuW6CzRlJ0tATcsaEHbfhYWOpsoixa2I M8mzKaIkr117ce9aVj7NDgKWlZv31LA92HqIK5CbXPxZcarCiv9ZJ9Wcd5ONXCVBf/r6 IcfiFhr6uUSwhHymlTWD9HszAjohknLMYaiYDFq9z0N4BhG2cMhR1VQbqD7XatKX/epy R8ENJClbetFxnAtOs+xYcbJhYad5MDjdwxM/RdFIVpAbsmltr8Vbx95+8Vv9itYIT6bj 5keqsxPO7k97WMI2q+rZ9K2D3t6+eCadkl6nEJUw5w0TJknTU+imYPjaSd61B7Vi7uhj ClaQ== X-Forwarded-Encrypted: i=1; AFNElJ8l1Nf1YeU4UEoTTWFCPsnbsaM6qYwAUu4HN5W5I3RZons7FUTQ4mqX8U/R/+eJQqtA8IFXwYHVKircPBc=@vger.kernel.org X-Gm-Message-State: AOJu0YzCANm6f5zUZCTysfBTOcwR+4cU7E3Hhng2b8I6XcB1UqG/y3hS Ur4E3/Q02g8PC2jsjp9/3qX3OdISmJEDMmI3vNMP2hIjq6S5So1ORXT1zlkZVutWRuU= X-Gm-Gg: Acq92OF5CtoqkUOvczJ08rk+RHJp02ijgEG6yknskhV6t9vTftyMaG+P06lOOkBsD2Y GpIjFYyG8LMXYpimjLPKavHKLwaF/W0YvvZDO/yfDNtElVKm1epAaw6kaJfbSBCsZkFh5Ml7xPG hxX/3WlFWleNawsoGki839tQdh5NuK24dEPwcg54FRT+qXp+GmR0xPgB92f2npy3o6otOC46hWZ QbCBEoSc0MNUBoIapSZfPRmuRJacHitpVxUqvauRB4bdvV135VVl/jMPuQQSnNPnJ4t+KgL3JDv 3T0dzsKJL60Lv+DtbCVoojDcwGY2hWMJLXNDfcbTBL7iqKCD009hZ08ZUrEh9tkg+XX8UJpFyjt MHBFGpVaHCfq/83GliIm+e+M7EThwXKFaMmR55SLq3301eHw1X10c+px8D21F09HURC4uQlxsYp EstG8yZsyC5K8hoksHQKvcdgpTxqPBM88Tfyvm8coGb5kIOx4huWJhsT94pgC/Vg== X-Received: by 2002:a05:620a:3910:b0:915:7f9f:8d97 with SMTP id af79cd13be357-915a9daef8bmr376847085a.53.1780630415906; Thu, 04 Jun 2026 20:33:35 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id af79cd13be357-9158a37c645sm743050785a.30.2026.06.04.20.33.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jun 2026 20:33:35 -0700 (PDT) From: Pasha Tatashin To: linux-kselftest@vger.kernel.org, rppt@kernel.org, shuah@kernel.org, akpm@linux-foundation.org, linux-mm@kvack.org, skhan@linuxfoundation.org, linux-doc@vger.kernel.org, jasonmiu@google.com, linux-kernel@vger.kernel.org, corbet@lwn.net, ran.xiaokai@zte.com.cn, pasha.tatashin@soleen.com, kexec@lists.infradead.org, pratyush@kernel.org, graf@amazon.com Subject: [RFC v1 5/9] kho: move kho_block.h to kho/block.h Date: Fri, 5 Jun 2026 03:32:31 +0000 Message-ID: <20260605033235.717351-6-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260605033235.717351-1-pasha.tatashin@soleen.com> References: <20260605033235.717351-1-pasha.tatashin@soleen.com> 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 Content-Type: text/plain; charset="utf-8" Move kho_block.h to kho/block.h, organizing it within the existing kho directory structure as more KHO data structures are introduced. This is a pure code movement patch; no logic or functional changes are introduced. Signed-off-by: Pasha Tatashin --- Documentation/core-api/kho/index.rst | 2 +- MAINTAINERS | 1 - include/linux/{kho_block.h =3D> kho/block.h} | 2 +- kernel/liveupdate/kho_block.c | 2 +- kernel/liveupdate/luo_internal.h | 2 +- kernel/liveupdate/luo_session.c | 2 +- 6 files changed, 5 insertions(+), 6 deletions(-) rename include/linux/{kho_block.h =3D> kho/block.h} (100%) diff --git a/Documentation/core-api/kho/index.rst b/Documentation/core-api/= kho/index.rst index a10b10700fb9..4a5477221fe4 100644 --- a/Documentation/core-api/kho/index.rst +++ b/Documentation/core-api/kho/index.rst @@ -95,7 +95,7 @@ KHO Serialization Blocks API .. kernel-doc:: kernel/liveupdate/kho_block.c :doc: KHO Serialization Blocks =20 -.. kernel-doc:: include/linux/kho_block.h +.. kernel-doc:: include/linux/kho/block.h =20 .. kernel-doc:: kernel/liveupdate/kho_block.c :internal: diff --git a/MAINTAINERS b/MAINTAINERS index 920ba7622afa..9ec290e38b44 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14208,7 +14208,6 @@ F: Documentation/admin-guide/mm/kho.rst F: Documentation/core-api/kho/* F: include/linux/kexec_handover.h F: include/linux/kho/ -F: include/linux/kho_block.h F: kernel/liveupdate/kexec_handover* F: lib/test_kho.c F: tools/testing/selftests/kho/ diff --git a/include/linux/kho_block.h b/include/linux/kho/block.h similarity index 100% rename from include/linux/kho_block.h rename to include/linux/kho/block.h index 93a7cc2be5f5..2b9d5a080a6a 100644 --- a/include/linux/kho_block.h +++ b/include/linux/kho/block.h @@ -7,9 +7,9 @@ #ifndef _LINUX_KHO_BLOCK_H #define _LINUX_KHO_BLOCK_H =20 +#include #include #include -#include =20 /** * struct kho_block - Internal representation of a serialization block. diff --git a/kernel/liveupdate/kho_block.c b/kernel/liveupdate/kho_block.c index 0d2a342ef422..6cedcd36bfd2 100644 --- a/kernel/liveupdate/kho_block.c +++ b/kernel/liveupdate/kho_block.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include =20 /* diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_inter= nal.h index 64879ffe7378..349f6d141873 100644 --- a/kernel/liveupdate/luo_internal.h +++ b/kernel/liveupdate/luo_internal.h @@ -8,9 +8,9 @@ #ifndef _LINUX_LUO_INTERNAL_H #define _LINUX_LUO_INTERNAL_H =20 +#include #include #include -#include =20 struct luo_ucmd { void __user *ubuffer; diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_sessio= n.c index b79b2a488974..01c0ccf09919 100644 --- a/kernel/liveupdate/luo_session.c +++ b/kernel/liveupdate/luo_session.c @@ -90,8 +90,8 @@ #include #include #include -#include #include +#include #include #include #include --=20 2.53.0 From nobody Mon Jun 8 08:32:27 2026 Received: from mail-qv1-f54.google.com (mail-qv1-f54.google.com [209.85.219.54]) (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 B57B73655E3 for ; Fri, 5 Jun 2026 03:33:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630432; cv=none; b=RAlcR9+githLKuh0oNYO+0ahiHp5Ouf1ujvTjmixTS819gdjd7hRXD0X/hrYylXIz+fwzxlTW8b1FBQokadHzCTwY5ogJT7ujj5RLDOYeypl0P0j+BiobJ97dcQiIm8vtc3DvTYUBPEyFVPm42p9tQoryEQoSFk9kpa/oVFNR1c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630432; c=relaxed/simple; bh=56yqutzR1Yl+W9ZaMZOq3iC0gVO2m06Akdi9QmEvda8=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=r30YMs2Fnla9jaM55AFacSoG3B1kkt2Zr3ANmNHKGq//2jklS/5jD7IrZkb9PA20HR98AA6gFW1sJf+asjX+VTDwy8Kn1jmtfXBmMf3aq82Mj1jDu0BJP3871R8y4gfYwpyYlsC+nTGAmAII2yWg8chF9aGrirE6gPyrz74OrYc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com; spf=pass smtp.mailfrom=soleen.com; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b=D0W+7Zzt; arc=none smtp.client-ip=209.85.219.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=soleen.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b="D0W+7Zzt" Received: by mail-qv1-f54.google.com with SMTP id 6a1803df08f44-8cd45d4b7e2so16072046d6.2 for ; Thu, 04 Jun 2026 20:33:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1780630427; x=1781235227; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=MTLNc6RdVPC/3p3BVrwRRbnK/J4mwuIt5WmEdvU+mDY=; b=D0W+7ZztxxXsozC80rxLJ/joznPxT4/iqyUWCky8LY8NoSvhytGAxZAlcFv1g/n0O/ 00+vv4yG0f5K5V+nuMb3+lqNRDnD2R7sZ77OGVZQ2X8f8qfbq53DnGd8XUV1hCHVMXJ5 LHYVD9H7/gSe9lpoPhHNX+5OUSe8Lj9Rwoe3HSAy+/4uth2C4WGLA0CG/L7nVomjwt0Q y/u/FLapZ5V6QZeeswCumZDmUzFZN8twmjMPDKGtQr6SUnScMTdX7qS6aqvVi5kLOZ8X qZbMVXLoE9oobLusvE4UGIJ8zWafweXWAP1W78zGomnEJAH6NrzplN4JeYCgBGQBDnXp qnDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780630428; x=1781235228; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=MTLNc6RdVPC/3p3BVrwRRbnK/J4mwuIt5WmEdvU+mDY=; b=Ld9jDXDull/66LTzgyk0pYjJOrCLBHlAP9S5gKGr6+UJvm0NtpVlKV8sBOvbI24kKP AiGUD4lXpo6pl/8OLv8SOUNaA39fCGuKs8IJpnSQlwBN07k6CfqHQjY5unJAmojlo/xe rVtqIsOULkJZQygpZb0Utb1UksiugFv7xt2gm8JmhLJCIC2UJGJXT71tgOn+/E96V+8z R1TAPwX3PCesg2ie+tKdXBGqtY5NibIYHiiHpoUEflrmaq36Ugy0RmoMm4wmKFJ5gelv l8byCljBAhq22g0MyZGF6p2sqJPwISRYjtdebMPFNq29US1kxQ/qbPUZBMSlg4zMDBCt 2NYg== X-Forwarded-Encrypted: i=1; AFNElJ+9u05vCKdCA8KEjfA/m3Aw1CIceTGxeL9MM73nzcDVqufI+IQbQnrS1Y0Nd6Fu7I+mSoB4gRiHkspwg+g=@vger.kernel.org X-Gm-Message-State: AOJu0YzprSWF2GhE+NDDgtZZ+FNcrK8Cd8Xd7YAmo/XW7Ol0vE63nK+q aXSn4kfp/sUghc4guwLxuEDq1I/u20/s5vCrIdZleSeFtLnibyMx84V/BdCnL7hlAfU= X-Gm-Gg: Acq92OESpLPI90MaAITJCQB56JboPGUaqmfPIKObjT4frUG5nvt4+2goYhWqxkpYUrh 1L0d7+2cWf/Rzd7H69qYnBQ1yPekaucv9liEInSXf3y6g3zxEAUJ4taSsadGDHizJlykf7r9Pq1 Khsk+h0IKF++TMb1zOFIzfWKEK9H9sr4TFGGy5S3jlgS9lQVY8j/T1y/b3/cxuHGURPnSdJmmR4 U6yb9EmH+fjOUW5qW3/Qm575E663CuCQ5vV72gmq6jlytumW2ePlmsutQjka9Tm58/eAJWFkv2d DyGiwfjm72eCGxHlJkSSbK5Mv/kA5ZJWfYmQ/dF0x76iuye7yVMLCfGWC4C+yThXbDbj1I1zqV0 0jmo+qLS5B6o4xonNPg7y1tlp04nWG7D3tENzxeTxpxugdcjG/cXwzQBBk+28T2cF0twslIOcWp QMJoFd8oLX5hQqjpdK/lSYw0L2ogdvBAecvSlO278cGBhjWxDCwNTsAELH1ef8ug== X-Received: by 2002:a05:6214:8088:b0:8cc:58f2:339f with SMTP id 6a1803df08f44-8cee601673fmr33023096d6.16.1780630427604; Thu, 04 Jun 2026 20:33:47 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8ceccd9fc7dsm70512926d6.5.2026.06.04.20.33.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jun 2026 20:33:47 -0700 (PDT) From: Pasha Tatashin To: linux-kselftest@vger.kernel.org, rppt@kernel.org, shuah@kernel.org, akpm@linux-foundation.org, linux-mm@kvack.org, skhan@linuxfoundation.org, linux-doc@vger.kernel.org, jasonmiu@google.com, linux-kernel@vger.kernel.org, corbet@lwn.net, ran.xiaokai@zte.com.cn, pasha.tatashin@soleen.com, kexec@lists.infradead.org, pratyush@kernel.org, graf@amazon.com Subject: [RFC v1 6/9] kho: introduce compatibility helpers and decouple block version Date: Fri, 5 Jun 2026 03:32:32 +0000 Message-ID: <20260605033235.717351-7-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260605033235.717351-1-pasha.tatashin@soleen.com> References: <20260605033235.717351-1-pasha.tatashin@soleen.com> 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 Content-Type: text/plain; charset="utf-8" Decouple the block compatibility string from the global KHO version. Introduce a compatibility helper header (compat.h) defining utility macros for constructing subsystem compatibility strings, specifically: - KHO_SUB_COMPAT() to append sub-component compatibility strings using a semicolon separator. - KHO_COMPAT_ALIGN() to align compatibility string sizes to 8-byte boundaries. Define the individual block compatibility string "block-v1" in block.h, and integrate it into the composite LUO compatibility string (LUO_ABI_COMPA= TIBLE) via the new compatibility helpers. Signed-off-by: Pasha Tatashin --- include/linux/kho/abi/block.h | 4 +++- include/linux/kho/abi/compat.h | 33 +++++++++++++++++++++++++++++++++ include/linux/kho/abi/luo.h | 8 ++++++-- 3 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 include/linux/kho/abi/compat.h diff --git a/include/linux/kho/abi/block.h b/include/linux/kho/abi/block.h index d06d64b963be..95d13cf677cf 100644 --- a/include/linux/kho/abi/block.h +++ b/include/linux/kho/abi/block.h @@ -14,7 +14,7 @@ * This interface is a contract. Any modification to the structure fields, * compatible strings, or the layout of the `__packed` serialization * structures defined here constitutes a breaking change. Such changes req= uire - * incrementing the version number in the `KHO_FDT_COMPATIBLE` string to + * incrementing the version number in the `KHO_BLOCK_COMPATIBLE` string to * prevent a new kernel from misinterpreting data from an old kernel. * * Changes are allowed provided the compatibility version is incremented; @@ -28,6 +28,8 @@ #include #include =20 +#define KHO_BLOCK_COMPATIBLE "block-v1" + /** * KHO_BLOCK_SIZE - The size of each serialization block. * diff --git a/include/linux/kho/abi/compat.h b/include/linux/kho/abi/compat.h new file mode 100644 index 000000000000..25edd964c390 --- /dev/null +++ b/include/linux/kho/abi/compat.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2026 Google LLC. + * Pasha Tatashin + */ + +#ifndef _LINUX_KHO_ABI_COMPAT_H +#define _LINUX_KHO_ABI_COMPAT_H + +#include + +/** + * KHO_SUB_COMPAT - Helper to append a sub-component compatibility string. + * @str: The compatibility string of the sub-component. + * + * Appends a KHO safe data structure compatibility string to a sub-system + * compatibility string using a semicolon ';' as a separator. + * + * NOTE: Sub-components MUST be added in strict alphabetical order to main= tain + * a consistent and predictable compatibility string value. + */ +#define KHO_SUB_COMPAT(str) ";" str + +/** + * KHO_COMPAT_ALIGN - Align a compatibility string size to 8 bytes. + * @str: The compatibility string. + * + * Aligns the size of a compatibility string to an 8-byte boundary for use + * in ABI structures. + */ +#define KHO_COMPAT_ALIGN(str) ALIGN(sizeof(str), 8) + +#endif /* _LINUX_KHO_ABI_COMPAT_H */ diff --git a/include/linux/kho/abi/luo.h b/include/linux/kho/abi/luo.h index 288076de6d4a..b502670cd2a6 100644 --- a/include/linux/kho/abi/luo.h +++ b/include/linux/kho/abi/luo.h @@ -58,6 +58,7 @@ #define _LINUX_KHO_ABI_LUO_H =20 #include +#include #include #include =20 @@ -65,8 +66,11 @@ * The LUO state is registered under this KHO entry name. */ #define LUO_KHO_ENTRY_NAME "LUO" -#define LUO_ABI_COMPATIBLE "luo-v5" -#define LUO_ABI_COMPAT_LEN ALIGN(sizeof(LUO_ABI_COMPATIBLE), 8) +#define LUO_ABI_COMPAT_BASE "luo-v5" +#define LUO_ABI_COMPATIBLE \ + LUO_ABI_COMPAT_BASE \ + KHO_SUB_COMPAT(KHO_BLOCK_COMPATIBLE) +#define LUO_ABI_COMPAT_LEN KHO_COMPAT_ALIGN(LUO_ABI_COMPATIBLE) =20 /** * struct luo_ser - Centralized LUO ABI header. --=20 2.53.0 From nobody Mon Jun 8 08:32:27 2026 Received: from mail-qk1-f181.google.com (mail-qk1-f181.google.com [209.85.222.181]) (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 3AB322EEE98 for ; Fri, 5 Jun 2026 03:34:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630441; cv=none; b=dZWeF3JwL/ZJ/yT1nijxdDhNlq7kaXoPAIlXEcuPAQJWUBAxuu4FSgLSDFfMiZqAk/VuFZb1FVFLWEINXXaWvPdbb7x7OcNmSo0ph3q4WSnlcw5vT97Ie0JjONl7vl/tAIbsfnenEPU5TEpub70MQm0cUXBrbmIfpee7AnR/D2A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630441; c=relaxed/simple; bh=eU1fOM4eOd3z2yeGVKb+QlTsoAWC8tuz1WiFB/USShI=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pdvGvBSl4aeUO4KeOsOKvMdhAPtjbMnS8F7XnR++DLKd0D14+5BB8b9sx2Bjj1bJmkjoaMHsUXQKuwbMZ654USteSJIxsK0Da7TLZQSyFOi+liCu+xG4PyrUCkHPlCDh8k7mnA4mjENbwRMsygx2zb6IPwQ+7V0mRdBmqwbkyXc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com; spf=pass smtp.mailfrom=soleen.com; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b=PfIkSFJC; arc=none smtp.client-ip=209.85.222.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=soleen.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b="PfIkSFJC" Received: by mail-qk1-f181.google.com with SMTP id af79cd13be357-9155183b42cso211061085a.0 for ; Thu, 04 Jun 2026 20:34:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1780630439; x=1781235239; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=jYmKPVlEdqw9nJIpln28SQxgNWXUbITnOaKq2Dm+DFI=; b=PfIkSFJC+zV/o6fdsI/6c3+0vJ0o0jwIIpnyxNvKze0ap7rp+yjGJrvLdY9QbEohFT Qwm2MCJZKPyHGXgPXHT0w0VK4JJUUboaQpsa5D9CgxK6olxY3ztzbr5o6OOaoVCe3e+I 8zshjfRj0Gp5cXUcmFeBaaCSu6jd95Nzzj0fCty1RvrT59rrEWImby0ymEEIjh8Ad5Po 6ERVqtLVOy6y4BI1bZboowhNwuZXMJKYt4EcleWES4eGY09Bpeq3LlhjD/14COipbQ+F 9f0KsTt0nq03AIqxtbuLrS6tdsm4IO5ylKwCWE93go4VTTL6gbOJ9exGwdI3yPPXYajR zCZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780630439; x=1781235239; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=jYmKPVlEdqw9nJIpln28SQxgNWXUbITnOaKq2Dm+DFI=; b=rqzPgrsJc1q1LcmrPkNWSCmfwBEOECJL5K46+y7ZMCTXjM120T9XhZ/c/ZziBEFRVO z5/i+KEWPd+nkJ7QMSJqMW2xXCPFTfaOYQIbMKHD04bIVeQ1FFt0/FWPAMwBli4onBRS Fa20eb9sNmeGVJdjzHf+99AdwkwjWpe5Lt3Ab5nkxDLMqlzgABSY3RFZcOKt8+D3w+WU v2FOpCr4LKnhPypXgn5peCf8lLJBo4rEFLqQHb/TShzMBKj0o3sbk8B/aVsscgBNEeMo vEEXfUDSWQSWkpEDB43oHE/WKNDJbD2sqpKdNOF6olgAu3URqA2S0WaABjKcowHrooc3 HvxA== X-Forwarded-Encrypted: i=1; AFNElJ9z5IkiG/h6Z85ss2h+u9WkoY8Ff4a1RL1O9gYpgRiNkr0YOt/pX3mc8WvBLGbr2eASazhxQSx40r9TaII=@vger.kernel.org X-Gm-Message-State: AOJu0YxMoAJualgAHTj3BwOnHgKoZniSmwQZxn2tEbFHMxSp8ccAR4IS NmC8P1HtrUC232MSsM+eQm+viP9uvFFBZY+5ApNUcc/OSmQpi9pRYK1RzrL2MK116FQ= X-Gm-Gg: Acq92OGpPyhRUt3q69tdyyl6YZwjWz05vyoCMhAKGxczBKGAexaT00URJJRDkFdbPnr VEiREUyNMajtMHw6KldXgDuXZM1oOEujrmnA/7CPg1G5zIx2GMYlrll7Wcxj6p0hMuK3aTSUQ9g jokqyRfnWF4HWSDwiqtRxjGN7ESHWGrz0ecHzM835tZ3jHNHc2s5rmDNeDG3iRAa3c7OsUCQBBO qy7THKWQ4Yc1Nelphyq+dAvkTmYVgfBFFHIxBTeJlPrcT8gqNRN/V4eRAV9Ldonigk7e7K2jJnX NI0GrRWqC0XEkGmG5D3VFpyF2+ZO9OUzYRVEZqt/J/miVNgfOg5Q0v7FyjqxfDETofCQ/pJEvhv d0NW6vZRuK19jPu3f0Da80rk48Pf+DpWlPBftfaRxBGTU5RQ6H3SMRxoNM34pg6/756y3aGjFpw GnXnFzmCqN317qJeC7NwS0X0oQ5YvNDELdpcHI7DGKfbXOknTpXjK0s4KDpLwrjA== X-Received: by 2002:a05:620a:450c:b0:8cd:d688:7aef with SMTP id af79cd13be357-915ad197c8dmr107318585a.19.1780630439344; Thu, 04 Jun 2026 20:33:59 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id af79cd13be357-91589ea0bcfsm780607085a.0.2026.06.04.20.33.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jun 2026 20:33:59 -0700 (PDT) From: Pasha Tatashin To: linux-kselftest@vger.kernel.org, rppt@kernel.org, shuah@kernel.org, akpm@linux-foundation.org, linux-mm@kvack.org, skhan@linuxfoundation.org, linux-doc@vger.kernel.org, jasonmiu@google.com, linux-kernel@vger.kernel.org, corbet@lwn.net, ran.xiaokai@zte.com.cn, pasha.tatashin@soleen.com, kexec@lists.infradead.org, pratyush@kernel.org, graf@amazon.com Subject: [RFC v1 7/9] kho: decouple radix tree compatibility from global KHO version Date: Fri, 5 Jun 2026 03:32:33 +0000 Message-ID: <20260605033235.717351-8-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260605033235.717351-1-pasha.tatashin@soleen.com> References: <20260605033235.717351-1-pasha.tatashin@soleen.com> 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 Content-Type: text/plain; charset="utf-8" Decouple the kho radix tree compatibility version from the global KHO compatibility version KHO_FDT_COMPATIBLE. Define the independent compatibility version "radix-v1" for the radix tree KHO_RADIX_COMPATIBLE in radix_tree.h. Integrate KHO_RADIX_COMPATIBLE into the composite root compatibility string KHO_FDT_COMPATIBLE. Additionally, document the new KHO Compatibility ABI under the Documentation/core-api/kho/abi.rst section. Signed-off-by: Pasha Tatashin --- Documentation/core-api/kho/abi.rst | 5 +++++ include/linux/kho/abi/kexec_handover.h | 10 ++++++---- include/linux/kho/abi/radix_tree.h | 4 +++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Documentation/core-api/kho/abi.rst b/Documentation/core-api/kh= o/abi.rst index b61363679829..6acdb7c85239 100644 --- a/Documentation/core-api/kho/abi.rst +++ b/Documentation/core-api/kho/abi.rst @@ -10,6 +10,11 @@ Core Kexec Handover ABI .. kernel-doc:: include/linux/kho/abi/kexec_handover.h :doc: Kexec Handover ABI =20 +KHO Compatibility ABI +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +.. kernel-doc:: include/linux/kho/abi/compat.h + vmalloc preservation ABI =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi= /kexec_handover.h index c893b5045078..49ac4b47cc3d 100644 --- a/include/linux/kho/abi/kexec_handover.h +++ b/include/linux/kho/abi/kexec_handover.h @@ -8,9 +8,8 @@ =20 #ifndef _LINUX_KHO_ABI_KEXEC_HANDOVER_H #define _LINUX_KHO_ABI_KEXEC_HANDOVER_H -#include - -#include +#include +#include =20 /** * DOC: Kexec Handover ABI @@ -85,7 +84,10 @@ */ =20 /* The compatible string for the KHO FDT root node. */ -#define KHO_FDT_COMPATIBLE "kho-v4" +#define KHO_FDT_COMPAT_BASE "kho-v4" +#define KHO_FDT_COMPATIBLE \ + KHO_FDT_COMPAT_BASE \ + KHO_SUB_COMPAT(KHO_RADIX_COMPATIBLE) =20 /* The FDT property for the preserved memory map. */ #define KHO_FDT_MEMORY_MAP_PROP_NAME "preserved-memory-map" diff --git a/include/linux/kho/abi/radix_tree.h b/include/linux/kho/abi/rad= ix_tree.h index f4cc5c02f37a..89cd7eb4a91d 100644 --- a/include/linux/kho/abi/radix_tree.h +++ b/include/linux/kho/abi/radix_tree.h @@ -20,7 +20,7 @@ * This interface is a contract. Any modification to the structure fields, * compatible strings, or the layout of the serialization structures defin= ed * here constitutes a breaking change. Such changes require incrementing t= he - * version number in the `KHO_FDT_COMPATIBLE` string to prevent a new kern= el + * version number in the `KHO_RADIX_COMPATIBLE` string to prevent a new ke= rnel * from misinterpreting data from an old kernel. * * Changes are allowed provided the compatibility version is incremented; @@ -94,6 +94,8 @@ * 4KB. */ =20 +#define KHO_RADIX_COMPATIBLE "radix-v1" + /* * Defines constants for the KHO radix tree structure, used to track prese= rved * memory. These constants govern the indexing, sizing, and depth of the t= ree. --=20 2.53.0 From nobody Mon Jun 8 08:32:27 2026 Received: from mail-qk1-f172.google.com (mail-qk1-f172.google.com [209.85.222.172]) (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 F296A3D7D8D for ; Fri, 5 Jun 2026 03:34:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630454; cv=none; b=ZJJvt1C+mRbkLk5ZyQcZ4ViliqlYYoH2ktIWGxeyWtPU/gEp7pux+HPl/nBFG/mGYqxYkJWVZrt7dOyKfrLH0y1j02w4JSsKNPmdlbUnCg8e0ODLiimxlI7wWikEBcKgJlT6UGI/42YN7CBTFE2cgujyHccSqLSRDqXyIX8/nHM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630454; c=relaxed/simple; bh=gG+BMzTQAvQ99ajXilaSRudbxpmfCpeFzhzw+IUPT7Y=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eOzd0y/Y6o4z38+cYxfTbuv10TkQTOY0+A8y1Wx6md57FtauEzqyxr8LnXLzn3yK8cq7vUCLZvlu521jgKY/hz+uBBigV9+SEl8OrLa0oOlVLEFSD32A164z/5SDdLqBUc6jbguxITIdp/na6vQjMNoSq5DfGkBJ3kbLDIiKpc8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com; spf=pass smtp.mailfrom=soleen.com; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b=lGJL4ynJ; arc=none smtp.client-ip=209.85.222.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=soleen.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b="lGJL4ynJ" Received: by mail-qk1-f172.google.com with SMTP id af79cd13be357-91587626a3eso182710385a.2 for ; Thu, 04 Jun 2026 20:34:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1780630452; x=1781235252; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=2YcWKgEizOcY9z0vq5q3df4Dwqk/3q2KHCFvnTeL730=; b=lGJL4ynJqM5hV2myVR4/CaQ0T32pZ5fy4ZVzaNNabzCaj0xXm9co9facJb0a2boji3 YRtpNZVdrcCoqWRh9LL9YTI2nquCLecmsJIlqWuDItCpG+rKuV9/7ZPbD6iFxR38AJvT J1lVBTiaj3eVEiBBUOJgeGygq2+gYEDXHVib157pFnbR6g9gEgmdUYN1pJ1GhLBHduuD gK5ZJ/V5sfQ/jUgQrkaXHmoIbvlzEgn32w/bgr7MKuetzuDz0kWPGZdlywMtQxtRqfKK VbUU+5fBF7+KGKd5T7YUlb9Gt7KpZd3sk2X82RC5eBYOjA2naZWxpoqVtUDYdXx9IPSS VAQA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780630452; x=1781235252; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=2YcWKgEizOcY9z0vq5q3df4Dwqk/3q2KHCFvnTeL730=; b=Gv+aIASggaRYppduB6gPLdVCtlsadoxsj4tx96gQXjFtmrpibGxjPX9T3PfbqVo5Ou FekIzV5kQ2hGAk5cweSwboirpXqrWDwG15GkMYhy542fnAArW+Q0AiLPqb1z6HQPj/dm VudThOlstEClSSIDRJPCbwAEzU2V7TCvKaNe05GEUf/ALZDHw5CZ8SlPN38zL6RqBQJr OVKiY73NPnSNGVozszGSbGzjyUlrpTvL1o2S0APdByXLwzAdthnCNWZl2ilLDfO6MZJh /5vcc+sVyIGouEp14Uq48nJ/JuylQ7HE70TnWZSmZvaWlPH6qEjLMO2V3t3n/x/XSykS ljJw== X-Forwarded-Encrypted: i=1; AFNElJ/yUtec/YysifU6SC1ykqVC1Cp7qJ225Xrl0IYPayPmXrv18kdgGyfhLRgCsDJUMS0EXwTZVfpdfIRSbzc=@vger.kernel.org X-Gm-Message-State: AOJu0Yz/6ibCxop2RuQQaYX90eTsrV8WxKRU+VUvucy/869yHmUw2D6p Nke57vU8k0PdkdNr7TIv+ft0q2UHiNDZf4oeMChvd2Ivym3fXhVJtPvdmo13chmt1cg= X-Gm-Gg: Acq92OF0sTTuoc4f9+wY2KdsA0DH9VxiO8/u81KnyFreAtcnDp/k7oMeu9GdcVRJ1sK Q7VVLlNx2WA5XSR68ZGu/fm3jMIB0BaAvVHsOjL5F5P0hEiaJXKgVnsUpREZ9RtZOwnkj9ZbHl1 fBeA610CDt5eQhd8fFv429Wrcym4TtOjFodyILic+Fd8YIqX10N7PMGWOpaNwSO08XpmhEfbJ8D IshT2etCjoRtsqC6CPZvW1G5It8c8w1sg3m9InGC2iVNz0LBeSk/Dlt2sLwqOJeMu6Cd2spxcJS 9NykiZv5T6Jgp2tHqsRsX2KY5AYQ3Sh+5sqMk9uj/q50REZjn0c0yhVYA8UZBQ1Pvcg4w3wj9iR GElxtZT2JQFXeRFKF47i7xS9EZRMbJ30YJL0VX83IkA4Es4t++NMHlRKewuYji+I/li0NCCckDS GzzK++/kfXUxqxU3UtwVjdbsngSt2ghO3fSL1WBnzTt3RCtCczXUYRLpdI9SWaOw== X-Received: by 2002:a05:620a:f0e:b0:915:a953:4b93 with SMTP id af79cd13be357-915a9c4b267mr362733285a.3.1780630451754; Thu, 04 Jun 2026 20:34:11 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id af79cd13be357-9158a00b474sm768496585a.10.2026.06.04.20.34.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jun 2026 20:34:10 -0700 (PDT) From: Pasha Tatashin To: linux-kselftest@vger.kernel.org, rppt@kernel.org, shuah@kernel.org, akpm@linux-foundation.org, linux-mm@kvack.org, skhan@linuxfoundation.org, linux-doc@vger.kernel.org, jasonmiu@google.com, linux-kernel@vger.kernel.org, corbet@lwn.net, ran.xiaokai@zte.com.cn, pasha.tatashin@soleen.com, kexec@lists.infradead.org, pratyush@kernel.org, graf@amazon.com Subject: [RFC v1 8/9] kho: decouple vmalloc compatibility from global KHO version and update memfd Date: Fri, 5 Jun 2026 03:32:34 +0000 Message-ID: <20260605033235.717351-9-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260605033235.717351-1-pasha.tatashin@soleen.com> References: <20260605033235.717351-1-pasha.tatashin@soleen.com> 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 Content-Type: text/plain; charset="utf-8" Decouple the vmalloc preservation compatibility version from the global KHO compatibility version KHO_FDT_COMPATIBLE. Define the independent compatibility version "vmalloc-v1" for vmalloc preservation KHO_VMALLOC_COMPATIBLE in vmalloc.h. Integrate KHO_VMALLOC_COMPATIBLE into the composite root compatibility string KHO_FDT_COMPATIBLE. Additionally, update the memfd compatibility string MEMFD_LUO_FH_COMPATIBLE to include the vmalloc compatibility dependency, and add a static assertion to verify its length limit. Signed-off-by: Pasha Tatashin --- include/linux/kho/abi/kexec_handover.h | 4 +++- include/linux/kho/abi/memfd.h | 9 ++++++++- include/linux/kho/abi/vmalloc.h | 6 ++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi= /kexec_handover.h index 49ac4b47cc3d..f048bc95fed3 100644 --- a/include/linux/kho/abi/kexec_handover.h +++ b/include/linux/kho/abi/kexec_handover.h @@ -10,6 +10,7 @@ #define _LINUX_KHO_ABI_KEXEC_HANDOVER_H #include #include +#include =20 /** * DOC: Kexec Handover ABI @@ -87,7 +88,8 @@ #define KHO_FDT_COMPAT_BASE "kho-v4" #define KHO_FDT_COMPATIBLE \ KHO_FDT_COMPAT_BASE \ - KHO_SUB_COMPAT(KHO_RADIX_COMPATIBLE) + KHO_SUB_COMPAT(KHO_RADIX_COMPATIBLE) \ + KHO_SUB_COMPAT(KHO_VMALLOC_COMPATIBLE) =20 /* The FDT property for the preserved memory map. */ #define KHO_FDT_MEMORY_MAP_PROP_NAME "preserved-memory-map" diff --git a/include/linux/kho/abi/memfd.h b/include/linux/kho/abi/memfd.h index af310c0c9fdf..24ecbf48cbe1 100644 --- a/include/linux/kho/abi/memfd.h +++ b/include/linux/kho/abi/memfd.h @@ -11,7 +11,9 @@ #ifndef _LINUX_KHO_ABI_MEMFD_H #define _LINUX_KHO_ABI_MEMFD_H =20 +#include #include +#include #include #include =20 @@ -89,6 +91,11 @@ struct memfd_luo_ser { } __packed; =20 /* The compatibility string for memfd file handler */ -#define MEMFD_LUO_FH_COMPATIBLE "memfd-v2" +#define MEMFD_LUO_FH_COMPAT_BASE "memfd-v2" +#define MEMFD_LUO_FH_COMPATIBLE \ + MEMFD_LUO_FH_COMPAT_BASE \ + KHO_SUB_COMPAT(KHO_VMALLOC_COMPATIBLE) + +static_assert(KHO_COMPAT_ALIGN(MEMFD_LUO_FH_COMPATIBLE) <=3D LIVEUPDATE_HN= DL_COMPAT_LENGTH); =20 #endif /* _LINUX_KHO_ABI_MEMFD_H */ diff --git a/include/linux/kho/abi/vmalloc.h b/include/linux/kho/abi/vmallo= c.h index 87650e1dd774..1847b82e147b 100644 --- a/include/linux/kho/abi/vmalloc.h +++ b/include/linux/kho/abi/vmalloc.h @@ -9,13 +9,13 @@ * * The Kexec Handover ABI for preserving vmalloc'ed memory is defined by * a set of structures and helper macros. The layout of these structures i= s a - * stable contract between kernels and is versioned by the KHO_FDT_COMPATI= BLE + * stable contract between kernels and is versioned by the KHO_VMALLOC_COM= PATIBLE * string. * * This interface is a contract. Any modification to the structure fields, * compatible strings, or the layout of the serialization structures defin= ed * here constitutes a breaking change. Such changes require incrementing t= he - * version number in the `KHO_FDT_COMPATIBLE` string to prevent a new kern= el + * version number in the `KHO_VMALLOC_COMPATIBLE` string to prevent a new = kernel * from misinterpreting data from an old kernel. * * Changes are allowed provided the compatibility version is incremented; @@ -36,6 +36,8 @@ #include #include =20 +#define KHO_VMALLOC_COMPATIBLE "vmalloc-v1" + /* Helper macro to define a union for a serializable pointer. */ #define DECLARE_KHOSER_PTR(name, type) \ union { \ --=20 2.53.0 From nobody Mon Jun 8 08:32:27 2026 Received: from mail-qt1-f178.google.com (mail-qt1-f178.google.com [209.85.160.178]) (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 6A18C3988F8 for ; Fri, 5 Jun 2026 03:34:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630465; cv=none; b=Poc6Dig0s9CxooCgKnwlqe7sFvxOsD2XyehR2pFbEGkx2U9CojQ+zHbUluOpiXnJ0km2l0fNwDOXKiQ29n5N+oiDi739mAFiWi+yCwPaMEKb7MYPN2BXQ6WVMXDKC0gDjK3tmm7Ek33AwrWBPgsP6hxvoApbTBfaYmPVi6EWzyk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780630465; c=relaxed/simple; bh=EryfO6BIhkEjNjxl4nuOnpJQVHpd6RmCotJcy7+BaGQ=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GY957zLnMCFkQAYvhuGx2Q5KaNBnkK6tqkt8WMI8MMQZLy7kA7lO8r6VAqYUQIvsdTAUuTHQpEXuPKhCQYCxcxDmoqTbCODtpBG5s4Ste0xSvCPhZutXyP0MPlWNt/JjlP3drwIrjuriEiQPQ7H3dLHQyW6KJ8CPbiEXH+7E7t0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com; spf=pass smtp.mailfrom=soleen.com; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b=fpwL7b4m; arc=none smtp.client-ip=209.85.160.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=soleen.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b="fpwL7b4m" Received: by mail-qt1-f178.google.com with SMTP id d75a77b69052e-516e1525aa3so17514041cf.3 for ; Thu, 04 Jun 2026 20:34:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1780630463; x=1781235263; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=rfxlNkzCx8TA3SebJdSu06wI/is0K0+hQNvlMemiJzs=; b=fpwL7b4mVbU5SWWgO7SMj/OjXxWa785AG4w3MSGrnRIBYHpNpz3QZRhK7EvOP96BzM 89Ep7ecmEBt1skBHo3gW3OBBseh91kz75FC3z6aOVnx0utwLmcmRGHpzovaZxwrpLmBo +3nATnatQF4+QDE/0Wh8t09jaBDtHxVwboemJu7RofMpZhSmaF1TCgQFDZ7X4+MLwY1D sff4Uu1SBOVncw92VZ1WHAy8MlBj8k2NYg22YwjcZB0z2UdXZHPOLRD0JdpU7kGkzP59 fnDVDYTeskdhJ8KVqWftlhEErYj4rMOwpsm6CfnPyACWhyN26ee/JAAebnslaGSmmUMw YchA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780630463; x=1781235263; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=rfxlNkzCx8TA3SebJdSu06wI/is0K0+hQNvlMemiJzs=; b=nAz2ioviLpQjd0i2dOJrU0pw/WwD42h+xquWZ87g2QrvzMSaJS35dmlrV2rBVih+vd ewgUwht6wNWyk71kLM900/pckiQ7z3N8d77/ip+CJy2Nlg50pbRQf8CUVWSUv3OVkIWG ZhnJ7d/XTP1YtrgQyuV6t/AAfuhVqy5vK/p/Rf7Z0hmR9mIDuHACT8vg0QLZz8b1FsX5 5VQHRw767epa3vSPiXVTCBL2KaWY4G0e2DZdKeGYoGIX+OrsvYImvn2/mMs98ojlgBgH XqXravMbiS8JOzMMCL8VyelAowOSxry7IY7pQptqAJOObjDFXWFzvWBuCrIttD/wHHix qySw== X-Forwarded-Encrypted: i=1; AFNElJ99JQWzH/U5CxcCcvcA/vEJnCBgrUVvkYoL0kDOTHDsq3w8XiR97IC+sid3C/Pj+hwE0B2kFJlh6451HqE=@vger.kernel.org X-Gm-Message-State: AOJu0YyX/QvNwC/W8dBUS7vDQfje+twfsktxxwjUdhx+CDz3igYoUxcT 6ZIYMxc8mOKPrRls+X4vlIExW/KC17J0VKKPCB+bCdnypZS6xdXsMayI6tvJm4qBjt8= X-Gm-Gg: Acq92OE4A2bDaAIJoeIOaJy06IzlRkKhqheZJiGjy1+Haqq07OQUnXd8cSi4Ll/rXmp 8onPKAA3TWlkvOjJKYrlqN8bZ91TOh2todkDy59A3Ppj5Ll1dmF2WxU46pMqVc+l6AbnvcPpYgc qoLayQwVI2wkZb80TLiD+IpdcxvL5nHbyMwuDTXzUlnWkeWDrtl1OVfCdfxL1R03OE9xg7l9R5n hAFKK8RykczbhmbpCWxwUY6CmVRTYgBqIIDKf419is5cMxg3QhJdLKH9EAtYZVnZX1YJhfGM5mG gDNCFxGc1vARLLvySSIXfcm5EH3BGrcw40nux1zvHkm+3re5VsjqXhyNcCIIlimy8OvJWmuMXMq /HtrEOjsLxRR1neykVc2UIxDZvTBpaOVkcU88PlYMmtQ3yZbOo/I9M9m+CAkgpMR8erCdmgEInR CKfnXZNhjT5B5QhSRj/eGqili3bYmbxBC/RRnqU81UByBcTWgKvvLkIMXm3G9O9A== X-Received: by 2002:a05:622a:4106:b0:517:6665:2a9a with SMTP id d75a77b69052e-51795c920f2mr28080531cf.50.1780630463488; Thu, 04 Jun 2026 20:34:23 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-51775df4dd6sm67871381cf.27.2026.06.04.20.34.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jun 2026 20:34:23 -0700 (PDT) From: Pasha Tatashin To: linux-kselftest@vger.kernel.org, rppt@kernel.org, shuah@kernel.org, akpm@linux-foundation.org, linux-mm@kvack.org, skhan@linuxfoundation.org, linux-doc@vger.kernel.org, jasonmiu@google.com, linux-kernel@vger.kernel.org, corbet@lwn.net, ran.xiaokai@zte.com.cn, pasha.tatashin@soleen.com, kexec@lists.infradead.org, pratyush@kernel.org, graf@amazon.com Subject: [RFC v1 9/9] liveupdate: add KUnit test to verify alphabetical order of compatibility strings Date: Fri, 5 Jun 2026 03:32:35 +0000 Message-ID: <20260605033235.717351-10-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260605033235.717351-1-pasha.tatashin@soleen.com> References: <20260605033235.717351-1-pasha.tatashin@soleen.com> 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 Content-Type: text/plain; charset="utf-8" Introduce a KUnit test suite to verify that composite compatibility strings are formatted correctly, specifically ensuring that all KHO sub-component compatibility strings are unique and strictly sorted in alphabetical order. Maintaining alphabetical order in composite compatibility strings is required to guarantee consistent, predictable, and reproducible compatibility string representation across different system configurations. The test suite validates: - KHO_FDT_COMPATIBLE (the root composite compatibility string) - LUO_ABI_COMPATIBLE (the LUO composite compatibility string) - MEMFD_LUO_FH_COMPATIBLE (the memfd file handler composite compatibility s= tring) Signed-off-by: Pasha Tatashin --- kernel/liveupdate/Kconfig | 15 ++++++ kernel/liveupdate/Makefile | 2 + kernel/liveupdate/liveupdate_test.c | 56 +++++++++++++++++++++++ tools/testing/selftests/liveupdate/config | 1 + 4 files changed, 74 insertions(+) create mode 100644 kernel/liveupdate/liveupdate_test.c diff --git a/kernel/liveupdate/Kconfig b/kernel/liveupdate/Kconfig index c13af38ba23a..617a31dcee73 100644 --- a/kernel/liveupdate/Kconfig +++ b/kernel/liveupdate/Kconfig @@ -86,4 +86,19 @@ config LIVEUPDATE_MEMFD =20 If unsure, say N. =20 +config LIVEUPDATE_KUNIT_TEST + tristate "KUnit tests for LUO and KHO" if !KUNIT_ALL_TESTS + depends on KUNIT + depends on LIVEUPDATE + default KUNIT_ALL_TESTS + help + Enable KUnit tests for LUO and KHO. These tests verify that the + composite KHO, LUO, and memfd compatibility strings remain unique + and sorted alphabetically. + + For more information on KUnit and unit tests in general, please refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. + endmenu diff --git a/kernel/liveupdate/Makefile b/kernel/liveupdate/Makefile index b481e21a311a..5e0deb85e1b1 100644 --- a/kernel/liveupdate/Makefile +++ b/kernel/liveupdate/Makefile @@ -17,3 +17,5 @@ obj-$(CONFIG_KEXEC_HANDOVER_DEBUG) +=3D kexec_handover_de= bug.o obj-$(CONFIG_KEXEC_HANDOVER_DEBUGFS) +=3D kexec_handover_debugfs.o =20 obj-$(CONFIG_LIVEUPDATE) +=3D luo.o +obj-$(CONFIG_LIVEUPDATE_KUNIT_TEST) +=3D liveupdate_test.o + diff --git a/kernel/liveupdate/liveupdate_test.c b/kernel/liveupdate/liveup= date_test.c new file mode 100644 index 000000000000..15688d69735e --- /dev/null +++ b/kernel/liveupdate/liveupdate_test.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KUnit test for Live Update compatibility strings. + */ +#include +#include +#include +#include +#include + +/* Verify that compatibility sub-components are unique and sorted alphabet= ically */ +static bool is_alphabetical_unique(const char *compat) +{ + char buf[1024]; + char *string =3D buf; + char *token; + char *prev =3D NULL; + char *sub; + + strscpy(buf, compat, sizeof(buf)); + + sub =3D strchr(string, ';'); + if (!sub) + return true; + + sub++; + + while ((token =3D strsep(&sub, ";")) !=3D NULL) { + if (prev && strcmp(prev, token) >=3D 0) + return false; + prev =3D token; + } + + return true; +} + +static void test_compatibility_alphabetical(struct kunit *test) +{ + KUNIT_EXPECT_TRUE(test, is_alphabetical_unique(KHO_FDT_COMPATIBLE)); + KUNIT_EXPECT_TRUE(test, is_alphabetical_unique(LUO_ABI_COMPATIBLE)); + KUNIT_EXPECT_TRUE(test, is_alphabetical_unique(MEMFD_LUO_FH_COMPATIBLE)); +} + +static struct kunit_case liveupdate_test_cases[] =3D { + KUNIT_CASE(test_compatibility_alphabetical), + {} +}; + +static struct kunit_suite liveupdate_test_suite =3D { + .name =3D "liveupdate-compatibility", + .test_cases =3D liveupdate_test_cases, +}; + +kunit_test_suite(liveupdate_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/tools/testing/selftests/liveupdate/config b/tools/testing/self= tests/liveupdate/config index 91d03f9a6a39..28c54bb473b8 100644 --- a/tools/testing/selftests/liveupdate/config +++ b/tools/testing/selftests/liveupdate/config @@ -6,6 +6,7 @@ CONFIG_KEXEC_HANDOVER_DEBUGFS=3Dy CONFIG_KEXEC_HANDOVER_DEBUG=3Dy CONFIG_LIVEUPDATE=3Dy CONFIG_LIVEUPDATE_TEST=3Dy +CONFIG_LIVEUPDATE_KUNIT_TEST=3Dy CONFIG_MEMFD_CREATE=3Dy CONFIG_TMPFS=3Dy CONFIG_SHMEM=3Dy --=20 2.53.0