From nobody Fri Jun 12 12:49:01 2026 Received: from mail-qt1-f172.google.com (mail-qt1-f172.google.com [209.85.160.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 D11453D1CB4 for ; Thu, 14 May 2026 22:26:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797596; cv=none; b=F49l/bS7bzU7ucajsdgExDe9h8xCiNTedSy5Dj6MlXuyuvB5nhbkjAvqTbJWK8eYseIcy5zffeTKBmqElTRcRwtO7orKiUPsYpHmSqd5Iqr3XUQFy5pebFxnNi0O5vIJ5IHBYavgpUDXQFjMKXB0Jky80HXWkup3jfqLzxXJ02I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797596; c=relaxed/simple; bh=77XZZZd7wZLWvAWz9Idgem9rTSNEdzau8xW9Scy7nx0=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ve4o6n6OgztxDMAkkZxZxoHvLDW0+YhUq0KDxtB5g0RQ6No0MDCUYs+q9Dl2SoZ5K01zXbP/GENYQi91jjqcM1uawLfzfC98O+Ys7N0iXoaob1DCzraEaXeQXZoi0O8dLO9m9e/CPiMHXT5sQ/JY797MOGTDSA8W7PtRSt8m3ZQ= 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=gkj+Pif6; arc=none smtp.client-ip=209.85.160.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="gkj+Pif6" Received: by mail-qt1-f172.google.com with SMTP id d75a77b69052e-5164dafcf97so9610881cf.2 for ; Thu, 14 May 2026 15:26:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1778797594; x=1779402394; 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=j39P/d5rSho/yV0JzJL6Y2jMMbUZ/GwYCZvoLGL4UKQ=; b=gkj+Pif6WSaKbT3fHkMN7hAvBjBw681Va92PFw8scwpWG7FK0kwB0kIOrz1F+WEj/S JFvWzqCqpJOuarcqTWjtVHPOj0SZSzPLbd082BrONYD9+Hs74GYldcc1F56ofI4AomX9 aCVTssAcEqIjlBUebxW3J6poG/RdKYuLIbBOaIj999OrL2Pqp1LLf3Icsl86rurj+zUY fkdn5+tNw4fBC81rqeusG9/c6cRwJu+nVhQ8pKq4Bs1pRGdwKOmQ1qM9pTsnet41TxYj 86/BSCFXpSbMHNnOC+9WkZCFebZIcunlup0yEXX/MKwtWzg6Fv9LRseCY36yE1Bho575 oFow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778797594; x=1779402394; 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=j39P/d5rSho/yV0JzJL6Y2jMMbUZ/GwYCZvoLGL4UKQ=; b=dYrib+kdmMShRQewj7L736Zh1Kvd7BrY/mc8PpKwJT5hkKyhuF46OtnhCCYYWim/Sf 13zzbBTf4ZJ+8tiTFa41q2iFXeGt22dfPVs8/mgyzgDr5Gkyy8KHgX77OnMBBztKjzBT BVK/nL1BFqBpuKsq8jKCbCv4594cVpAhM7E5giiDWsHOi9/kMHULGpaFmeOCyAGKDARE gAU/OJQn3rNaIvFSGnmRbsQuHnyedYEs5eN8wuDgaWLqMPUAcprc1qVvSc6M6LPqHCOs KGQVKz/bfR0Yl0xZCfST5Ql/yWyRHDAvcc0hk5lKO4q35xs06lXrPD0OQnVvXVdiKkvV RGdA== X-Forwarded-Encrypted: i=1; AFNElJ+iqd7ruLkoyI0vHVaiMwO/ZyugA5bW9koOQptrrCjMO8KYHOpu4016IeN/QeUNEN73tNeCuv3Oa+B9mho=@vger.kernel.org X-Gm-Message-State: AOJu0YzTWy0sTrIx/3OGvhw8bk3EQnnB+GbBtunp2zUB4nkHrB7vFVeo S9ZuTOtlRLdg2fo+ULk4Ks+IpqlK6dxL7KqraFqSOYI1TZT35XUmvQjkdm+M7ow054o= X-Gm-Gg: Acq92OEH5+Wx5bnhmM98N0lfRPa08asAxrfK1YmY4J6cxcppsaDPgoANaQagWchonR/ jJWeTdd9NKy1YgPyWbXsQfT+Qih/dgg2IsJBsxmBEuANKOg2Bf3C4xA04XKKm3uXBsoG0rq/vQe RjeMxusImKkFzecLe5041jg7plKD+z8FGFagUsJ5Xu9idJuZUGEjx/ik7ZsFe/6Scw1Mtrz2rm2 53yBMcN6QQr4AThR7oJaAmVUqX7iFtIk6K1x9Fr/Dgs1SGCUhLRcxixmdwk1fcVs/UgBg1FG/ij q5J9y0EnXml2B2HnpFqH0Zv204lXgEuMtzr2sJWelY/yLHJ4TDZtjvxo+kD+G7v7CMrjPxan0CL XzVoiGmjaRVWF3NddT2F2pizEzqrWAPIrcdfSegtOlrNuDdyin0/LEYzw6V/RwbFpCZkEDwiMA/ IHfOA2vI0ykFGpkatsqvk8jJ/Dkbt/G9fYtxI+b3iCiMkmG478bxDqyLiaPgR5sQ== X-Received: by 2002:ac8:57cd:0:b0:50d:b33d:bc6b with SMTP id d75a77b69052e-5165a026958mr19386901cf.20.1778797593734; Thu, 14 May 2026 15:26:33 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-516456ba92fsm28671901cf.9.2026.05.14.15.26.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 15:26:33 -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, linux-kernel@vger.kernel.org, corbet@lwn.net, pasha.tatashin@soleen.com, dmatlack@google.com, kexec@lists.infradead.org, pratyush@kernel.org, skhawaja@google.com, graf@amazon.com Subject: [PATCH v2 01/10] liveupdate: centralize state management into struct luo_ser Date: Thu, 14 May 2026 22:26:19 +0000 Message-ID: <20260514222628.931312-2-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260514222628.931312-1-pasha.tatashin@soleen.com> References: <20260514222628.931312-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" Transition the LUO to ABI v2, which centralizes state management into a single struct luo_ser header. Previously, LUO state was spread across multiple FDT properties and subnodes. ABI v2 simplifies this by placing all core state, including the liveupdate number and physical addresses for sessions and FLB headers into a centralized struct luo_ser. Signed-off-by: Pasha Tatashin --- include/linux/kho/abi/luo.h | 91 +++++++++++--------------------- kernel/liveupdate/luo_core.c | 59 ++++++++++++++------- kernel/liveupdate/luo_flb.c | 65 ++++------------------- kernel/liveupdate/luo_internal.h | 8 +-- kernel/liveupdate/luo_session.c | 57 +++----------------- 5 files changed, 93 insertions(+), 187 deletions(-) diff --git a/include/linux/kho/abi/luo.h b/include/linux/kho/abi/luo.h index 46750a0ddf88..1b2f865a771a 100644 --- a/include/linux/kho/abi/luo.h +++ b/include/linux/kho/abi/luo.h @@ -30,52 +30,25 @@ * .. code-block:: none * * / { - * compatible =3D "luo-v1"; - * liveupdate-number =3D <...>; - * - * luo-session { - * compatible =3D "luo-session-v1"; - * luo-session-header =3D ; - * }; - * - * luo-flb { - * compatible =3D "luo-flb-v1"; - * luo-flb-header =3D ; - * }; + * compatible =3D "luo-v2"; + * luo-abi-header =3D ; * }; * * Main LUO Node (/): * - * - compatible: "luo-v1" + * - compatible: "luo-v2" * Identifies the overall LUO ABI version. - * - liveupdate-number: u64 - * A counter tracking the number of successful live updates performed. - * - * Session Node (luo-session): - * This node describes all preserved user-space sessions. - * - * - compatible: "luo-session-v1" - * Identifies the session ABI version. - * - luo-session-header: u64 - * The physical address of a `struct luo_session_header_ser`. This str= ucture - * is the header for a contiguous block of memory containing an array = of - * `struct luo_session_ser`, one for each preserved session. - * - * File-Lifecycle-Bound Node (luo-flb): - * This node describes all preserved global objects whose lifecycle is b= ound - * to that of the preserved files (e.g., shared IOMMU state). - * - * - compatible: "luo-flb-v1" - * Identifies the FLB ABI version. - * - luo-flb-header: u64 - * The physical address of a `struct luo_flb_header_ser`. This structu= re is - * the header for a contiguous block of memory containing an array of - * `struct luo_flb_ser`, one for each preserved global object. + * - luo-abi-header: u64 + * The physical address of `struct luo_ser`. * * Serialization Structures: * The FDT properties point to memory regions containing arrays of simpl= e, * `__packed` structures. These structures contain the actual preserved = state. * + * - struct luo_ser: + * The central ABI structure that contains the overall state of the LU= O. + * It includes the liveupdate-number and pointers to sessions and FLBs. + * * - struct luo_session_header_ser: * Header for the session array. Contains the total page count of the * preserved memory block and the number of `struct luo_session_ser` @@ -109,13 +82,26 @@ =20 /* * The LUO FDT hooks all LUO state for sessions, fds, etc. - * In the root it also carries "liveupdate-number" 64-bit property that - * corresponds to the number of live-updates performed on this machine. */ #define LUO_FDT_SIZE PAGE_SIZE #define LUO_FDT_KHO_ENTRY_NAME "LUO" -#define LUO_FDT_COMPATIBLE "luo-v1" -#define LUO_FDT_LIVEUPDATE_NUM "liveupdate-number" +#define LUO_FDT_COMPATIBLE "luo-v2" +#define LUO_FDT_ABI_HEADER "luo-abi-header" + +/** + * struct luo_ser - Centralized LUO ABI header. + * @liveupdate_num: A counter tracking the number of successful live updat= es. + * @sessions_pa: Physical address of the first session block header. + * @flbs_pa: Physical address of the FLB header. + * + * This structure is the root of all preserved LUO state. It is pointed to= by + * the "luo-abi-header" property in the LUO FDT. + */ +struct luo_ser { + u64 liveupdate_num; + u64 sessions_pa; + u64 flbs_pa; +} __packed; =20 #define LIVEUPDATE_HNDL_COMPAT_LENGTH 48 =20 @@ -147,15 +133,6 @@ struct luo_file_set_ser { u64 count; } __packed; =20 -/* - * LUO FDT session node - * LUO_FDT_SESSION_HEADER: is a u64 physical address of struct - * luo_session_header_ser - */ -#define LUO_FDT_SESSION_NODE_NAME "luo-session" -#define LUO_FDT_SESSION_COMPATIBLE "luo-session-v2" -#define LUO_FDT_SESSION_HEADER "luo-session-header" - /** * struct luo_session_header_ser - Header for the serialized session data = block. * @count: The number of `struct luo_session_ser` entries that immediately @@ -165,7 +142,7 @@ struct luo_file_set_ser { * physical memory preserved across the kexec. It provides the necessary * metadata to interpret the array of session entries that follow. * - * If this structure is modified, `LUO_FDT_SESSION_COMPATIBLE` must be upd= ated. + * If this structure is modified, `LUO_FDT_COMPATIBLE` must be updated. */ struct luo_session_header_ser { u64 count; @@ -182,7 +159,7 @@ struct luo_session_header_ser { * session) is created and passed to the new kernel, allowing it to recons= truct * the session context. * - * If this structure is modified, `LUO_FDT_SESSION_COMPATIBLE` must be upd= ated. + * If this structure is modified, `LUO_FDT_COMPATIBLE` must be updated. */ struct luo_session_ser { char name[LIVEUPDATE_SESSION_NAME_LENGTH]; @@ -192,10 +169,6 @@ struct luo_session_ser { /* The max size is set so it can be reliably used during in serialization = */ #define LIVEUPDATE_FLB_COMPAT_LENGTH 48 =20 -#define LUO_FDT_FLB_NODE_NAME "luo-flb" -#define LUO_FDT_FLB_COMPATIBLE "luo-flb-v1" -#define LUO_FDT_FLB_HEADER "luo-flb-header" - /** * struct luo_flb_header_ser - Header for the serialized FLB data block. * @pgcnt: The total number of pages occupied by the entire preserved memo= ry @@ -205,11 +178,9 @@ struct luo_session_ser { * in the memory block. * * This structure is located at the physical address specified by the - * `LUO_FDT_FLB_HEADER` FDT property. It provides the new kernel with the - * necessary information to find and iterate over the array of preserved - * File-Lifecycle-Bound objects and to manage the underlying memory. + * flbs_pa in luo_ser. * - * If this structure is modified, LUO_FDT_FLB_COMPATIBLE must be updated. + * If this structure is modified, `LUO_FDT_COMPATIBLE` must be updated. */ struct luo_flb_header_ser { u64 pgcnt; @@ -231,7 +202,7 @@ struct luo_flb_header_ser { * passed to the new kernel. Each entry allows the LUO core to restore one * global, shared object. * - * If this structure is modified, LUO_FDT_FLB_COMPATIBLE must be updated. + * If this structure is modified, `LUO_FDT_COMPATIBLE` must be updated. */ struct luo_flb_ser { char name[LIVEUPDATE_FLB_COMPAT_LENGTH]; diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c index 803f51c84275..9bd649b22029 100644 --- a/kernel/liveupdate/luo_core.c +++ b/kernel/liveupdate/luo_core.c @@ -82,9 +82,11 @@ early_param("liveupdate", early_liveupdate_param); =20 static int __init luo_early_startup(void) { + struct luo_ser *luo_ser; + int err, header_size; phys_addr_t fdt_phys; - int err, ln_size; const void *ptr; + u64 luo_ser_pa; =20 if (!kho_is_enabled()) { if (liveupdate_enabled()) @@ -115,27 +117,29 @@ static int __init luo_early_startup(void) return -EINVAL; } =20 - ln_size =3D 0; - ptr =3D fdt_getprop(luo_global.fdt_in, 0, LUO_FDT_LIVEUPDATE_NUM, - &ln_size); - if (!ptr || ln_size !=3D sizeof(luo_global.liveupdate_num)) { - pr_err("Unable to get live update number '%s' [%d]\n", - LUO_FDT_LIVEUPDATE_NUM, ln_size); + header_size =3D 0; + ptr =3D fdt_getprop(luo_global.fdt_in, 0, LUO_FDT_ABI_HEADER, &header_siz= e); + if (!ptr || header_size !=3D sizeof(u64)) { + pr_err("Unable to get ABI header '%s' [%d]\n", + LUO_FDT_ABI_HEADER, header_size); =20 return -EINVAL; } =20 - luo_global.liveupdate_num =3D get_unaligned((u64 *)ptr); + luo_ser_pa =3D get_unaligned((u64 *)ptr); + luo_ser =3D phys_to_virt(luo_ser_pa); + + luo_global.liveupdate_num =3D luo_ser->liveupdate_num; pr_info("Retrieved live update data, liveupdate number: %lld\n", luo_global.liveupdate_num); =20 - err =3D luo_session_setup_incoming(luo_global.fdt_in); + err =3D luo_session_setup_incoming(luo_ser->sessions_pa); if (err) return err; =20 - err =3D luo_flb_setup_incoming(luo_global.fdt_in); + luo_flb_setup_incoming(luo_ser->flbs_pa); =20 - return err; + return 0; } =20 static int __init liveupdate_early_init(void) @@ -156,7 +160,8 @@ early_initcall(liveupdate_early_init); /* Called during boot to create outgoing LUO fdt tree */ static int __init luo_fdt_setup(void) { - const u64 ln =3D luo_global.liveupdate_num + 1; + struct luo_ser *luo_ser; + u64 luo_ser_pa; void *fdt_out; int err; =20 @@ -166,27 +171,45 @@ static int __init luo_fdt_setup(void) return PTR_ERR(fdt_out); } =20 + luo_ser =3D kho_alloc_preserve(sizeof(*luo_ser)); + if (IS_ERR(luo_ser)) { + err =3D PTR_ERR(luo_ser); + goto exit_free_fdt; + } + luo_ser_pa =3D virt_to_phys(luo_ser); + err =3D fdt_create(fdt_out, LUO_FDT_SIZE); err |=3D fdt_finish_reservemap(fdt_out); err |=3D fdt_begin_node(fdt_out, ""); err |=3D fdt_property_string(fdt_out, "compatible", LUO_FDT_COMPATIBLE); - err |=3D fdt_property(fdt_out, LUO_FDT_LIVEUPDATE_NUM, &ln, sizeof(ln)); - err |=3D luo_session_setup_outgoing(fdt_out); - err |=3D luo_flb_setup_outgoing(fdt_out); + err |=3D fdt_property(fdt_out, LUO_FDT_ABI_HEADER, &luo_ser_pa, + sizeof(luo_ser_pa)); err |=3D fdt_end_node(fdt_out); err |=3D fdt_finish(fdt_out); if (err) - goto exit_free; + goto exit_free_luo_ser; + + err =3D luo_session_setup_outgoing(&luo_ser->sessions_pa); + if (err) + goto exit_free_luo_ser; + + err =3D luo_flb_setup_outgoing(&luo_ser->flbs_pa); + if (err) + goto exit_free_luo_ser; + + luo_ser->liveupdate_num =3D luo_global.liveupdate_num + 1; =20 err =3D kho_add_subtree(LUO_FDT_KHO_ENTRY_NAME, fdt_out, fdt_totalsize(fdt_out)); if (err) - goto exit_free; + goto exit_free_luo_ser; luo_global.fdt_out =3D fdt_out; =20 return 0; =20 -exit_free: +exit_free_luo_ser: + kho_unpreserve_free(luo_ser); +exit_free_fdt: kho_unpreserve_free(fdt_out); pr_err("failed to prepare LUO FDT: %d\n", err); =20 diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c index 8f5c5dd01cd0..7ccc59981297 100644 --- a/kernel/liveupdate/luo_flb.c +++ b/kernel/liveupdate/luo_flb.c @@ -159,8 +159,8 @@ static void luo_flb_file_unpreserve_one(struct liveupda= te_flb *flb) =20 static int luo_flb_retrieve_one(struct liveupdate_flb *flb) { - struct luo_flb_private *private =3D luo_flb_get_private(flb); struct luo_flb_header *fh =3D &luo_flb_global.incoming; + struct luo_flb_private *private =3D luo_flb_get_private(flb); struct liveupdate_flb_op_args args =3D {0}; bool found =3D false; int err; @@ -551,27 +551,15 @@ int liveupdate_flb_get_outgoing(struct liveupdate_flb= *flb, void **objp) return 0; } =20 -int __init luo_flb_setup_outgoing(void *fdt_out) +int __init luo_flb_setup_outgoing(u64 *flbs_pa) { struct luo_flb_header_ser *header_ser; - u64 header_ser_pa; - int err; =20 header_ser =3D kho_alloc_preserve(LUO_FLB_PGCNT << PAGE_SHIFT); if (IS_ERR(header_ser)) return PTR_ERR(header_ser); =20 - header_ser_pa =3D virt_to_phys(header_ser); - - err =3D fdt_begin_node(fdt_out, LUO_FDT_FLB_NODE_NAME); - err |=3D fdt_property_string(fdt_out, "compatible", - LUO_FDT_FLB_COMPATIBLE); - err |=3D fdt_property(fdt_out, LUO_FDT_FLB_HEADER, &header_ser_pa, - sizeof(header_ser_pa)); - err |=3D fdt_end_node(fdt_out); - - if (err) - goto err_unpreserve; + *flbs_pa =3D virt_to_phys(header_ser); =20 header_ser->pgcnt =3D LUO_FLB_PGCNT; luo_flb_global.outgoing.header_ser =3D header_ser; @@ -579,53 +567,18 @@ int __init luo_flb_setup_outgoing(void *fdt_out) luo_flb_global.outgoing.active =3D true; =20 return 0; - -err_unpreserve: - kho_unpreserve_free(header_ser); - - return err; } =20 -int __init luo_flb_setup_incoming(void *fdt_in) +void __init luo_flb_setup_incoming(u64 flbs_pa) { struct luo_flb_header_ser *header_ser; - int err, header_size, offset; - const void *ptr; - u64 header_ser_pa; - - offset =3D fdt_subnode_offset(fdt_in, 0, LUO_FDT_FLB_NODE_NAME); - if (offset < 0) { - pr_err("Unable to get FLB node [%s]\n", LUO_FDT_FLB_NODE_NAME); =20 - return -ENOENT; + if (flbs_pa) { + header_ser =3D phys_to_virt(flbs_pa); + luo_flb_global.incoming.header_ser =3D header_ser; + luo_flb_global.incoming.ser =3D (void *)(header_ser + 1); + luo_flb_global.incoming.active =3D true; } - - err =3D fdt_node_check_compatible(fdt_in, offset, - LUO_FDT_FLB_COMPATIBLE); - if (err) { - pr_err("FLB node is incompatible with '%s' [%d]\n", - LUO_FDT_FLB_COMPATIBLE, err); - - return -EINVAL; - } - - header_size =3D 0; - ptr =3D fdt_getprop(fdt_in, offset, LUO_FDT_FLB_HEADER, &header_size); - if (!ptr || header_size !=3D sizeof(u64)) { - pr_err("Unable to get FLB header property '%s' [%d]\n", - LUO_FDT_FLB_HEADER, header_size); - - return -EINVAL; - } - - header_ser_pa =3D get_unaligned((u64 *)ptr); - header_ser =3D phys_to_virt(header_ser_pa); - - luo_flb_global.incoming.header_ser =3D header_ser; - luo_flb_global.incoming.ser =3D (void *)(header_ser + 1); - luo_flb_global.incoming.active =3D true; - - return 0; } =20 /** diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_inter= nal.h index 875844d7a41d..4b6c18348d9b 100644 --- a/kernel/liveupdate/luo_internal.h +++ b/kernel/liveupdate/luo_internal.h @@ -81,8 +81,8 @@ extern struct rw_semaphore luo_register_rwlock; =20 int luo_session_create(const char *name, struct file **filep); int luo_session_retrieve(const char *name, struct file **filep); -int __init luo_session_setup_outgoing(void *fdt); -int __init luo_session_setup_incoming(void *fdt); +int __init luo_session_setup_outgoing(u64 *sessions_pa); +int __init luo_session_setup_incoming(u64 sessions_pa); int luo_session_serialize(void); int luo_session_deserialize(void); =20 @@ -104,8 +104,8 @@ int luo_flb_file_preserve(struct liveupdate_file_handle= r *fh); void luo_flb_file_unpreserve(struct liveupdate_file_handler *fh); void luo_flb_file_finish(struct liveupdate_file_handler *fh); void luo_flb_unregister_all(struct liveupdate_file_handler *fh); -int __init luo_flb_setup_outgoing(void *fdt); -int __init luo_flb_setup_incoming(void *fdt); +int __init luo_flb_setup_outgoing(u64 *flbs_pa); +void __init luo_flb_setup_incoming(u64 flbs_pa); void luo_flb_serialize(void); =20 #ifdef CONFIG_LIVEUPDATE_TEST diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_sessio= n.c index 1caaa7886ec6..915ab9ce0f34 100644 --- a/kernel/liveupdate/luo_session.c +++ b/kernel/liveupdate/luo_session.c @@ -458,75 +458,34 @@ int luo_session_retrieve(const char *name, struct fil= e **filep) return err; } =20 -int __init luo_session_setup_outgoing(void *fdt_out) +int __init luo_session_setup_outgoing(u64 *sessions_pa) { struct luo_session_header_ser *header_ser; - u64 header_ser_pa; - int err; =20 header_ser =3D kho_alloc_preserve(LUO_SESSION_PGCNT << PAGE_SHIFT); if (IS_ERR(header_ser)) return PTR_ERR(header_ser); - header_ser_pa =3D virt_to_phys(header_ser); - - err =3D fdt_begin_node(fdt_out, LUO_FDT_SESSION_NODE_NAME); - err |=3D fdt_property_string(fdt_out, "compatible", - LUO_FDT_SESSION_COMPATIBLE); - err |=3D fdt_property(fdt_out, LUO_FDT_SESSION_HEADER, &header_ser_pa, - sizeof(header_ser_pa)); - err |=3D fdt_end_node(fdt_out); =20 - if (err) - goto err_unpreserve; + *sessions_pa =3D virt_to_phys(header_ser); =20 luo_session_global.outgoing.header_ser =3D header_ser; luo_session_global.outgoing.ser =3D (void *)(header_ser + 1); luo_session_global.outgoing.active =3D true; =20 return 0; - -err_unpreserve: - kho_unpreserve_free(header_ser); - return err; } =20 -int __init luo_session_setup_incoming(void *fdt_in) +int __init luo_session_setup_incoming(u64 sessions_pa) { struct luo_session_header_ser *header_ser; - int err, header_size, offset; - u64 header_ser_pa; - const void *ptr; - - offset =3D fdt_subnode_offset(fdt_in, 0, LUO_FDT_SESSION_NODE_NAME); - if (offset < 0) { - pr_err("Unable to get session node: [%s]\n", - LUO_FDT_SESSION_NODE_NAME); - return -EINVAL; - } =20 - err =3D fdt_node_check_compatible(fdt_in, offset, - LUO_FDT_SESSION_COMPATIBLE); - if (err) { - pr_err("Session node incompatible [%s]\n", - LUO_FDT_SESSION_COMPATIBLE); - return -EINVAL; - } - - header_size =3D 0; - ptr =3D fdt_getprop(fdt_in, offset, LUO_FDT_SESSION_HEADER, &header_size); - if (!ptr || header_size !=3D sizeof(u64)) { - pr_err("Unable to get session header '%s' [%d]\n", - LUO_FDT_SESSION_HEADER, header_size); - return -EINVAL; + if (sessions_pa) { + header_ser =3D phys_to_virt(sessions_pa); + luo_session_global.incoming.header_ser =3D header_ser; + luo_session_global.incoming.ser =3D (void *)(header_ser + 1); + luo_session_global.incoming.active =3D true; } =20 - header_ser_pa =3D get_unaligned((u64 *)ptr); - header_ser =3D phys_to_virt(header_ser_pa); - - luo_session_global.incoming.header_ser =3D header_ser; - luo_session_global.incoming.ser =3D (void *)(header_ser + 1); - luo_session_global.incoming.active =3D true; - return 0; } =20 --=20 2.53.0 From nobody Fri Jun 12 12:49:01 2026 Received: from mail-qt1-f181.google.com (mail-qt1-f181.google.com [209.85.160.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 E4F9A3D25B1 for ; Thu, 14 May 2026 22:26:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797597; cv=none; b=QDoEbqdYCMkjnnrnE+91Z/f1WTtYBW0QFOHlKgqMTPeSgyajRTlBY/tF9At8zXUQRTosJPshrgp7um76K0BOk1lvcFsEbgNjblbxW7lzJz78h5WrRCNG4h/Ka661JVgoIP93VUi5iDzE7XeJcCriLD4L5u4LNhgxAM7thoJCMAU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797597; c=relaxed/simple; bh=ZiieCgvQr10bJWZl83vVIkp0x1RhpipuOsxCe6TWm10=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=du+I9eXQsgphJv3vSBubTTzRZmHV7340yz0S4hh4RGW3Q6i8dv8BKrBffu6B362um5mg4hKtoWeK262gB4OeYhe7qEbm1cF6H4Wq3QwMAMTP30VuZ6q+Tj5e+cN4G0uWGSgBxqeM/jTty75LB+orFzYdgR87nXGHXPMfHtPRTP4= 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=DWM+GPvU; arc=none smtp.client-ip=209.85.160.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="DWM+GPvU" Received: by mail-qt1-f181.google.com with SMTP id d75a77b69052e-50e97863425so84391321cf.0 for ; Thu, 14 May 2026 15:26:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1778797595; x=1779402395; 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=lNYZS3s0Ezy+RQHVqVYSzxTe1QiuBpPaay8EBa5d/Xw=; b=DWM+GPvUCLHiD8HtHcxflKwcWomGBNlyfhu4QJKmNGGLMBYYcdIoiz/r2Y7k6xBLpk sUdaG14uE38lhr/Y/8NPYn82cNwv/qlvFw2TK9HVYkKB4NvZCygrxfAU95Y9AzS1p2Ps zmSOrtfhBGiR/T4a5jdsi6CNvtlExvVk7eo9/9SUA0nCbLVUzBbaFBxRq/FVNaUufE9m bO7HSyOG8aQA/AQPmvk8adjYBbZQJ5lXnGpNKJajtZBRBVxCYl14DOLgqOMpLm1k0LoU wKMdsYCyqYOZqT2z800PXFctCMnobF7jlmqXHAEy6N6kKHETJ8NpdlhQ4+BpsQi/71cT hpKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778797595; x=1779402395; 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=lNYZS3s0Ezy+RQHVqVYSzxTe1QiuBpPaay8EBa5d/Xw=; b=gp9widsGtH+JxqPPZniscU9lcnEDjgVLInuOX9KlgoTh1Xzqqoh/3UnMxLvMmgmGyf R1m+0QATA1KUFOfKC+K2eak1eb/vQIKgKz8BPPT9l697Cv/J0EcHTJOYHwLGCRt24naR eBe5vIm/i+PCnT8qIwoLmgQaD/vjw90TpaSvDeq+9zZOR6pT6onPQ0Lu7V5iJLOlmbym /5vLApnkMLWtJ6jlvbxJpAUCFUSnwXGIZV4AfNQ+upfdSuSbR/DLytHVubrOn7ricYrY GJ4Ch2SCnrTQLYA25ttoehdYkiwUsGigpjt6enctcKSGAn1e6k2ViiwvbjtLDakGPoxW ECYA== X-Forwarded-Encrypted: i=1; AFNElJ84/eNINGHTRGHVxBeuRE6ws9au4KjhLRPr8BJ+6MJxdoqkj92yDQiq+LwX6e6IbwmywhBqj26doo95wXM=@vger.kernel.org X-Gm-Message-State: AOJu0YyvUTntmOFj4iMS/WGLzvw3S33EcXdxO7dbfSTiiMd+VxVjJP0K dmPYVaQsHkgKk7vFmNGikhi3721Ri3fMrBJTbvrubm+e4clv+9ZffsSX8Fmp7pTuuVA= X-Gm-Gg: Acq92OHALmN+CWjB7YDYFg8ZTkJn4ZlNpClFc7pjeEIFofCX+fhVoIwurCqUGcMDgwR BIFk12FpHOuJgbhV4vdA33nX0hRIyzObwUVwYov+Hk3kFGhOErWUBHqmLVSIhnwjAx+Rllj/hcJ 5N6pavVL5Ciz76+W7zQfrXOAYgBBOAz//USeCUcdHldVwFEaQrUIWXtELVCBAGfVqp48HPi6wL/ KFlws2xzmkr8eF13KVq758syjkpk5Lef2pphShmdMS8apO4SRu/JtdNJLdfFZEFt4nTA5qnC1rd B6Y305GTtmF6Rw0KMgkvsysmHEUeh6lMyVuoT5MoK4wcelHWDL+bbh8GeEnH7bw6TBOGNoWhS0h l6BAKwD+lmDHcYlNsiuZJ0dp7wm96K9SvecL2GEdxQkh/xncyW9/OBDccr4Jit92CpHy9QBk3h3 T1H0Y3hAJmWWXATxBfJFZHrnnOh2TFJBJi4NiEhntfN85QR+qqeaw= X-Received: by 2002:ac8:7dcd:0:b0:50e:6055:274e with SMTP id d75a77b69052e-5165a025376mr20219891cf.17.1778797595002; Thu, 14 May 2026 15:26:35 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-516456ba92fsm28671901cf.9.2026.05.14.15.26.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 15:26:34 -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, linux-kernel@vger.kernel.org, corbet@lwn.net, pasha.tatashin@soleen.com, dmatlack@google.com, kexec@lists.infradead.org, pratyush@kernel.org, skhawaja@google.com, graf@amazon.com Subject: [PATCH v2 02/10] liveupdate: Extract luo_file_deserialize_one helper Date: Thu, 14 May 2026 22:26:20 +0000 Message-ID: <20260514222628.931312-3-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260514222628.931312-1-pasha.tatashin@soleen.com> References: <20260514222628.931312-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" Extract the logic for deserializing single entries for files into separate helper functions. In preparation to a linked-block serialization for files. Signed-off-by: Pasha Tatashin Acked-by: Mike Rapoport (Microsoft) Reviewed-by: Pratyush Yadav (Google) --- kernel/liveupdate/luo_file.c | 77 ++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c index a0a419085e28..a2510563469a 100644 --- a/kernel/liveupdate/luo_file.c +++ b/kernel/liveupdate/luo_file.c @@ -752,6 +752,46 @@ int luo_file_finish(struct luo_file_set *file_set) return 0; } =20 +static int luo_file_deserialize_one(struct luo_file_set *file_set, + struct luo_file_ser *ser) +{ + struct liveupdate_file_handler *fh; + bool handler_found =3D false; + struct luo_file *luo_file; + + down_read(&luo_register_rwlock); + list_private_for_each_entry(fh, &luo_file_handler_list, list) { + if (!strcmp(fh->compatible, ser->compatible)) { + if (try_module_get(fh->ops->owner)) + handler_found =3D true; + break; + } + } + up_read(&luo_register_rwlock); + + if (!handler_found) { + pr_warn("No registered handler for compatible '%.*s'\n", + (int)sizeof(ser->compatible), + ser->compatible); + return -ENOENT; + } + + luo_file =3D kzalloc_obj(*luo_file); + if (!luo_file) { + module_put(fh->ops->owner); + return -ENOMEM; + } + + luo_file->fh =3D fh; + luo_file->file =3D NULL; + luo_file->serialized_data =3D ser->data; + luo_file->token =3D ser->token; + mutex_init(&luo_file->mutex); + list_add_tail(&luo_file->list, &file_set->files_list); + + return 0; +} + /** * luo_file_deserialize - Reconstructs the list of preserved files in the = new kernel. * @file_set: The incoming file_set to fill with deserialized data. @@ -781,6 +821,7 @@ int luo_file_deserialize(struct luo_file_set *file_set, struct luo_file_set_ser *file_set_ser) { struct luo_file_ser *file_ser; + int err; u64 i; =20 if (!file_set_ser->files) { @@ -808,39 +849,9 @@ int luo_file_deserialize(struct luo_file_set *file_set, */ file_ser =3D file_set->files; for (i =3D 0; i < file_set->count; i++) { - struct liveupdate_file_handler *fh; - bool handler_found =3D false; - struct luo_file *luo_file; - - down_read(&luo_register_rwlock); - list_private_for_each_entry(fh, &luo_file_handler_list, list) { - if (!strcmp(fh->compatible, file_ser[i].compatible)) { - if (try_module_get(fh->ops->owner)) - handler_found =3D true; - break; - } - } - up_read(&luo_register_rwlock); - - if (!handler_found) { - pr_warn("No registered handler for compatible '%.*s'\n", - (int)sizeof(file_ser[i].compatible), - file_ser[i].compatible); - return -ENOENT; - } - - luo_file =3D kzalloc_obj(*luo_file); - if (!luo_file) { - module_put(fh->ops->owner); - return -ENOMEM; - } - - luo_file->fh =3D fh; - luo_file->file =3D NULL; - luo_file->serialized_data =3D file_ser[i].data; - luo_file->token =3D file_ser[i].token; - mutex_init(&luo_file->mutex); - list_add_tail(&luo_file->list, &file_set->files_list); + err =3D luo_file_deserialize_one(file_set, &file_ser[i]); + if (err) + return err; } =20 return 0; --=20 2.53.0 From nobody Fri Jun 12 12:49:01 2026 Received: from mail-qt1-f174.google.com (mail-qt1-f174.google.com [209.85.160.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 2F0CB3D3012 for ; Thu, 14 May 2026 22:26:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797600; cv=none; b=d2oiTyTD7oEJWpOjUZ923sBQH3VzRdMPCyEyCE8S70m5mZZenLwFf1cIRPNW/jJkVrEieA22tlclT9DP1LH+lzdMaHKaHWCg0lwtcZ3bt1qLmi8x0XfZDDVotBMyezQWhqOCIDHFt2bRLMIcxElsOt9trKqXjfkdASAruJqepkc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797600; c=relaxed/simple; bh=sVZ5o7p+/qtFwBG8i7ARh0384/n8GSnFc4REGXxfxJs=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lrwcEBaKmpJjeZkbkkXtQUEsamoWUGALfNU4oGV8rYrf3MQ6DRzblhXpaGN5Nxywdnrd0N5ELvl5OcswYYK1jDZX5oeR0HwdB1oz/65JPmtxjaQoVZzrqtffx8RqPsnccp//SJqDWosT8Sp2D4DkmxCsh3USnMhzKYOLPl0OhLQ= 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=bKUr1cjh; arc=none smtp.client-ip=209.85.160.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="bKUr1cjh" Received: by mail-qt1-f174.google.com with SMTP id d75a77b69052e-50d75bfb259so56813411cf.1 for ; Thu, 14 May 2026 15:26:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1778797597; x=1779402397; 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=5DzA3L8/isnr0sHad5OpiNWdq+EP7DXQ1j7lGoEnI0Q=; b=bKUr1cjhQpiTyrgFEa9EdedLg4DPjFrY748LQdexu81c0WrSiBv4Bb48KliyEvs6wN nvLUhBO4NOYOm814+k6le7MG1+D+A1wcbWEGl8kyans1YuYCrpqv/rLwe1ivQ/Li6J1B RuQA75xm22QzOY/POXVBn9UbVfy+mUoKtdU+abR0e4O5YQjiJch7Y6E52hmDJmoTlXme 3k5eOkZnJnf+ItaZePV0Hu4TxhqAGpELcgmJem0i2KuX14R19HQ+lUHN/HO2XhErNmC0 gN6MvAy/373/+wee8bOiKyAVf9d22ayO5KxhEt3Yz5/knivhQz/RcSeqyU2OF8ysYMKj Gyvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778797597; x=1779402397; 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=5DzA3L8/isnr0sHad5OpiNWdq+EP7DXQ1j7lGoEnI0Q=; b=Lq3Rrm3zqDnhacFgBRb0fonMp1vElxmNxDBeqrPHYtIxywkZEm5oAvsnLQlScVPUWk X0VnGxu5k5BAzpfO6QZfFY7W00KXidqHa33vMc4eBqAZa4m0F4exihfWgpC6uEZZQWJf G0qQReVBsuBvgI8uaeEkSLkvi+QcfUTOjtXL0L3NA7SA7hXGjEetKiQUdEwRLTeKA07K Jv9FW5Nv0ZpseAKIBq/Ni5n2Gm/HXt6EXWA33c4RITejHxQjn5ejoqFkbMMcEaHrpTzd RVo0gMIx7jlhwi/jK7339WPaazUkV7JPGffUjlhSIAJru/+Yj1aRA7sNTSahLYWA+aIV Y3Qw== X-Forwarded-Encrypted: i=1; AFNElJ/YlG1aUGdZEWRrEGcmbwCCwH3qgpJILKvq1ElHO1ud3vFipwr27PPK00tqoig3l2/y/RTCRs8eR0rbVss=@vger.kernel.org X-Gm-Message-State: AOJu0Yz1oBd0L81HqhJiBPjRhfbGOvui8VYO8UafpkXQbIybiEamvOh1 iGc/Q7SH5ruxUcir5r1/QC5JhG0JLNK8VznPVXkGNwIxUZRL2q1GQ99QiK9IjbhMgSA= X-Gm-Gg: Acq92OFmjXWCH/YvlTGLt/svZxXBjSETHrR6Ft/Z4GoViCrzF9CdNtXhqoVhWfeXUbl AyhK3V9Ohm2ojXKF8wPb/fByQPsOZNJr+027IABFeyTQR5Nfylo+Mm1TdafjNwxbrFmtD0MYvzd TTbBAJqDu3SAswosxZqw78EAVVaWPKJkkv7wDwSAKAggVmeJXvH6lTlaYOdmudCEZ6+MdVOeVT3 Gs/Hubm+dR7jtO09nlGcR0pYj1Dov15OpBXU2OW8GpBGZpKjCHhBt0k5L6qPXWPUk9kELTdG2IT EykWcHkijY1VrOaQC+xepqY8mRx96N+swMh3xcBiVIiRSgx2qa1Ca03ywhJyglHNRoEyakbBfBW t5YBgoHYi5tRby8iffHxweZ/V7uiTYqCDDVth/PS8d1u7j2c8r4hkrzFb5wLM9gyZrlGL5xBCRc +FmMwCsyO4WqfqsGIxVvx9Bq8KDM8+nKoL++4e5EEm9dfcTUHFGIM= X-Received: by 2002:a05:622a:1814:b0:50b:893f:7d93 with SMTP id d75a77b69052e-5165a00061amr19897201cf.2.1778797597005; Thu, 14 May 2026 15:26:37 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-516456ba92fsm28671901cf.9.2026.05.14.15.26.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 15:26: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, linux-kernel@vger.kernel.org, corbet@lwn.net, pasha.tatashin@soleen.com, dmatlack@google.com, kexec@lists.infradead.org, pratyush@kernel.org, skhawaja@google.com, graf@amazon.com Subject: [PATCH v2 03/10] liveupdate: Extract luo_session_deserialize_one helper Date: Thu, 14 May 2026 22:26:21 +0000 Message-ID: <20260514222628.931312-4-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260514222628.931312-1-pasha.tatashin@soleen.com> References: <20260514222628.931312-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" Extract the logic for deserializing single entries for sessions into separate helper functions. In preparation to a linked-block serialization for sessions. Signed-off-by: Pasha Tatashin Acked-by: Mike Rapoport (Microsoft) Reviewed-by: Pratyush Yadav (Google) --- kernel/liveupdate/luo_session.c | 62 +++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_sessio= n.c index 915ab9ce0f34..c08733a328bc 100644 --- a/kernel/liveupdate/luo_session.c +++ b/kernel/liveupdate/luo_session.c @@ -489,6 +489,40 @@ int __init luo_session_setup_incoming(u64 sessions_pa) return 0; } =20 +static int luo_session_deserialize_one(struct luo_session_header *sh, + struct luo_session_ser *ser) +{ + struct luo_session *session; + int err; + + session =3D luo_session_alloc(ser->name); + if (IS_ERR(session)) { + pr_warn("Failed to allocate session [%.*s] during deserialization %pe\n", + (int)sizeof(ser->name), ser->name, session); + return PTR_ERR(session); + } + + err =3D luo_session_insert(sh, session); + if (err) { + pr_warn("Failed to insert session [%s] %pe\n", + session->name, ERR_PTR(err)); + luo_session_free(session); + return err; + } + + scoped_guard(mutex, &session->mutex) { + err =3D luo_file_deserialize(&session->file_set, + &ser->file_set_ser); + } + if (err) { + pr_warn("Failed to deserialize files for session [%s] %pe\n", + session->name, ERR_PTR(err)); + return err; + } + + return 0; +} + int luo_session_deserialize(void) { struct luo_session_header *sh =3D &luo_session_global.incoming; @@ -519,33 +553,9 @@ int luo_session_deserialize(void) * reliably reset devices and reclaim memory. */ for (int i =3D 0; i < sh->header_ser->count; i++) { - struct luo_session *session; - - session =3D luo_session_alloc(sh->ser[i].name); - if (IS_ERR(session)) { - pr_warn("Failed to allocate session [%.*s] during deserialization %pe\n= ", - (int)sizeof(sh->ser[i].name), - sh->ser[i].name, session); - return PTR_ERR(session); - } - - err =3D luo_session_insert(sh, session); - if (err) { - pr_warn("Failed to insert session [%s] %pe\n", - session->name, ERR_PTR(err)); - luo_session_free(session); - return err; - } - - scoped_guard(mutex, &session->mutex) { - err =3D luo_file_deserialize(&session->file_set, - &sh->ser[i].file_set_ser); - } - if (err) { - pr_warn("Failed to deserialize files for session [%s] %pe\n", - session->name, ERR_PTR(err)); + err =3D luo_session_deserialize_one(sh, &sh->ser[i]); + if (err) return err; - } } =20 kho_restore_free(sh->header_ser); --=20 2.53.0 From nobody Fri Jun 12 12:49:01 2026 Received: from mail-qv1-f45.google.com (mail-qv1-f45.google.com [209.85.219.45]) (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 6D4A13D1CAE for ; Thu, 14 May 2026 22:26:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797601; cv=none; b=dmFEVluvmMdatPXcQiWd/aOKt/YE8QuStASJJuj01iURSNaA6iYg4iiajineoKqvlqziU/fQchH9U75SuC5a4nLiB7ku4WXWN0F+hcpchvAGNhPHDVWdo9rGxnY2a+baIuD4PKQt+VNzdg4o3M10WafJaWmeePrssSjGTDQVjS8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797601; c=relaxed/simple; bh=5xLPUOejBaIrD+BvtyUrgcJ1vD6f9+MCOnpYJ7y9CvY=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=c//WAiGYlv97VksjBZ4CFDvZmPOXV+BpDe1tNSFSNj/rKWnGmhBpy6InIVtGzeJkW9Nrcf0/MqLwgCUwDQ8DyVejDiz9+Em/QAVNCYoeEexQfsctQNAyn4yoXEGi9nk3gc6Sw6yIFLDo5OZ2rk3DRaBlpulSTyrLiqaHUe4IUCQ= 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=j/IbRoKD; arc=none smtp.client-ip=209.85.219.45 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="j/IbRoKD" Received: by mail-qv1-f45.google.com with SMTP id 6a1803df08f44-8b4eb1fd5d0so82978016d6.0 for ; Thu, 14 May 2026 15:26:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1778797598; x=1779402398; 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=iNqqwGdiG18Z/AQkO2ZGChCHZOKJcrPhRyXZH73Csio=; b=j/IbRoKDjqoD54xBNQRFCFnYl1pwSoUbXW8tgAks/AVHQ2t4PCyj8nBJ+KOdrHGKTk 17ZOs6vqNTD1xsgvuaWcUS4lFASgs/HcaN/JCqt6+DZIm/d4cn8uZSGQ1pKOQv80cgQm 2n3XgqFRpZ464mRiMs9+k6iRvu2pYIciYzBeWEBL8AqKQ2CikkVdzAZ+KMGbVZgUWJCL VY0SwmcR9ZLjHJea27IAyU6k4g2namMAhnz9Ka2tM379HoZOrDkk2cK1BvmupPyq0Y/8 re0HrEt1gw+XiZtZVifEUse82NPYCMcdkdD/4LHKUJNFppesATWG3EN2tfI5zP1bvNNf s5Yw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778797598; x=1779402398; 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=iNqqwGdiG18Z/AQkO2ZGChCHZOKJcrPhRyXZH73Csio=; b=CtRWp81hSA/ptyNKN9cKneItNgZuIiIaDWf9ECTYTVCQQDzlqCtFCfReOfqz/wGmxh kEaS06wLsR6E5MSDwpVkJWLI+DouscwMYHgxs6j5pp1OEYA+QpJhY0aftjArbdMFTtUH PfRqKzvVSLyWq0/OvwUVwtt3apWyxUCxQ3uJ5J4+oraHAz32CcKvoH0hSbIl5GbeMZmp 4tZLR7VATOL4LN/vQIfywSCLuMUrgm0gS+UVGWi1PU/HEyavx1NriESu7oNTI/njU5uW 761Q3BfR+JADzspIcjKgVgX8fLqUe5YMlkKB4+vo/m965iTGmNjVT56Cx/Ew1vGralS2 I7qw== X-Forwarded-Encrypted: i=1; AFNElJ+b8AgyUZ3tQeC+k1iTwc6P3pzc68epNf/6qdWSNa5NJi4oori4NxUgMTPbkySG/vU22NoowEgc74WyL0Q=@vger.kernel.org X-Gm-Message-State: AOJu0YygfiuCc+iwNtCAe4CT1IDkGNR/0YO/lvfX0HCvhVmUAJtCTELE g97B7IPCcIEO8F4kHbaFE/GBkd2KkX7xd1GdP5UbvSHrAgIlyteIr5fUkC4HlEelQ1k= X-Gm-Gg: Acq92OE3l0Uiv7EYgUu3oi/taSLm4qagri+4hfQ18AaBaE2kWmtwOgDzjq0OWnIYE6v J68u8b2rJYG9jw/CllR8EEM3KkjcoJqNO/A6PCQJA5u8WPHFY9Ja10LS16xlcfeFW4vhQETnwTt 982WmCJ9tEnTmx57tH9+1n7RiHOBwOSGLCfQiWZ1MPjFdOxbPXaJ/Y2iEJZeVBlueNmPWMCBlvk YOaruMecmgePLRHZZaQRfEuu4VZVbUr+VetWaVS/7CIRFBrPHAfjFIsJ9rnnJ/jKcYYTv9/1l2O y9Hgjobt2Gv2+ys78dL1WifO8c5TA3/nuZX+6juBEZhhg1cgkL5yfT+fhBPTfRTeYhZEIQVGjNe R8unzfMCdHQkMqbsa7qxUNNUhjWiGD+TyS732uVl9KftZNII0OxXXhBLFJfg2ShJVUW0diRn5yD rpCd963CLQc2HWowmbD9eYgl8ECFSBCClzvNZvWoleJ9fEkpdqRIg= X-Received: by 2002:a05:622a:13cb:b0:509:348f:bc1a with SMTP id d75a77b69052e-5165a07eed4mr19793671cf.26.1778797598409; Thu, 14 May 2026 15:26:38 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-516456ba92fsm28671901cf.9.2026.05.14.15.26.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 15:26:37 -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, linux-kernel@vger.kernel.org, corbet@lwn.net, pasha.tatashin@soleen.com, dmatlack@google.com, kexec@lists.infradead.org, pratyush@kernel.org, skhawaja@google.com, graf@amazon.com Subject: [PATCH v2 04/10] liveupdate: add support for linked-block serialization Date: Thu, 14 May 2026 22:26:22 +0000 Message-ID: <20260514222628.931312-5-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260514222628.931312-1-pasha.tatashin@soleen.com> References: <20260514222628.931312-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 linked-block serialization mechanism for LUO state. Previously, LUO used contiguous memory blocks for serializing sessions and files, which imposed limits on the total number of items that could be preserved across a live update. This commit adds the infrastructure for a more flexible, block-based approach where serialized data is stored in a chain of linked blocks. This is a preparatory step to allow an unlimited number of luo_sessions and luo_files to be preserved. Signed-off-by: Pasha Tatashin --- Documentation/core-api/liveupdate.rst | 8 + include/linux/kho/abi/luo.h | 22 ++ kernel/liveupdate/Makefile | 1 + kernel/liveupdate/luo_block.c | 388 ++++++++++++++++++++++++++ kernel/liveupdate/luo_internal.h | 57 ++++ 5 files changed, 476 insertions(+) create mode 100644 kernel/liveupdate/luo_block.c diff --git a/Documentation/core-api/liveupdate.rst b/Documentation/core-api= /liveupdate.rst index 5a292d0f3706..978beb02292f 100644 --- a/Documentation/core-api/liveupdate.rst +++ b/Documentation/core-api/liveupdate.rst @@ -23,6 +23,11 @@ LUO File Lifecycle Bound Global Data .. kernel-doc:: kernel/liveupdate/luo_flb.c :doc: LUO File Lifecycle Bound Global Data =20 +LUO Serialization Blocks +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +.. kernel-doc:: kernel/liveupdate/luo_block.c + :doc: LUO Serialization Blocks + Live Update Orchestrator 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 .. kernel-doc:: include/linux/kho/abi/luo.h @@ -65,6 +70,9 @@ Internal API .. kernel-doc:: kernel/liveupdate/luo_file.c :internal: =20 +.. kernel-doc:: kernel/liveupdate/luo_block.c + :internal: + See Also =3D=3D=3D=3D=3D=3D=3D=3D =20 diff --git a/include/linux/kho/abi/luo.h b/include/linux/kho/abi/luo.h index 1b2f865a771a..2ba447c0c1ba 100644 --- a/include/linux/kho/abi/luo.h +++ b/include/linux/kho/abi/luo.h @@ -49,6 +49,11 @@ * The central ABI structure that contains the overall state of the LU= O. * It includes the liveupdate-number and pointers to sessions and FLBs. * + * - struct luo_block_header_ser: + * Header for the session or file data block. Contains the physical ad= dress + * of the next data block and the number of entries that follow this + * header in the current block. + * * - struct luo_session_header_ser: * Header for the session array. Contains the total page count of the * preserved memory block and the number of `struct luo_session_ser` @@ -105,6 +110,23 @@ struct luo_ser { =20 #define LIVEUPDATE_HNDL_COMPAT_LENGTH 48 =20 +/** + * struct luo_block_header_ser - Header for the serialized data block. + * @next: Physical address of the next struct luo_block_header_ser. + * @count: The number of entries that immediately follow this header in the + * memory block. + * + * This structure is located at the beginning of a block of + * physical memory preserved across the kexec. It provides the necessary + * metadata to interpret the array of entries that follow. + * + * If this structure is modified, `LUO_FDT_COMPATIBLE` must be updated. + */ +struct luo_block_header_ser { + u64 next; + u64 count; +} __packed; + /** * struct luo_file_ser - Represents the serialized preserves files. * @compatible: File handler compatible string. diff --git a/kernel/liveupdate/Makefile b/kernel/liveupdate/Makefile index d2f779cbe279..9f8f6fb1b8e5 100644 --- a/kernel/liveupdate/Makefile +++ b/kernel/liveupdate/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 =20 luo-y :=3D \ + luo_block.o \ luo_core.o \ luo_file.o \ luo_flb.o \ diff --git a/kernel/liveupdate/luo_block.c b/kernel/liveupdate/luo_block.c new file mode 100644 index 000000000000..0be0669b5cac --- /dev/null +++ b/kernel/liveupdate/luo_block.c @@ -0,0 +1,388 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (c) 2026, Google LLC. + * Pasha Tatashin + */ + +/** + * DOC: LUO Serialization Blocks + * + * LUO provides a mechanism to preserve stateful data across a kexec-based= live + * update by serializing it into contiguous memory blocks. This file provi= des + * the common infrastructure for managing these blocks. + * + * Each block consists of a header (struct luo_block_header_ser) followed = by an + * array of serialized entries. Multiple blocks are linked together via a + * physical pointer in the header, forming a linked list that can be easily + * traversed in both the current and the next kernel. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include "luo_internal.h" + +/* 2 4K pages, give space for 170 sessions or 127 files per block */ +#define LUO_BLOCK_PGCNT 2ul +#define LUO_BLOCK_SIZE (LUO_BLOCK_PGCNT << PAGE_SHIFT) + +/* + * Safeguard limit for the number of serialization blocks. This is used to + * prevent infinite loops and excessive memory allocation in case of memory + * corruption in the preserved state. + * + * This limit allows for 1.7 million sessions and 1.27 million files per + * session, which is more than enough for all realistic use cases. + */ +#define LUO_MAX_BLOCKS 10000 + +/** + * luo_block_set_init - Initialize a block set. + * @bs: The block set to initialize. + * @entry_size: The size of each entry in the blocks. + */ +void luo_block_set_init(struct luo_block_set *bs, size_t entry_size) +{ + *bs =3D (struct luo_block_set)LUO_BLOCK_SET_INIT(*bs, entry_size); +} + +static inline u64 luo_block_count_per_block(struct luo_block_set *bs) +{ + if (unlikely(!bs->count_per_block)) { + bs->count_per_block =3D (LUO_BLOCK_SIZE - + sizeof(struct luo_block_header_ser)) / + bs->entry_size; + WARN_ON(!bs->count_per_block); + } + return bs->count_per_block; +} + +/* Free serialzied data */ +static void luo_block_free_ser(struct luo_block_set *bs, + struct luo_block_header_ser *ser) +{ + if (bs->incoming) + kho_restore_free(ser); + else + kho_unpreserve_free(ser); +} + +static struct luo_block_header_ser *luo_block_alloc_ser(struct luo_block_s= et *bs) +{ + WARN_ON(bs->incoming); + return kho_alloc_preserve(LUO_BLOCK_SIZE); +} + +static int luo_block_add(struct luo_block_set *bs, + struct luo_block_header_ser *ser) +{ + struct luo_block *block, *last; + + if (bs->nblocks >=3D LUO_MAX_BLOCKS) + return -ENOSPC; + + block =3D kzalloc_obj(*block); + if (!block) + return -ENOMEM; + + block->ser =3D ser; + last =3D list_last_entry_or_null(&bs->blocks, struct luo_block, list); + list_add_tail(&block->list, &bs->blocks); + bs->nblocks++; + + if (last) + last->ser->next =3D virt_to_phys(ser); + else + bs->head_pa =3D virt_to_phys(ser); + + return 0; +} + +/** + * luo_block_grow - Create a new block if the current capacity is reached. + * @bs: The block set. + * @count: The current number of entries. + * + * This function handles the dynamic expansion of a block set. It allocates + * and links a new serialization block if the provided entry count matches + * the current total capacity of the set. + * + * Return: 0 on success, or a negative errno on failure. + */ +int luo_block_grow(struct luo_block_set *bs, u64 count) +{ + struct luo_block_header_ser *ser; + int err; + + if (WARN_ON(bs->incoming)) + return -EINVAL; + + if (count !=3D bs->nblocks * luo_block_count_per_block(bs)) + return 0; + + ser =3D luo_block_alloc_ser(bs); + if (IS_ERR(ser)) + return PTR_ERR(ser); + + err =3D luo_block_add(bs, ser); + if (err) { + luo_block_free_ser(bs, ser); + return err; + } + + return 0; +} + +/** + * luo_block_shrink - Conditionally destroy the last block in a block set. + * @bs: The block set. + * @count: The current number of entries across all blocks. + * + * This function checks if the last block in the set is redundant based on= the + * total entry count and the capacity of the preceding blocks. If the entry + * count can be accommodated by the blocks that come before the last one, = the + * last block is destroyed and removed from the set. + */ +void luo_block_shrink(struct luo_block_set *bs, u64 count) +{ + struct luo_block *last, *new_last; + + if (count > (bs->nblocks - 1) * luo_block_count_per_block(bs)) + return; + + if (list_empty(&bs->blocks)) + return; + + last =3D list_last_entry(&bs->blocks, struct luo_block, list); + list_del(&last->list); + bs->nblocks--; + luo_block_free_ser(bs, last->ser); + kfree(last); + + new_last =3D list_last_entry_or_null(&bs->blocks, struct luo_block, list); + if (new_last) + new_last->ser->next =3D 0; + else + bs->head_pa =3D 0; +} + +/* + * luo_cyclic_blocks_check - Check for cycles in a linked list of blocks. + * Uses Floyd's cycle-finding algorithm to ensure sanity of the incoming l= ist. + */ +static bool luo_cyclic_blocks_check(struct luo_block_set *bs) +{ + struct luo_block_header_ser *fast; + struct luo_block_header_ser *slow; + int count =3D 0; + + fast =3D phys_to_virt(bs->head_pa); + slow =3D fast; + + while (fast) { + if (count++ >=3D LUO_MAX_BLOCKS) { + pr_err("Linked list too long\n"); + return false; + } + + if (!fast->next) + break; + + fast =3D phys_to_virt(fast->next); + if (!fast->next) + break; + + fast =3D phys_to_virt(fast->next); + slow =3D phys_to_virt(slow->next); + + if (slow =3D=3D fast) { + pr_err("Cyclic list detected\n"); + return false; + } + } + + return true; +} + +/** + * luo_block_restore - Restore a block set from a physical address. + * @bs: The block set to restore. + * @head_pa: Physical address of the first block header. + * + * Return: 0 on success, or a negative errno on failure. + */ +int luo_block_restore(struct luo_block_set *bs, u64 head_pa) +{ + struct luo_block_header_ser *ser; + u64 next_pa =3D head_pa; + int err; + + /* Restored block sets use size from the previous kernel */ + bs->incoming =3D true; + if (!head_pa) + return 0; + + bs->head_pa =3D head_pa; + if (!luo_cyclic_blocks_check(bs)) + return -EINVAL; + + while (next_pa) { + ser =3D phys_to_virt(next_pa); + if (ser->count > luo_block_count_per_block(bs)) { + pr_warn("Block contains too many entries: %llu\n", + ser->count); + err =3D -EINVAL; + goto err_destroy; + } + err =3D luo_block_add(bs, ser); + if (err) + goto err_destroy; + next_pa =3D ser->next; + } + + return 0; + +err_destroy: + luo_block_destroy(bs); + return err; +} + +/** + * luo_block_destroy - Destroy all blocks in a block set. + * @bs: The block set. + */ +void luo_block_destroy(struct luo_block_set *bs) +{ + u64 head_pa =3D bs->head_pa; + struct luo_block *block; + + while (!list_empty(&bs->blocks)) { + block =3D list_first_entry(&bs->blocks, struct luo_block, list); + list_del(&block->list); + kfree(block); + } + bs->nblocks =3D 0; + bs->head_pa =3D 0; + + while (head_pa) { + struct luo_block_header_ser *ser =3D phys_to_virt(head_pa); + + head_pa =3D ser->next; + luo_block_free_ser(bs, ser); + } +} + +/** + * luo_block_set_clear - Clear all serialized data in a block set. + * @bs: The block set to clear. + */ +void luo_block_set_clear(struct luo_block_set *bs) +{ + struct luo_block *block; + + list_for_each_entry(block, &bs->blocks, list) { + block->ser->count =3D 0; + memset(block->ser + 1, 0, LUO_BLOCK_SIZE - sizeof(*block->ser)); + } +} + +/** + * luo_block_it_init - Initialize a block set iterator. + * @it: The iterator to initialize. + * @bs: The block set to iterate over. + */ +void luo_block_it_init(struct luo_block_it *it, struct luo_block_set *bs) +{ + it->bs =3D bs; + it->block =3D list_first_entry_or_null(&bs->blocks, struct luo_block, lis= t); + it->i =3D 0; +} + +/** + * luo_block_it_next - Return the next entry slot in the block set. + * @it: The block iterator. + * + * If the current block is full, it automatically advances to the next blo= ck + * in the set. + * + * Return: A pointer to the next entry slot, or NULL if no more slots are + * available. + */ +void *luo_block_it_next(struct luo_block_it *it) +{ + if (!it->block) + return NULL; + + if (it->i =3D=3D luo_block_count_per_block(it->bs)) { + it->block->ser->count =3D it->i; + if (list_is_last(&it->block->list, &it->bs->blocks)) + return NULL; + it->block =3D list_next_entry(it->block, list); + it->i =3D 0; + } + + return (void *)(it->block->ser + 1) + (it->i++ * it->bs->entry_size); +} + +/** + * luo_block_it_read - Return the next entry slot for reading. + * @it: The block iterator. + * + * This function iterates through entries that were previously serialized, + * respecting the count stored in each block's header. + * + * Return: A pointer to the next entry slot, or NULL if no more entries are + * available. + */ +void *luo_block_it_read(struct luo_block_it *it) +{ + if (!it->block) + return NULL; + + while (it->i =3D=3D it->block->ser->count) { + if (list_is_last(&it->block->list, &it->bs->blocks)) + return NULL; + it->block =3D list_next_entry(it->block, list); + it->i =3D 0; + } + + return (void *)(it->block->ser + 1) + (it->i++ * it->bs->entry_size); +} + +/** + * luo_block_it_prev - Return the previous entry slot in the block set. + * @it: The block iterator. + * + * If the current index is at the start of a block, it automatically moves= to + * the end of the previous block. + * + * Return: A pointer to the previous entry slot, or NULL if at the very + * beginning of the block set. + */ +void *luo_block_it_prev(struct luo_block_it *it) +{ + if (!it->block) + return NULL; + + if (it->i =3D=3D 0) { + if (list_is_first(&it->block->list, &it->bs->blocks)) + return NULL; + it->block =3D list_prev_entry(it->block, list); + it->i =3D luo_block_count_per_block(it->bs); + } + + return (void *)(it->block->ser + 1) + (--it->i * it->bs->entry_size); +} + +/** + * luo_block_it_finalize - Finalize the current block by setting its entry= count. + * @it: The block iterator. + */ +void luo_block_it_finalize(struct luo_block_it *it) +{ + if (it->block) + it->block->ser->count =3D it->i; +} diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_inter= nal.h index 4b6c18348d9b..04f31319ccdf 100644 --- a/kernel/liveupdate/luo_internal.h +++ b/kernel/liveupdate/luo_internal.h @@ -40,6 +40,51 @@ static inline int luo_ucmd_respond(struct luo_ucmd *ucmd, */ #define luo_restore_fail(__fmt, ...) panic(__fmt, ##__VA_ARGS__) =20 +/** + * struct luo_block - Internal representation of a serialization block. + * @list: List head for linking blocks in memory. + * @ser: Pointer to the serialized header in preserved memory. + */ +struct luo_block { + struct list_head list; + struct luo_block_header_ser *ser; +}; + +/** + * struct luo_block_set - A set of blocks that belong to the same object. + * @blocks: The list of serialization blocks (struct luo_block). + * @nblocks: The number of allocated serialization blocks. + * @head_pa: Physical address of the first block header. + * @entry_size: The size of each entry in the blocks. + * @count_per_block: The maximum number of entries each block can hold. + * @incoming: True if this block set was restored from the previous= kernel. + */ +struct luo_block_set { + struct list_head blocks; + long nblocks; + u64 head_pa; + size_t entry_size; + u64 count_per_block; + bool incoming; +}; + +/** + * struct luo_block_it - Iterator for serializing entries into blocks. + * @bs: The block set being iterated. + * @block: The current block. + * @i: The current entry index within @block. + */ +struct luo_block_it { + struct luo_block_set *bs; + struct luo_block *block; + u64 i; +}; + +#define LUO_BLOCK_SET_INIT(name, _entry_size) { \ + .blocks =3D LIST_HEAD_INIT((name).blocks), \ + .entry_size =3D _entry_size, \ +} + /** * struct luo_file_set - A set of files that belong to the same sessions. * @files_list: An ordered list of files associated with this session, it = is @@ -100,6 +145,18 @@ int luo_file_deserialize(struct luo_file_set *file_set, void luo_file_set_init(struct luo_file_set *file_set); void luo_file_set_destroy(struct luo_file_set *file_set); =20 +void luo_block_set_init(struct luo_block_set *bs, size_t entry_size); +int luo_block_grow(struct luo_block_set *bs, u64 count); +void luo_block_shrink(struct luo_block_set *bs, u64 count); +int luo_block_restore(struct luo_block_set *bs, u64 head_pa); +void luo_block_destroy(struct luo_block_set *bs); +void luo_block_set_clear(struct luo_block_set *bs); +void luo_block_it_init(struct luo_block_it *it, struct luo_block_set *bs); +void *luo_block_it_next(struct luo_block_it *it); +void *luo_block_it_read(struct luo_block_it *it); +void *luo_block_it_prev(struct luo_block_it *it); +void luo_block_it_finalize(struct luo_block_it *it); + int luo_flb_file_preserve(struct liveupdate_file_handler *fh); void luo_flb_file_unpreserve(struct liveupdate_file_handler *fh); void luo_flb_file_finish(struct liveupdate_file_handler *fh); --=20 2.53.0 From nobody Fri Jun 12 12:49:01 2026 Received: from mail-qt1-f175.google.com (mail-qt1-f175.google.com [209.85.160.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 DC60D3D25B1 for ; Thu, 14 May 2026 22:26:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797602; cv=none; b=eC/tXhB6MWu5zXExl2IMdAwZL/uVbu3N0crHW+TTPCxNTwQ84pH7608GKnKgHyc/E3bR1oYSdPictk9InxW3+a/XFt/ioPvQNPuZMjW663gw79o5Hz614+wuTuPHAyOOLHDoSNI5R96Y7h3OPryKOq69x/AYxHgh5Cu60vg5eWE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797602; c=relaxed/simple; bh=a0VHFJPCyhL3TbqKc1uvHP9e7w/9wd3KOhTGNjyl+S4=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NV0BBaT4ixsaYBBu8R+FLCqEOobqIrK7CFmf0U1SgvVFSeBTwiFLFBCq8yRA4NAyu1sHlY0CAMHxeHKT9p708sVufXnTfwVP+j4kqQc8pHlLO9ClMdMnk0XFpS1OljhTetjeiAv8iUJO13oYHfNOGVHJ300RG2rvS0sBxxkZDkQ= 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=fGTGlgpx; arc=none smtp.client-ip=209.85.160.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="fGTGlgpx" Received: by mail-qt1-f175.google.com with SMTP id d75a77b69052e-50fb4a7d704so64170801cf.1 for ; Thu, 14 May 2026 15:26:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1778797600; x=1779402400; 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=Eb8o2KCzs8bbwuZWDFPZ38APTKPTdJK2DFY1v5TRs6Q=; b=fGTGlgpxN8bQJqB7vk9M8MrSRxSL2RoHVCU+Wkz9n4fhx5bWSYMZruscI5tT//K+Uv ZZgCC05c9sb1lqmi7Dgh4hJlYgv7FVaceoPGd5UmQg9Ioq+XjlXiSt49fqGSOlHVjlCq 7VzkD4K0ZUh0c8aqcALpHRNH2wfrSKxQloL1ubA7WWR4PojGCGDxGwnKD1xQPkNbjgGM UJBmXpiIwvfFTKEnaiDWtYAIkert8XJo7piOqjWq203oUCVi/REG6M/4HfvmABbe5GEg fc9qxPvy+rg4dIQAy1tKqeF4tufZd+Se9rvxt9sh0r6wSQCULuJUJAeygS0rwpdHIUds VRXQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778797600; x=1779402400; 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=Eb8o2KCzs8bbwuZWDFPZ38APTKPTdJK2DFY1v5TRs6Q=; b=tZd4mrE15CF4JyB2FRzBXC16g9mC57MvmqTURZz1IUrsHKAXN4jZ7dKzz8agVy/tSN NvcJsftdrTiG57F6/iKGkUEqaXH5sM2WUA2pYpyvAy3AmvFmAwl05fRARYBUHM5iV9v4 xtT9FLvCrADIMkQVgmEhiHWVsAGsvX5ueBukxj43s3rABTddPUEfkdNNQa5dHOZFNkS+ rcpIt3XbAiCQjeqFePhl0ORLrupwXWwPr8bNzVo5LfkKLr85zOB07KZbrANocFhPKh8m 3kVcLOV9oUk1ZxTS/93lgQ+YGNdwqft94yughIwTtqGFFU5x8YRU6My6+guRG1wHL1Hw o8CA== X-Forwarded-Encrypted: i=1; AFNElJ/YEogxii5v464tddMlkcLIHsfWpadh7rkN+396+mLr01vQBIpmXbfHWh329jrJZjZKKPAaLqRUIgnaFjg=@vger.kernel.org X-Gm-Message-State: AOJu0YyYB38MGUnO7UsAAP7mSPNONxh8O7cFMDG+8KmVEIUMgtYezTTJ Gv5iCruLrmCM4bklZP5tBI5ZAg1PRehG8JYeV1nsAMJv1p+YS1Fim6khxkreRgND0Afb9/5PLMm B+NQ4zB8= X-Gm-Gg: Acq92OEGB/SW+b+8w6HiLAAUjZbcgLglkiVV3YjG8PVjmxB/mMV0tNQZkF/u1nap2th pXKs9DUVpTv1BD+a/Dq/uvhk4FJAyytR+EAzi9zdQ5myL2+/LUSS3mK0DhdAy/TFCSR94pdm22I fSNGCiu3Rokw6Ks0MhgI2KtnoQv1YQsEFNWXhLfbFIBrgMwHQV3s2x8zC6cXoeKjICxZY4dCBRo v8ZlzZ2gXJLVg1iabJmkC1P7Blmb/SQ1cS8tZ4STKOxAtCVm6MXizK35ODOjKtQ4zZI9WAgUPbi erVSOFZ+U/hAClTvCrpmUJIpfM0uvlV8pNQT9mL/3LolVJXk5QonFofm4eqxOcuHqmUsomPRA1S fbVLuIUdyHZstpsJzsO3xMf6NdAojBNVlA8+SpNjqkGXsfGStokroPWSPzSSZY91zB+k2pcOmQi 1Mbfpf+Iijm2E/p/JrSi7ZwDg3NtzKSAjGJIg4KvxXlgBya9cwLOw= X-Received: by 2002:ac8:5cc5:0:b0:50e:601a:217f with SMTP id d75a77b69052e-5165a076dcamr19672381cf.25.1778797599975; Thu, 14 May 2026 15:26:39 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-516456ba92fsm28671901cf.9.2026.05.14.15.26.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 15:26:39 -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, linux-kernel@vger.kernel.org, corbet@lwn.net, pasha.tatashin@soleen.com, dmatlack@google.com, kexec@lists.infradead.org, pratyush@kernel.org, skhawaja@google.com, graf@amazon.com Subject: [PATCH v2 05/10] liveupdate: defer session block allocation and PA setting Date: Thu, 14 May 2026 22:26:23 +0000 Message-ID: <20260514222628.931312-6-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260514222628.931312-1-pasha.tatashin@soleen.com> References: <20260514222628.931312-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" Currently, luo_session_setup_outgoing() allocates the session block and sets its physical address in the header immediately. With upcoming dynamic block-based session management, this makes the first block different from the rest. Move the allocation to where it is first needed. Signed-off-by: Pasha Tatashin Acked-by: Mike Rapoport (Microsoft) --- kernel/liveupdate/luo_core.c | 4 +- kernel/liveupdate/luo_internal.h | 2 +- kernel/liveupdate/luo_session.c | 68 ++++++++++++++++++++------------ 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c index 9bd649b22029..5dd7f1e7dddb 100644 --- a/kernel/liveupdate/luo_core.c +++ b/kernel/liveupdate/luo_core.c @@ -189,9 +189,7 @@ static int __init luo_fdt_setup(void) if (err) goto exit_free_luo_ser; =20 - err =3D luo_session_setup_outgoing(&luo_ser->sessions_pa); - if (err) - goto exit_free_luo_ser; + luo_session_setup_outgoing(&luo_ser->sessions_pa); =20 err =3D luo_flb_setup_outgoing(&luo_ser->flbs_pa); if (err) diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_inter= nal.h index 04f31319ccdf..090078ad771c 100644 --- a/kernel/liveupdate/luo_internal.h +++ b/kernel/liveupdate/luo_internal.h @@ -126,7 +126,7 @@ extern struct rw_semaphore luo_register_rwlock; =20 int luo_session_create(const char *name, struct file **filep); int luo_session_retrieve(const char *name, struct file **filep); -int __init luo_session_setup_outgoing(u64 *sessions_pa); +void __init luo_session_setup_outgoing(u64 *sessions_pa); int __init luo_session_setup_incoming(u64 sessions_pa); int luo_session_serialize(void); int luo_session_deserialize(void); diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_sessio= n.c index c08733a328bc..339514e8122c 100644 --- a/kernel/liveupdate/luo_session.c +++ b/kernel/liveupdate/luo_session.c @@ -77,15 +77,16 @@ =20 /** * struct luo_session_header - Header struct for managing LUO sessions. - * @count: The number of sessions currently tracked in the @list. - * @list: The head of the linked list of `struct luo_session` instan= ces. - * @rwsem: A read-write semaphore providing synchronized access to the - * session list and other fields in this structure. - * @header_ser: The header data of serialization array. - * @ser: The serialized session data (an array of - * `struct luo_session_ser`). - * @active: Set to true when first initialized. If previous kernel did= not - * send session data, active stays false for incoming. + * @count: The number of sessions currently tracked in the @list. + * @list: The head of the linked list of `struct luo_session` insta= nces. + * @rwsem: A read-write semaphore providing synchronized access to t= he + * session list and other fields in this structure. + * @header_ser: The header data of serialization array. + * @ser: The serialized session data (an array of + * `struct luo_session_ser`). + * @sessions_pa: Points to the location of sessions_pa within struct luo_s= er. + * @active: Set to true when first initialized. If previous kernel di= d not + * send session data, active stays false for incoming. */ struct luo_session_header { long count; @@ -93,6 +94,7 @@ struct luo_session_header { struct rw_semaphore rwsem; struct luo_session_header_ser *header_ser; struct luo_session_ser *ser; + u64 *sessions_pa; bool active; }; =20 @@ -140,10 +142,30 @@ static void luo_session_free(struct luo_session *sess= ion) kfree(session); } =20 +static int luo_session_grow_ser(struct luo_session_header *sh) +{ + struct luo_session_header_ser *header_ser; + + if (sh->count =3D=3D LUO_SESSION_MAX) + return -ENOMEM; + + if (sh->header_ser) + return 0; + + header_ser =3D kho_alloc_preserve(LUO_SESSION_PGCNT << PAGE_SHIFT); + if (IS_ERR(header_ser)) + return PTR_ERR(header_ser); + + sh->header_ser =3D header_ser; + sh->ser =3D (void *)(header_ser + 1); + return 0; +} + static int luo_session_insert(struct luo_session_header *sh, struct luo_session *session) { struct luo_session *it; + int err; =20 guard(rwsem_write)(&sh->rwsem); =20 @@ -152,8 +174,9 @@ static int luo_session_insert(struct luo_session_header= *sh, * for new session. */ if (sh =3D=3D &luo_session_global.outgoing) { - if (sh->count =3D=3D LUO_SESSION_MAX) - return -ENOMEM; + err =3D luo_session_grow_ser(sh); + if (err) + return err; } =20 /* @@ -458,21 +481,10 @@ int luo_session_retrieve(const char *name, struct fil= e **filep) return err; } =20 -int __init luo_session_setup_outgoing(u64 *sessions_pa) +void __init luo_session_setup_outgoing(u64 *sessions_pa) { - struct luo_session_header_ser *header_ser; - - header_ser =3D kho_alloc_preserve(LUO_SESSION_PGCNT << PAGE_SHIFT); - if (IS_ERR(header_ser)) - return PTR_ERR(header_ser); - - *sessions_pa =3D virt_to_phys(header_ser); - - luo_session_global.outgoing.header_ser =3D header_ser; - luo_session_global.outgoing.ser =3D (void *)(header_ser + 1); + luo_session_global.outgoing.sessions_pa =3D sessions_pa; luo_session_global.outgoing.active =3D true; - - return 0; } =20 int __init luo_session_setup_incoming(u64 sessions_pa) @@ -573,6 +585,8 @@ int luo_session_serialize(void) int err; =20 guard(rwsem_write)(&sh->rwsem); + *sh->sessions_pa =3D 0; + list_for_each_entry(session, &sh->list, list) { err =3D luo_session_freeze_one(session, &sh->ser[i]); if (err) @@ -582,7 +596,11 @@ int luo_session_serialize(void) sizeof(sh->ser[i].name)); i++; } - sh->header_ser->count =3D sh->count; + + if (sh->header_ser && sh->count > 0) { + sh->header_ser->count =3D sh->count; + *sh->sessions_pa =3D virt_to_phys(sh->header_ser); + } =20 return 0; =20 --=20 2.53.0 From nobody Fri Jun 12 12:49:01 2026 Received: from mail-qt1-f171.google.com (mail-qt1-f171.google.com [209.85.160.171]) (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 0C8103D4119 for ; Thu, 14 May 2026 22:26:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797604; cv=none; b=tGxHb3QMOa8kS/J9GAmHhmDxA60E9UAcqkB7hTcdkteFVYn3R/MYinRpFYRQPfMMO1c901Yl3AG2Is+xB6CziRUGkr7dDrO2yCUt3jYETjT7W+FE3pn6pe3p0w3MsYwKJr5bf7voDc8F4B2il5ntUP5ikVIVE6Bj490UFz+Sov0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797604; c=relaxed/simple; bh=QUWPsXAuk9w8x8hvZHmCxbdsSUfg7OnvjTcXRnKOaX8=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XTUvh6c5ISdcthyzM5ZO7OC0uCEWTlJslxvWoB1Ubo7GGgsMtR9bj8A3xncovBbMGZmsf+sVz+MVvFB6j/r3a2o61+HLHtEqZRwdViTY4xFZdcThuRlWy6TXDkzvQK75snEZXxDCpzr93dCW7va+RBhAwr56VZfsMkNiVDPXIgs= 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=GY4TZ5C6; arc=none smtp.client-ip=209.85.160.171 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="GY4TZ5C6" Received: by mail-qt1-f171.google.com with SMTP id d75a77b69052e-50d75bfb259so56813721cf.1 for ; Thu, 14 May 2026 15:26:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1778797602; x=1779402402; 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=2T3oA7tkx4rspjASSft4V+bRK2GXucIgM1nPm7xvZEk=; b=GY4TZ5C6qvkDfLtPMspH7X2oPhEKsiaJRQAn3QC/HwQyD/rhIVjsWHVMLo7okxYwAU KsytTEblAykhbXNhElVshVnHLQqhlU+wQypSSaP8WkDgGrAkqYzk/WrLYRSxsHK6/EDL oSBC3yR/y8XQekgY2Z7h4G5u9i/T5uWTV0++I67JrMzpgxuMWQKA/LW6D3k4ybxI7r/B O6yrQwkU1/UFi6I7K+C0dzpfHAcaOmXYaXc9yFaScXOWzlTw+KEQAfq2fXu0spO3mXoW Rc4SU6UnWP20Kxdyas188gdrbyoYeP30nXoFafvZT5/6DCs3BRUSrKr26txOmmqDZiux dnbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778797602; x=1779402402; 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=2T3oA7tkx4rspjASSft4V+bRK2GXucIgM1nPm7xvZEk=; b=BnhL3+Y6iW8xXZkLWm10oaxEVNlgS8nZPyhE/BkqjNiPllQcVGzkxnX5xfX7NbXrBs 8P1ZzfKf14lZTyzfMST07eBRLSJuVNyWVJ2eYjTH5uT7B1y2V5ZtvmINUuyhHk0E6zQD jjVdQ8i3Nleq7hSsMkVSeLMLoXWJ1W5oCSiuQvmV7OI+RNrHAxMQJ2/YSnMGDw9HW6jA yfbwpOuMaltyHKdJDx6CqSmHU5I4OrESVOLL8s2iXCPslTZbaFIPz4UGbMFy1d0ri7yM 4b59DgYRVA2B8iQWIUisHKaiRuGxmQp9tkNeJVhW6XF7zDFxTLeWJELdRv6k5FEittpe d7Tg== X-Forwarded-Encrypted: i=1; AFNElJ/bXRuafArDM0O+A4PzXy2akbLxACmAUBCKy3Lre8xZCvmSUI6DA4u/+TK9e3iiTyLwuexdi5YGThSu7AY=@vger.kernel.org X-Gm-Message-State: AOJu0YzB9jpvZnAooaRR1YWAqfEGYXlBsKB3TDJ6Lk/Zh342yka0IyyE RsiB1oP3JnaqSba1SiUgR3v9O58Sggmq3x/UIcANW8Eyzsi+8dxEgeXBEBSlt4tPAOk= X-Gm-Gg: Acq92OHF5WLtLxmqLTfUKN+a8LEmE0VhYXVIvicrzrpG9dh4eCb1xZ7CDu5te7Ifg+i wSTOEpFrdrcpTpZ2Mb36fbo1s3niemvYskH1bKXKIMj/quk0RGVY7ty99IdpOAbECZrvZgXbon6 gK3WRcDV0jvO/hk1ZVgFOZiUA7GOo6SVqmIC/opMpF99NfDq0MjD9hH+8aio/TXDZHp8SlrwPpL qDAlYsn5Moqbf183SaiCkO/xscD5QAL8r7iQCNC/4Hf+iC28oNcbuPKD9oa73cSj3OxGKm1Mtzd +oImmZZ7WQRkILiKmZIpxn5jA6G8ltWhZG/CDvBngAugRw9EftecdLJI36JVlIgQemquvgb2bWs kbJpCHChHA3uyCuBfcZsLA7UUjyjcGLRO5Q0BVKie2YzMfKu/+0GH5s4LrYGboX07DfxWXhOOUJ +GELZKeomDrlzy4oN0w2/ARlYTUCn5Prz/WBJdpgM2aa6T+DXAT98= X-Received: by 2002:ac8:5c92:0:b0:514:6650:eea4 with SMTP id d75a77b69052e-5165a296e10mr18589761cf.57.1778797601967; Thu, 14 May 2026 15:26:41 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-516456ba92fsm28671901cf.9.2026.05.14.15.26.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 15:26:41 -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, linux-kernel@vger.kernel.org, corbet@lwn.net, pasha.tatashin@soleen.com, dmatlack@google.com, kexec@lists.infradead.org, pratyush@kernel.org, skhawaja@google.com, graf@amazon.com Subject: [PATCH v2 06/10] liveupdate: Remove limit on the number of sessions Date: Thu, 14 May 2026 22:26:24 +0000 Message-ID: <20260514222628.931312-7-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260514222628.931312-1-pasha.tatashin@soleen.com> References: <20260514222628.931312-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" Currently, the number of LUO sessions is limited by a fixed number of pre-allocated pages for serialization (16 pages, allowing for ~819 sessions). This limitation is problematic if LUO is used to support things such as systemd file descriptor store, and would be used not just as VM memory but to save other states on the machine. Remove this limit by transitioning to a linked-block approach for session metadata serialization. Instead of a single contiguous block, session metadata is now stored in a chain of 16-page blocks. Each block starts with a header containing the physical address of the next block and the number of session entries in the current block. Signed-off-by: Pasha Tatashin Acked-by: Mike Rapoport (Microsoft) --- include/linux/kho/abi/luo.h | 24 +------- kernel/liveupdate/luo_session.c | 105 +++++++++++++++----------------- 2 files changed, 50 insertions(+), 79 deletions(-) diff --git a/include/linux/kho/abi/luo.h b/include/linux/kho/abi/luo.h index 2ba447c0c1ba..a643193a379c 100644 --- a/include/linux/kho/abi/luo.h +++ b/include/linux/kho/abi/luo.h @@ -36,7 +36,7 @@ * * Main LUO Node (/): * - * - compatible: "luo-v2" + * - compatible: "luo-v3" * Identifies the overall LUO ABI version. * - luo-abi-header: u64 * The physical address of `struct luo_ser`. @@ -54,11 +54,6 @@ * of the next data block and the number of entries that follow this * header in the current block. * - * - struct luo_session_header_ser: - * Header for the session array. Contains the total page count of the - * preserved memory block and the number of `struct luo_session_ser` - * entries that follow. - * * - struct luo_session_ser: * Metadata for a single session, including its name and a physical po= inter * to another preserved memory block containing an array of @@ -90,7 +85,7 @@ */ #define LUO_FDT_SIZE PAGE_SIZE #define LUO_FDT_KHO_ENTRY_NAME "LUO" -#define LUO_FDT_COMPATIBLE "luo-v2" +#define LUO_FDT_COMPATIBLE "luo-v3" #define LUO_FDT_ABI_HEADER "luo-abi-header" =20 /** @@ -155,21 +150,6 @@ struct luo_file_set_ser { u64 count; } __packed; =20 -/** - * struct luo_session_header_ser - Header for the serialized session data = block. - * @count: The number of `struct luo_session_ser` entries that immediately - * follow this header in the memory block. - * - * This structure is located at the beginning of a contiguous block of - * physical memory preserved across the kexec. It provides the necessary - * metadata to interpret the array of session entries that follow. - * - * If this structure is modified, `LUO_FDT_COMPATIBLE` must be updated. - */ -struct luo_session_header_ser { - u64 count; -} __packed; - /** * struct luo_session_ser - Represents the serialized metadata for a LUO s= ession. * @name: The unique name of the session, provided by the userspac= e at diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_sessio= n.c index 339514e8122c..064e83fabe62 100644 --- a/kernel/liveupdate/luo_session.c +++ b/kernel/liveupdate/luo_session.c @@ -69,21 +69,13 @@ #include #include "luo_internal.h" =20 -/* 16 4K pages, give space for 744 sessions */ -#define LUO_SESSION_PGCNT 16ul -#define LUO_SESSION_MAX (((LUO_SESSION_PGCNT << PAGE_SHIFT) - \ - sizeof(struct luo_session_header_ser)) / \ - sizeof(struct luo_session_ser)) - /** * struct luo_session_header - Header struct for managing LUO sessions. * @count: The number of sessions currently tracked in the @list. * @list: The head of the linked list of `struct luo_session` insta= nces. * @rwsem: A read-write semaphore providing synchronized access to t= he * session list and other fields in this structure. - * @header_ser: The header data of serialization array. - * @ser: The serialized session data (an array of - * `struct luo_session_ser`). + * @block_set: The set of serialization blocks. * @sessions_pa: Points to the location of sessions_pa within struct luo_s= er. * @active: Set to true when first initialized. If previous kernel di= d not * send session data, active stays false for incoming. @@ -92,8 +84,7 @@ struct luo_session_header { long count; struct list_head list; struct rw_semaphore rwsem; - struct luo_session_header_ser *header_ser; - struct luo_session_ser *ser; + struct luo_block_set block_set; u64 *sessions_pa; bool active; }; @@ -112,10 +103,14 @@ static struct luo_session_global luo_session_global = =3D { .incoming =3D { .list =3D LIST_HEAD_INIT(luo_session_global.incoming.list), .rwsem =3D __RWSEM_INITIALIZER(luo_session_global.incoming.rwsem), + .block_set =3D LUO_BLOCK_SET_INIT(luo_session_global.incoming.block_set, + sizeof(struct luo_session_ser)), }, .outgoing =3D { .list =3D LIST_HEAD_INIT(luo_session_global.outgoing.list), .rwsem =3D __RWSEM_INITIALIZER(luo_session_global.outgoing.rwsem), + .block_set =3D LUO_BLOCK_SET_INIT(luo_session_global.outgoing.block_set, + sizeof(struct luo_session_ser)), }, }; =20 @@ -142,25 +137,6 @@ static void luo_session_free(struct luo_session *sessi= on) kfree(session); } =20 -static int luo_session_grow_ser(struct luo_session_header *sh) -{ - struct luo_session_header_ser *header_ser; - - if (sh->count =3D=3D LUO_SESSION_MAX) - return -ENOMEM; - - if (sh->header_ser) - return 0; - - header_ser =3D kho_alloc_preserve(LUO_SESSION_PGCNT << PAGE_SHIFT); - if (IS_ERR(header_ser)) - return PTR_ERR(header_ser); - - sh->header_ser =3D header_ser; - sh->ser =3D (void *)(header_ser + 1); - return 0; -} - static int luo_session_insert(struct luo_session_header *sh, struct luo_session *session) { @@ -174,7 +150,7 @@ static int luo_session_insert(struct luo_session_header= *sh, * for new session. */ if (sh =3D=3D &luo_session_global.outgoing) { - err =3D luo_session_grow_ser(sh); + err =3D luo_block_grow(&sh->block_set, sh->count); if (err) return err; } @@ -201,6 +177,8 @@ static void luo_session_remove(struct luo_session_heade= r *sh, guard(rwsem_write)(&sh->rwsem); list_del(&session->list); sh->count--; + if (sh =3D=3D &luo_session_global.outgoing) + luo_block_shrink(&sh->block_set, sh->count); } =20 static int luo_session_finish_one(struct luo_session *session) @@ -489,15 +467,17 @@ void __init luo_session_setup_outgoing(u64 *sessions_= pa) =20 int __init luo_session_setup_incoming(u64 sessions_pa) { - struct luo_session_header_ser *header_ser; + struct luo_session_header *sh =3D &luo_session_global.incoming; + int err; =20 - if (sessions_pa) { - header_ser =3D phys_to_virt(sessions_pa); - luo_session_global.incoming.header_ser =3D header_ser; - luo_session_global.incoming.ser =3D (void *)(header_ser + 1); - luo_session_global.incoming.active =3D true; - } + if (!sessions_pa) + return 0; =20 + err =3D luo_block_restore(&sh->block_set, sessions_pa); + if (err) + return err; + + sh->active =3D true; return 0; } =20 @@ -539,6 +519,8 @@ int luo_session_deserialize(void) { struct luo_session_header *sh =3D &luo_session_global.incoming; static bool is_deserialized; + struct luo_session_ser *ser; + struct luo_block_it it; static int err; =20 /* If has been deserialized, always return the same error code */ @@ -564,51 +546,60 @@ int luo_session_deserialize(void) * userspace to detect the failure and trigger a reboot, which will * reliably reset devices and reclaim memory. */ - for (int i =3D 0; i < sh->header_ser->count; i++) { - err =3D luo_session_deserialize_one(sh, &sh->ser[i]); + luo_block_it_init(&it, &sh->block_set); + while ((ser =3D luo_block_it_read(&it))) { + err =3D luo_session_deserialize_one(sh, ser); if (err) - return err; + goto err_destroy_blocks; } =20 - kho_restore_free(sh->header_ser); - sh->header_ser =3D NULL; - sh->ser =3D NULL; +err_destroy_blocks: + luo_block_destroy(&sh->block_set); =20 - return 0; + return err; } =20 int luo_session_serialize(void) { struct luo_session_header *sh =3D &luo_session_global.outgoing; struct luo_session *session; - int i =3D 0; + struct luo_block_it it; int err; =20 guard(rwsem_write)(&sh->rwsem); *sh->sessions_pa =3D 0; =20 + luo_block_it_init(&it, &sh->block_set); + list_for_each_entry(session, &sh->list, list) { - err =3D luo_session_freeze_one(session, &sh->ser[i]); + struct luo_session_ser *ser =3D luo_block_it_next(&it); + + if (!ser) { + err =3D -ENOSPC; + goto err_undo; + } + + err =3D luo_session_freeze_one(session, ser); if (err) goto err_undo; =20 - strscpy(sh->ser[i].name, session->name, - sizeof(sh->ser[i].name)); - i++; + strscpy(ser->name, session->name, sizeof(ser->name)); } =20 - if (sh->header_ser && sh->count > 0) { - sh->header_ser->count =3D sh->count; - *sh->sessions_pa =3D virt_to_phys(sh->header_ser); - } + luo_block_it_finalize(&it); + + if (sh->sessions_pa && sh->count > 0) + *sh->sessions_pa =3D sh->block_set.head_pa; =20 return 0; =20 err_undo: + luo_block_it_prev(&it); list_for_each_entry_continue_reverse(session, &sh->list, list) { - i--; - luo_session_unfreeze_one(session, &sh->ser[i]); - memset(sh->ser[i].name, 0, sizeof(sh->ser[i].name)); + struct luo_session_ser *ser =3D luo_block_it_prev(&it); + + luo_session_unfreeze_one(session, ser); + memset(ser->name, 0, sizeof(ser->name)); } =20 return err; --=20 2.53.0 From nobody Fri Jun 12 12:49:01 2026 Received: from mail-qv1-f47.google.com (mail-qv1-f47.google.com [209.85.219.47]) (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 B68233D413B for ; Thu, 14 May 2026 22:26:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797607; cv=none; b=bQHBP9s+UmUQLPjWYNN+M4O376fbLf3ChBuL4EulI/nn1CLMxJrJjLDBd/h5JDFufWlxItnoC4cOakRt5s7wPDMJxddApv4Kdb0MrggyHaEPp0tI2V25XtImhseQxD8DQfqj0uxiovheOtUSWoPT+7r07jSXE1u348+otN1ltpM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797607; c=relaxed/simple; bh=sJmEHcRTtHNVMsa8FZCJha+EKzJEBQis3z7BQaBPs/k=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=unRe7udTXB5dcMVV+8nFF7ZG8MQhZyx9N/CHvtO9nKT+CS/EJmwNfPUyUDHx/E8k92oaVqGc3MNrq+qWRXPn0pcoo2O5bcy0q+EFsVCocI9VSEOaSjYZ5DkLQlyDc6WA+POcscOPDetCbFnXndCUGMHHsqfXsFUJPI0tU3Jktxc= 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=AVFyIJ9f; arc=none smtp.client-ip=209.85.219.47 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="AVFyIJ9f" Received: by mail-qv1-f47.google.com with SMTP id 6a1803df08f44-8b5cda2dab9so3210166d6.0 for ; Thu, 14 May 2026 15:26:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1778797605; x=1779402405; 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=aQqqDxa74bXnO1ngkkwE1THWbm/MOk0NCF6+LcpRWdU=; b=AVFyIJ9fKxqwgdnttgDnTK5taUIAf+llSCQWmU/DPdYutzjtPoekyat0ZiA09BqJ1G 9CVSgRhsnIULC2Q5GelLNxldsy0Mma4FufZIyH6WklCtp/AV7aKR0kwoef2EDA5OwrKI ym8oy4qFUvGJbLxorgULQusCGmvaPSrG73ER2NcfM8kdII6RGpUrnkMKIxKwKJ8gFRob P7pf5+/ePapRZ8LR0/VSqXBUhozh0/MyGl/707glsgmxfKegl3EFtYkHuB7Zk4Et8hWK zsUMcKbk9M68WP76tRaULxbSL3siD0pCA87jhsX/izWDZkvwIqNhOh3utCgvN0nyB0rD 5RiA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778797605; x=1779402405; 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=aQqqDxa74bXnO1ngkkwE1THWbm/MOk0NCF6+LcpRWdU=; b=jvvDUInxPCQeIZrdoOW4KAG6l0HNREASt/BjB7Rzvdfjqao4/8PzLcGsqmtQ4McOTN EPqY0UL7KBBuYOeOGNQY2jdM46x4gqayanCtfHNFyo7IJiSRPY/tnWsJCJYP3/I/QOHQ u4mDWdKHrZ6ymvQsQcV9cOKI+0yn6QLSve/Ysb9oDl01ke4rsnwR38CQupCZqxajH9wu vUyJCLuLUqOnaSHYAj1y/A64KgURzaUOsHqvc9dZf2fiNlRIgeH1qv3WtUGzlwNTj+pr 2/j/G8KBS0FWR85EJjSMIEUAMgeeAb/iXl1pvIpcmq3rDE8uksepDCyWFBQzT14qkZiA oH9w== X-Forwarded-Encrypted: i=1; AFNElJ9+H52djDy7y9NX3sRNBV9Iq9ymaqyMOETSsW2+RH3+dLVUIAGFM1PVt7sfn24ex81zDTBbzVVqlDlKXYg=@vger.kernel.org X-Gm-Message-State: AOJu0YwbVEwT5LJ3i5T4V3iiQE8WSYPagkozp0tLzN1jIIhmxfqDr76L gcUgWYs2SUVxbvsUs2kr6/iY5mL+hJBUWY07LHCj9SHunOOknbEiw+2YrCQ1ZGo8NOc= X-Gm-Gg: Acq92OF+rhlWaUgKlqmtZDMNVE2BUiO7+vVJvYntY9UVsHW/lclS0NhVLsG68ZsJbaW UC3u+COJbBwBNnjy2Ol+xe8R9itaAkS1fwc4lSJsTruKP0+iMw/Zi/R0eBzdJJXAh4ukPfTYns3 53Ix7K7owBh99O6/+vSRByvXF9r+44RPAZazxSIyn4Haxst56U3nqWRfDRRspLhNXIoNaK0StiD wCJbsp9JlYyitTzXnjlWNg+8KNyPzdSA0+JC7rcYoSRqSVfp6bE9GL7RcFz3YzAdfpzMXZDQ1eA pmT8pH5koAyl8VjJshEUDaXCmhtg7vVhLEvAp6J3/I99PASLIeC5eh3rNtypTf5PKj+i50YWyoU kOd9/DOhzuqez1pQnMca6ug1anT8WSuZ9FdvI5Tzi/uVgt0UjgauQVCGAftOv9FvlyhJs99VdPK hz7E9g1SwnaEMjnYEEwMQJ4salBSx8Cp5lI8f/x6STcJLRQcdYxCICs8Wmhgp+nQ== X-Received: by 2002:a05:622a:254:b0:50f:39f4:3a2b with SMTP id d75a77b69052e-51641967867mr73061401cf.41.1778797604725; Thu, 14 May 2026 15:26:44 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-516456ba92fsm28671901cf.9.2026.05.14.15.26.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 15:26:43 -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, linux-kernel@vger.kernel.org, corbet@lwn.net, pasha.tatashin@soleen.com, dmatlack@google.com, kexec@lists.infradead.org, pratyush@kernel.org, skhawaja@google.com, graf@amazon.com Subject: [PATCH v2 07/10] liveupdate: Remove limit on the number of files per session Date: Thu, 14 May 2026 22:26:25 +0000 Message-ID: <20260514222628.931312-8-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260514222628.931312-1-pasha.tatashin@soleen.com> References: <20260514222628.931312-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" To remove the fixed limit on the number of preserved files per session, transition the file metadata serialization from a single contiguous memory block to a chain of linked blocks. Signed-off-by: Pasha Tatashin Acked-by: Mike Rapoport (Microsoft) --- include/linux/kho/abi/luo.h | 13 +-- kernel/liveupdate/luo_file.c | 142 +++++++++++++++---------------- kernel/liveupdate/luo_internal.h | 5 +- 3 files changed, 77 insertions(+), 83 deletions(-) diff --git a/include/linux/kho/abi/luo.h b/include/linux/kho/abi/luo.h index a643193a379c..59677dc9cdd1 100644 --- a/include/linux/kho/abi/luo.h +++ b/include/linux/kho/abi/luo.h @@ -56,8 +56,8 @@ * * - struct luo_session_ser: * Metadata for a single session, including its name and a physical po= inter - * to another preserved memory block containing an array of - * `struct luo_file_ser` for all files in that session. + * to the first `struct luo_block_header_ser` for all files in that se= ssion. + * Multiple blocks are linked via the `next` field in the header. * * - struct luo_file_ser: * Metadata for a single preserved file. Contains the `compatible` str= ing to @@ -85,7 +85,7 @@ */ #define LUO_FDT_SIZE PAGE_SIZE #define LUO_FDT_KHO_ENTRY_NAME "LUO" -#define LUO_FDT_COMPATIBLE "luo-v3" +#define LUO_FDT_COMPATIBLE "luo-v4" #define LUO_FDT_ABI_HEADER "luo-abi-header" =20 /** @@ -138,9 +138,10 @@ struct luo_file_ser { =20 /** * struct luo_file_set_ser - Represents the serialized metadata for file s= et - * @files: The physical address of a contiguous memory block that holds - * the serialized state of files (array of luo_file_ser) in this= file - * set. + * @files: The physical address of the first `struct luo_block_header_se= r`. + * This structure is the header for a block of memory containing + * an array of `struct luo_file_ser` entries. Multiple blocks are + * linked via the `next` field in the header. * @count: The total number of files that were part of this session duri= ng * serialization. Used for iteration and validation during * restoration. diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c index a2510563469a..e2ab7834963d 100644 --- a/kernel/liveupdate/luo_file.c +++ b/kernel/liveupdate/luo_file.c @@ -118,11 +118,6 @@ static LIST_HEAD(luo_file_handler_list); /* Keep track of files being preserved by LUO */ static DEFINE_XARRAY(luo_preserved_files); =20 -/* 2 4K pages, give space for 128 files per file_set */ -#define LUO_FILE_PGCNT 2ul -#define LUO_FILE_MAX \ - ((LUO_FILE_PGCNT << PAGE_SHIFT) / sizeof(struct luo_file_ser)) - /** * struct luo_file - Represents a single preserved file instance. * @fh: Pointer to the &struct liveupdate_file_handler that man= ages @@ -174,39 +169,6 @@ struct luo_file { u64 token; }; =20 -static int luo_alloc_files_mem(struct luo_file_set *file_set) -{ - size_t size; - void *mem; - - if (file_set->files) - return 0; - - WARN_ON_ONCE(file_set->count); - - size =3D LUO_FILE_PGCNT << PAGE_SHIFT; - mem =3D kho_alloc_preserve(size); - if (IS_ERR(mem)) - return PTR_ERR(mem); - - file_set->files =3D mem; - - return 0; -} - -static void luo_free_files_mem(struct luo_file_set *file_set) -{ - /* If file_set has files, no need to free preservation memory */ - if (file_set->count) - return; - - if (!file_set->files) - return; - - kho_unpreserve_free(file_set->files); - file_set->files =3D NULL; -} - static unsigned long luo_get_id(struct liveupdate_file_handler *fh, struct file *file) { @@ -276,16 +238,15 @@ int luo_preserve_file(struct luo_file_set *file_set, = u64 token, int fd) if (luo_token_is_used(file_set, token)) return -EEXIST; =20 - if (file_set->count =3D=3D LUO_FILE_MAX) - return -ENOSPC; + err =3D luo_block_grow(&file_set->block_set, file_set->count); + if (err) + return err; =20 file =3D fget(fd); - if (!file) - return -EBADF; - - err =3D luo_alloc_files_mem(file_set); - if (err) - goto err_fput; + if (!file) { + err =3D -EBADF; + goto err_shrink; + } =20 err =3D -ENOENT; down_read(&luo_register_rwlock); @@ -300,7 +261,7 @@ int luo_preserve_file(struct luo_file_set *file_set, u6= 4 token, int fd) =20 /* err is still -ENOENT if no handler was found */ if (err) - goto err_free_files_mem; + goto err_fput; =20 err =3D xa_insert(&luo_preserved_files, luo_get_id(fh, file), file, GFP_KERNEL); @@ -343,10 +304,10 @@ int luo_preserve_file(struct luo_file_set *file_set, = u64 token, int fd) xa_erase(&luo_preserved_files, luo_get_id(fh, file)); err_module_put: module_put(fh->ops->owner); -err_free_files_mem: - luo_free_files_mem(file_set); err_fput: fput(file); +err_shrink: + luo_block_shrink(&file_set->block_set, file_set->count); =20 return err; } @@ -391,13 +352,14 @@ void luo_file_unpreserve_files(struct luo_file_set *f= ile_set) luo_get_id(luo_file->fh, luo_file->file)); list_del(&luo_file->list); file_set->count--; + luo_block_shrink(&file_set->block_set, file_set->count); =20 fput(luo_file->file); mutex_destroy(&luo_file->mutex); kfree(luo_file); } =20 - luo_free_files_mem(file_set); + luo_block_destroy(&file_set->block_set); } =20 static int luo_file_freeze_one(struct luo_file_set *file_set, @@ -453,7 +415,7 @@ static void __luo_file_unfreeze(struct luo_file_set *fi= le_set, luo_file_unfreeze_one(file_set, luo_file); } =20 - memset(file_set->files, 0, LUO_FILE_PGCNT << PAGE_SHIFT); + luo_block_set_clear(&file_set->block_set); } =20 /** @@ -492,19 +454,23 @@ static void __luo_file_unfreeze(struct luo_file_set *= file_set, int luo_file_freeze(struct luo_file_set *file_set, struct luo_file_set_ser *file_set_ser) { - struct luo_file_ser *file_ser =3D file_set->files; struct luo_file *luo_file; + struct luo_block_it it; int err; - int i; =20 if (!file_set->count) return 0; =20 - if (WARN_ON(!file_ser)) - return -EINVAL; + luo_block_it_init(&it, &file_set->block_set); =20 - i =3D 0; list_for_each_entry(luo_file, &file_set->files_list, list) { + struct luo_file_ser *file_ser =3D luo_block_it_next(&it); + + if (!file_ser) { + err =3D -ENOSPC; + goto err_unfreeze; + } + err =3D luo_file_freeze_one(file_set, luo_file); if (err < 0) { pr_warn("Freeze failed for token[%#0llx] handler[%s] err[%pe]\n", @@ -513,16 +479,21 @@ int luo_file_freeze(struct luo_file_set *file_set, goto err_unfreeze; } =20 - strscpy(file_ser[i].compatible, luo_file->fh->compatible, - sizeof(file_ser[i].compatible)); - file_ser[i].data =3D luo_file->serialized_data; - file_ser[i].token =3D luo_file->token; - i++; + strscpy(file_ser->compatible, luo_file->fh->compatible, + sizeof(file_ser->compatible)); + file_ser->data =3D luo_file->serialized_data; + file_ser->token =3D luo_file->token; } + luo_block_it_finalize(&it); =20 file_set_ser->count =3D file_set->count; - if (file_set->files) - file_set_ser->files =3D virt_to_phys(file_set->files); + if (!list_empty(&file_set->block_set.blocks)) { + struct luo_block *block; + + block =3D list_first_entry(&file_set->block_set.blocks, + struct luo_block, list); + file_set_ser->files =3D virt_to_phys(block->ser); + } =20 return 0; =20 @@ -740,14 +711,12 @@ int luo_file_finish(struct luo_file_set *file_set) } list_del(&luo_file->list); file_set->count--; + luo_block_shrink(&file_set->block_set, file_set->count); mutex_destroy(&luo_file->mutex); kfree(luo_file); } =20 - if (file_set->files) { - kho_restore_free(file_set->files); - file_set->files =3D NULL; - } + luo_block_destroy(&file_set->block_set); =20 return 0; } @@ -821,16 +790,18 @@ int luo_file_deserialize(struct luo_file_set *file_se= t, struct luo_file_set_ser *file_set_ser) { struct luo_file_ser *file_ser; + struct luo_block_it it; int err; - u64 i; =20 if (!file_set_ser->files) { WARN_ON(file_set_ser->count); return 0; } =20 - file_set->count =3D file_set_ser->count; - file_set->files =3D phys_to_virt(file_set_ser->files); + file_set->count =3D 0; + err =3D luo_block_restore(&file_set->block_set, file_set_ser->files); + if (err) + return err; =20 /* * Note on error handling: @@ -847,25 +818,48 @@ int luo_file_deserialize(struct luo_file_set *file_se= t, * userspace to detect the failure and trigger a reboot, which will * reliably reset devices and reclaim memory. */ - file_ser =3D file_set->files; - for (i =3D 0; i < file_set->count; i++) { - err =3D luo_file_deserialize_one(file_set, &file_ser[i]); + luo_block_it_init(&it, &file_set->block_set); + while ((file_ser =3D luo_block_it_read(&it))) { + err =3D luo_file_deserialize_one(file_set, file_ser); if (err) - return err; + goto err_destroy_blocks; + file_set->count++; + } + + if (file_set->count !=3D file_set_ser->count) { + pr_warn("File count mismatch: expected %llu, found %ld\n", + file_set_ser->count, file_set->count); } =20 return 0; + +err_destroy_blocks: + while (!list_empty(&file_set->files_list)) { + struct luo_file *luo_file; + + luo_file =3D list_first_entry(&file_set->files_list, + struct luo_file, list); + list_del(&luo_file->list); + module_put(luo_file->fh->ops->owner); + mutex_destroy(&luo_file->mutex); + kfree(luo_file); + } + file_set->count =3D 0; + luo_block_destroy(&file_set->block_set); + return err; } =20 void luo_file_set_init(struct luo_file_set *file_set) { INIT_LIST_HEAD(&file_set->files_list); + luo_block_set_init(&file_set->block_set, sizeof(struct luo_file_ser)); } =20 void luo_file_set_destroy(struct luo_file_set *file_set) { WARN_ON(file_set->count); WARN_ON(!list_empty(&file_set->files_list)); + WARN_ON(!list_empty(&file_set->block_set.blocks)); } =20 /** diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_inter= nal.h index 090078ad771c..901483e6e4ad 100644 --- a/kernel/liveupdate/luo_internal.h +++ b/kernel/liveupdate/luo_internal.h @@ -89,14 +89,13 @@ struct luo_block_it { * struct luo_file_set - A set of files that belong to the same sessions. * @files_list: An ordered list of files associated with this session, it = is * ordered by preservation time. - * @files: The physically contiguous memory block that holds the seri= alized - * state of files. + * @block_set: The set of serialization blocks. * @count: A counter tracking the number of files currently stored in= the * @files_list for this session. */ struct luo_file_set { struct list_head files_list; - struct luo_file_ser *files; + struct luo_block_set block_set; long count; }; =20 --=20 2.53.0 From nobody Fri Jun 12 12:49:01 2026 Received: from mail-qt1-f179.google.com (mail-qt1-f179.google.com [209.85.160.179]) (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 F3CA03D3009 for ; Thu, 14 May 2026 22:26:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797608; cv=none; b=QlzwgmYlOTi/Z0YCh/37uNYwL6xj6eRzHm+SLi/b45MyclbgFWYNW0H5lLs3mQSLs95+1lRpXWvS5aWnrfryG7k+fLwKa4HR3UPgpaWMldDwfDiNfvbTPNNXKRIqerutEEW31KtTGqVWyeIwTuUEUve58pmcYadSof6xKJbG4kg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797608; c=relaxed/simple; bh=OWTM90yu1niJ/qeDOpSCZ+9Fa6JVVNlhhw5OiEwaYdE=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VJ/NC8ytbQYgRZOP5QePdGAoE0fvdDu1dP2X5XaHsSfZKLbpf+8fBwwS9HGfmMUz4eH+FC8JV6RE9uxYqz9skB4IRyoxnKbgF5nMNfwql2ar6+/ksmUDKLQP/UggDsURh7rlHPxaEAKj1AWLcoKRygzaHZNA7aSNVrFzthuyslA= 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=DMRc+JFo; arc=none smtp.client-ip=209.85.160.179 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="DMRc+JFo" Received: by mail-qt1-f179.google.com with SMTP id d75a77b69052e-50d75bfb259so56814161cf.1 for ; Thu, 14 May 2026 15:26:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1778797606; x=1779402406; 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=14TtfdaLNy/StuYSb6NEiZW+KT+gZJT0aVK824S/d4k=; b=DMRc+JFoX0z8R0e7u9OLl64WFd/ny8Fj3rlQryr5ZL72n1WQzPGeHnvY0VPRpqWe3O uc3YX5eXuiF6qCuFORNOtNS2tjUu8ips/OzCq4xObshcNDWEopuj+4X5yakMOHgpeuNy zzHwNEmLfyG1nI7Jk+lHhHUbSkVNOGrHMI6NaBzZeV7ewFgWFip4mtsnHVqADqK7jG+c ytn11NEqfJojdwo7GZveKyYnG4kIbvNiL3qhBODqhiYrq3qDwxI0PX4xnszdBurc+R4K lZAmihYZKmIEuHHMtoJ0633qKX7qJpvPmxR1wFEUxlCN+npBd5+tArC+kKG6EfTzhfMt Qdmg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778797606; x=1779402406; 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=14TtfdaLNy/StuYSb6NEiZW+KT+gZJT0aVK824S/d4k=; b=VmJzKMOQ6+Mih0wRv7YFHYvjj4EZLb/P26o8QwntH6g3Y52Y3O3ofCsKE3ejJ2xSF7 owPOykt/0i+letVNmewECBHhDArL5rx0mPKFImXE04Yz25dNK1ljKgtcoggnUCG2VTEq OKdj1fJGqceuidwAPMZhys2AFohxagiUne6TD2ZAj9Vuu9H8SvbYhzHpJQW/RK2mC+Re cMa5yAogMRoeKl31W8uyQhQeEudp5uYZd5+iUcl7S3au4mYGA8vqOQvmp6BGvepkcj9v QISn38t5zLWJkwwH8Fzx6wNUKJjtY/zbEHXLHuvAB3xvt0dvXBlJi15gtMWKvBcLPUNX fDpw== X-Forwarded-Encrypted: i=1; AFNElJ9g5QIAMw+iY5KU69xVD5DYyHVNdNNTjy/1YfnJwsSpc4XzKk8euEJjtziKVO3ZRBDFCnYTUIoSm2/dFZ8=@vger.kernel.org X-Gm-Message-State: AOJu0YxjzU1rI9n5gbS8Ncb/y5Ni/ESUj8BU86o+7/2B8OiD804TxacG vjrLMWNebOFBkiI0oTnB5Ln8cVSNFDK+ZdM2uMF90SJwFwjir12gHCONVuXHQxyASpA= X-Gm-Gg: Acq92OFlvlKT7r/2hnmGMaRRSgouRGpljBeGSzIHkc0+1ZBvTBHYVwdgQ8WjyHD4cdh kzCd7B86muVS2qYYgIES2GKJMZeGRWpyhbqWJjJ+dOWAPQ8O1iH9imB+e/WtfW5nuUfhVD3Dih2 3O53LjvO7F7QICk4jyI9q14Oz3ZCJjLRTkhvO2Kklms9G2ClnnZHzWqbHn51m0p8aMrtaW91rco 2MWfYR0+PA2ZljP0FrCPS+3I4E5giT1dYpDIkx5Dtq4E3MFPXOphyAZecc1iWxa3BU2uKfiJf+o 9b8nBYUYoUBLQ7fdhIySqQR+e71PCV5jqYnlN65uuAMIjfzAi8TpVVXcYTi7kS9tW9V8y3E67Jg Zkjmk8UeA/F2pE6s+w/x625zrqRqvFHFmioNNfMcaYKf06qCZK00XMzuHYx/NevhAi8Cby3vPpP /cV09TWbn8XDODh+nRh8RIUAJ7ng1zVE83sBJ1G40GHnIDCvKLKTE3iSFgBNy/aQ== X-Received: by 2002:a05:622a:59cc:b0:50d:7406:8f05 with SMTP id d75a77b69052e-5165a0010a3mr18527381cf.9.1778797605925; Thu, 14 May 2026 15:26:45 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-516456ba92fsm28671901cf.9.2026.05.14.15.26.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 15:26:45 -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, linux-kernel@vger.kernel.org, corbet@lwn.net, pasha.tatashin@soleen.com, dmatlack@google.com, kexec@lists.infradead.org, pratyush@kernel.org, skhawaja@google.com, graf@amazon.com Subject: [PATCH v2 08/10] selftests/liveupdate: Test session and file limit removal Date: Thu, 14 May 2026 22:26:26 +0000 Message-ID: <20260514222628.931312-9-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260514222628.931312-1-pasha.tatashin@soleen.com> References: <20260514222628.931312-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" With the removal of static limits on the number of sessions and files per session, the orchestrator now uses dynamic allocation. Add new test cases to verify that the system can handle a large number of sessions and files. These tests ensure that the dynamic block allocation and reuse logic for session metadata and outgoing files work correctly beyond the previous static limits. Signed-off-by: Pasha Tatashin Acked-by: Mike Rapoport (Microsoft) --- .../testing/selftests/liveupdate/liveupdate.c | 75 +++++++++++++++++++ .../selftests/liveupdate/luo_test_utils.c | 24 ++++++ .../selftests/liveupdate/luo_test_utils.h | 2 + 3 files changed, 101 insertions(+) diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testin= g/selftests/liveupdate/liveupdate.c index c7d94b9181e1..502fb3567e38 100644 --- a/tools/testing/selftests/liveupdate/liveupdate.c +++ b/tools/testing/selftests/liveupdate/liveupdate.c @@ -26,6 +26,7 @@ =20 #include =20 +#include "luo_test_utils.h" #include "../kselftest.h" #include "../kselftest_harness.h" =20 @@ -499,4 +500,78 @@ TEST_F(liveupdate_device, get_session_name_max_length) ASSERT_EQ(close(session_fd), 0); } =20 +/* + * Test Case: Manage Many Sessions + * + * Verifies that a large number of sessions can be created and then + * destroyed during normal system operation. This specifically tests the + * dynamic block allocation and reuse logic for session metadata management + * without preserving any files. + */ +TEST_F(liveupdate_device, preserve_many_sessions) +{ +#define MANY_SESSIONS 2000 + int session_fds[MANY_SESSIONS]; + int ret, i; + + self->fd1 =3D open(LIVEUPDATE_DEV, O_RDWR); + if (self->fd1 < 0 && errno =3D=3D ENOENT) + SKIP(return, "%s does not exist", LIVEUPDATE_DEV); + ASSERT_GE(self->fd1, 0); + + ret =3D luo_ensure_nofile_limit(MANY_SESSIONS); + if (ret =3D=3D -EPERM) + SKIP(return, "Insufficient privileges to set RLIMIT_NOFILE"); + ASSERT_EQ(ret, 0); + + for (i =3D 0; i < MANY_SESSIONS; i++) { + char name[64]; + + snprintf(name, sizeof(name), "many-session-%d", i); + session_fds[i] =3D create_session(self->fd1, name); + ASSERT_GE(session_fds[i], 0); + } + + for (i =3D 0; i < MANY_SESSIONS; i++) + ASSERT_EQ(close(session_fds[i]), 0); +} + +/* + * Test Case: Preserve Many Files + * + * Verifies that a large number of files can be preserved in a single sess= ion + * and then destroyed during normal system operation. This tests the dynam= ic + * block allocation and management for outgoing files. + */ +TEST_F(liveupdate_device, preserve_many_files) +{ +#define MANY_FILES 500 + int mem_fds[MANY_FILES]; + int session_fd, ret, i; + + self->fd1 =3D open(LIVEUPDATE_DEV, O_RDWR); + if (self->fd1 < 0 && errno =3D=3D ENOENT) + SKIP(return, "%s does not exist", LIVEUPDATE_DEV); + ASSERT_GE(self->fd1, 0); + + session_fd =3D create_session(self->fd1, "many-files-test"); + ASSERT_GE(session_fd, 0); + + ret =3D luo_ensure_nofile_limit(MANY_FILES + 10); + if (ret =3D=3D -EPERM) + SKIP(return, "Insufficient privileges to set RLIMIT_NOFILE"); + ASSERT_EQ(ret, 0); + + for (i =3D 0; i < MANY_FILES; i++) { + mem_fds[i] =3D memfd_create("test-memfd", 0); + ASSERT_GE(mem_fds[i], 0); + ASSERT_EQ(preserve_fd(session_fd, mem_fds[i], i), 0); + } + + for (i =3D 0; i < MANY_FILES; i++) + ASSERT_EQ(close(mem_fds[i]), 0); + + ASSERT_EQ(close(session_fd), 0); +} + TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/liveupdate/luo_test_utils.c b/tools/te= sting/selftests/liveupdate/luo_test_utils.c index 3c8721c505df..333a3530051b 100644 --- a/tools/testing/selftests/liveupdate/luo_test_utils.c +++ b/tools/testing/selftests/liveupdate/luo_test_utils.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,29 @@ int luo_open_device(void) return open(LUO_DEVICE, O_RDWR); } =20 +int luo_ensure_nofile_limit(long min_limit) +{ + struct rlimit hl; + + /* Allow to extra files to be used by test itself */ + min_limit +=3D 32; + + if (getrlimit(RLIMIT_NOFILE, &hl) < 0) + return -errno; + + if (hl.rlim_cur >=3D min_limit) + return 0; + + hl.rlim_cur =3D min_limit; + if (hl.rlim_cur > hl.rlim_max) + hl.rlim_max =3D hl.rlim_cur; + + if (setrlimit(RLIMIT_NOFILE, &hl) < 0) + return -errno; + + return 0; +} + int luo_create_session(int luo_fd, const char *name) { struct liveupdate_ioctl_create_session arg =3D { .size =3D sizeof(arg) }; diff --git a/tools/testing/selftests/liveupdate/luo_test_utils.h b/tools/te= sting/selftests/liveupdate/luo_test_utils.h index 90099bf49577..6a0d85386613 100644 --- a/tools/testing/selftests/liveupdate/luo_test_utils.h +++ b/tools/testing/selftests/liveupdate/luo_test_utils.h @@ -26,6 +26,8 @@ int luo_create_session(int luo_fd, const char *name); int luo_retrieve_session(int luo_fd, const char *name); int luo_session_finish(int session_fd); =20 +int luo_ensure_nofile_limit(long min_limit); + int create_and_preserve_memfd(int session_fd, int token, const char *data); int restore_and_verify_memfd(int session_fd, int token, const char *expect= ed_data); =20 --=20 2.53.0 From nobody Fri Jun 12 12:49:01 2026 Received: from mail-qt1-f177.google.com (mail-qt1-f177.google.com [209.85.160.177]) (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 D0BF13D3016 for ; Thu, 14 May 2026 22:26:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797610; cv=none; b=lYpgAsjFpjN1hNpalDjvvhvfU9TWyQ6xMR6fGIud21o6/HOEt139JFMc8SZ/kseIvuO5xKdx+jS4N6WNNC0XGJ6ZyT0KIc++EF8yFwitPegYNigpe1ms0U+WTclAM0oM6WF76mQDUf+yosfI70e9MyUq9KXGXhhT65SdT9K7aeM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797610; c=relaxed/simple; bh=WTBJUEEMM7K7ob4xZeJB7qcdaYVjvJmNAEO/PdJgFis=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZtPWrWauwAViSx43hVpbG4CJOCBSHIALr+5zx1cti36p+w0/o3oyqPCJ/A8Q0t6CZnXvLANpo86uD3SCDIhoC+K5+Ao5sTcvwTOlktIN2sflIBnJRHo2MPXlhwvfd+fX7OsxthFOTgG2GeNH0/ksIr8TiEs8cJlb4g7i+JibbdQ= 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=G9qChUUP; arc=none smtp.client-ip=209.85.160.177 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="G9qChUUP" Received: by mail-qt1-f177.google.com with SMTP id d75a77b69052e-50d75bfb259so56814421cf.1 for ; Thu, 14 May 2026 15:26:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1778797608; x=1779402408; 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=z+TDIuCJZXpxQehieZyZSUnjXJ4NsIJyCoOgTpI/vhI=; b=G9qChUUP2pceoS8Sp5qeM4P+165yrFC0mNQUOYQuU1NZDfsSZr5IXR5k5UiaAthqOi NU/vILiRhPsYf2/U4IhdnfJUrwH02oAwNNlLTVW+CCDxVHQ/Tf5kKB6uNErGNHAInmDI BCEWU0I27zaMcRxI4Edl5RY9vHn4ButA2KIzKop5KjzRQiYKfC7kOw0/mEyYpdvU99WT WWT/VFcRytvUIXYdS/6MjNsR1qpXX0dCTL/Ar1GDi0br+AZGt927BBriBFv0NSX2WS1U TlkVyNxMqC146SdKTCKoz+1aX/uYUQXEenARywIxDPwDzCMsQRQGPuZB5Yr4tvccXDPa TnQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778797608; x=1779402408; 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=z+TDIuCJZXpxQehieZyZSUnjXJ4NsIJyCoOgTpI/vhI=; b=aA+HFml5TVE4W7oJ/Q/52fqO06ORm4YvSNVMMLp02mRSPiur4MoBNMs0CcGsoAAi1F IMVGmtVjmuGTktuiDZpNHj38GCzDB6RGBKRE90RyI7wOeJDLwpwIdo+fLuj/fGfzKepu NDfL3JNb7XOj/4k4ND4dPduDmm1DfHY/437MP7CFy6ah1MWscusrJroh6Hs+pZc4WIJk sVzJ8otmeS9uldLcrNZ7sgW+THnCF1Cwy9dFIcbcCQNIlyCAzpHyNpM0FkZmBRsuN+ga 7i+vZiDOi1NUNSXfCtHuMCnL/NZLbEOxmSjd27bxhMghpCc+SnAZZfK+kf14FhVJQoDU 8PoA== X-Forwarded-Encrypted: i=1; AFNElJ/fYcSW3kAZJQFq8XQIN1wCmdIbz/VVX/o7wbgZwfN7eqLz3TMie25Y0h9G5l1dtvU8JuYfj0RpoCKoqls=@vger.kernel.org X-Gm-Message-State: AOJu0YwITyMmpI/ff9H4dtspeaQBNPxUaHRU4nC7u2iM6UJrMwZ4Ahxg N1iJ5GM+dN+pkc+6RrYIxPwC85PTXbwaqyfO8oSrrJVxi/eEsea2gGkqRVSLgk0nBMU= X-Gm-Gg: Acq92OGi0GQPwgEWsbsQwhKALc6V9+WzYKX2kU1SrcvH2PHXapGsTzq/LJwCySCAmbw QIzZFW+mLah7lWQmHuhHX6ChlEcAv7brFc34QeNq3GUBIAEQUz1Hxo4RAEVsLlu2SaBoPeFx8Xd 4rsmdhN2Zogzqi6ZUg+Dd6+qkuTQYUNJV4r0fPsioDCJLobnKJnuVizxmRImrGM+Fr+C9GyM/MA iB+i1jNgoYur5Bhv5bdeDA566z7Efj7LsEzPZ7IBzvXxAwCyU7wp73YTA1UDX8AurwQCipxAPp9 q5KE+DFG8Omk8HLg17Hg7IZEfROZpufgvcSc07j+bdBvqL4vTRoNrqYFPt4CC64LkQONR/8zcPc yUEuk1qgB8dyeu/GbOH8jgFucpNocmKPSLykb9Pujhk5bS2wS8Dyfc2e5fk6wRJ82JDYqsTdTxt zUlS1m5mCtqoPvVN9D9aadMoCay8jvEyxbZr84/VNZtlI8Kti+5a4= X-Received: by 2002:a05:622a:15c5:b0:50d:a8f5:1c02 with SMTP id d75a77b69052e-5165a219a43mr19531391cf.41.1778797607915; Thu, 14 May 2026 15:26:47 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-516456ba92fsm28671901cf.9.2026.05.14.15.26.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 15:26:46 -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, linux-kernel@vger.kernel.org, corbet@lwn.net, pasha.tatashin@soleen.com, dmatlack@google.com, kexec@lists.infradead.org, pratyush@kernel.org, skhawaja@google.com, graf@amazon.com Subject: [PATCH v2 09/10] selftests/liveupdate: Add stress-sessions kexec test Date: Thu, 14 May 2026 22:26:27 +0000 Message-ID: <20260514222628.931312-10-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260514222628.931312-1-pasha.tatashin@soleen.com> References: <20260514222628.931312-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" Add a new test that creates 2000 LUO sessions before a kexec reboot and verifies their presence after the reboot. This ensures that the linked-block serialization mechanism works correctly for a large number of sessions. Signed-off-by: Pasha Tatashin Acked-by: Mike Rapoport (Microsoft) --- tools/testing/selftests/liveupdate/Makefile | 1 + .../liveupdate/luo_stress_sessions.c | 102 ++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 tools/testing/selftests/liveupdate/luo_stress_sessions.c diff --git a/tools/testing/selftests/liveupdate/Makefile b/tools/testing/se= lftests/liveupdate/Makefile index 080754787ede..ed7534468386 100644 --- a/tools/testing/selftests/liveupdate/Makefile +++ b/tools/testing/selftests/liveupdate/Makefile @@ -6,6 +6,7 @@ TEST_GEN_PROGS +=3D liveupdate =20 TEST_GEN_PROGS_EXTENDED +=3D luo_kexec_simple TEST_GEN_PROGS_EXTENDED +=3D luo_multi_session +TEST_GEN_PROGS_EXTENDED +=3D luo_stress_sessions =20 TEST_FILES +=3D do_kexec.sh =20 diff --git a/tools/testing/selftests/liveupdate/luo_stress_sessions.c b/too= ls/testing/selftests/liveupdate/luo_stress_sessions.c new file mode 100644 index 000000000000..f201b1839d1d --- /dev/null +++ b/tools/testing/selftests/liveupdate/luo_stress_sessions.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (c) 2026, Google LLC. + * Pasha Tatashin + * + * Validate that LUO can handle a large number of sessions across a kexec + * reboot. + */ + +#include +#include +#include "luo_test_utils.h" + +#define NUM_SESSIONS 2000 +#define STATE_SESSION_NAME "kexec_many_state" +#define STATE_MEMFD_TOKEN 999 + +/* Stage 1: Executed before the kexec reboot. */ +static void run_stage_1(int luo_fd) +{ + int ret, i; + + ksft_print_msg("[STAGE 1] Increasing ulimit for open files...\n"); + ret =3D luo_ensure_nofile_limit(NUM_SESSIONS); + if (ret =3D=3D -EPERM) + ksft_exit_skip("Insufficient privileges to set RLIMIT_NOFILE\n"); + if (ret < 0) + ksft_exit_fail_msg("luo_ensure_nofile_limit failed: %s\n", strerror(-ret= )); + + ksft_print_msg("[STAGE 1] Creating state file for next stage (2)...\n"); + create_state_file(luo_fd, STATE_SESSION_NAME, STATE_MEMFD_TOKEN, 2); + + ksft_print_msg("[STAGE 1] Creating %d sessions...\n", NUM_SESSIONS); + + for (i =3D 0; i < NUM_SESSIONS; i++) { + char name[LIVEUPDATE_SESSION_NAME_LENGTH]; + int s_fd; + + snprintf(name, sizeof(name), "many-test-%d", i); + s_fd =3D luo_create_session(luo_fd, name); + if (s_fd < 0) { + fail_exit("luo_create_session for '%s' at index %d", + name, i); + } + } + + ksft_print_msg("[STAGE 1] Successfully created %d sessions.\n", + NUM_SESSIONS); + + close(luo_fd); + daemonize_and_wait(); +} + +/* Stage 2: Executed after the kexec reboot. */ +static void run_stage_2(int luo_fd, int state_session_fd) +{ + int i, stage; + + ksft_print_msg("[STAGE 2] Starting post-kexec verification...\n"); + + restore_and_read_stage(state_session_fd, STATE_MEMFD_TOKEN, &stage); + if (stage !=3D 2) { + fail_exit("Expected stage 2, but state file contains %d", + stage); + } + + ksft_print_msg("[STAGE 2] Retrieving and finishing %d sessions...\n", + NUM_SESSIONS); + + for (i =3D 0; i < NUM_SESSIONS; i++) { + char name[LIVEUPDATE_SESSION_NAME_LENGTH]; + int s_fd; + + snprintf(name, sizeof(name), "many-test-%d", i); + s_fd =3D luo_retrieve_session(luo_fd, name); + if (s_fd < 0) { + fail_exit("luo_retrieve_session for '%s' at index %d", + name, i); + } + + if (luo_session_finish(s_fd) < 0) { + fail_exit("luo_session_finish for '%s' at index %d", + name, i); + } + close(s_fd); + } + + ksft_print_msg("[STAGE 2] Finalizing state session...\n"); + if (luo_session_finish(state_session_fd) < 0) + fail_exit("luo_session_finish for state session"); + close(state_session_fd); + + ksft_print_msg("\n--- MANY-SESSIONS KEXEC TEST PASSED (%d sessions) ---\n= ", + NUM_SESSIONS); +} + +int main(int argc, char *argv[]) +{ + return luo_test(argc, argv, STATE_SESSION_NAME, + run_stage_1, run_stage_2); +} --=20 2.53.0 From nobody Fri Jun 12 12:49:01 2026 Received: from mail-qk1-f182.google.com (mail-qk1-f182.google.com [209.85.222.182]) (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 5B43B3D5652 for ; Thu, 14 May 2026 22:26:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797612; cv=none; b=cAb7yCyxQsAmgCeSTxv6HLtHPrQSLK/0KU0ikEqlJYqjRq85qizuzUpMXUYt+DNizEo80MNzumsfLnsahdq/nUHy0W7Le/LciWOIlGeKn9+M/kJSa04dmozKxlQn2mOzfXK6UfbV40uNWsXZA13ji+xI7g/byLvPLFAxJOeIOXE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778797612; c=relaxed/simple; bh=piyhP1WlFEDEC4wjfdVtJ+Ed5dSs0hL3Qd4yjf73GtU=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hS63sfQ3zBBFKY/36MZZ8EtOsaNEUj3akIBFDqSAHtqeqZiK6Ms4CJ+IwYPPN+h8TYF7kg65wSx7/oWaBKerVxLs1sIP/IT9+DOkayc+NMmbG94o4KaqfPTiY96QEL0u/4o7ieHbTPFv0YccTbdsb1kZwuOzjJnhBpzRHqUoWhs= 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=HTPqamg3; arc=none smtp.client-ip=209.85.222.182 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="HTPqamg3" Received: by mail-qk1-f182.google.com with SMTP id af79cd13be357-9118b952e2bso79368485a.0 for ; Thu, 14 May 2026 15:26:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1778797609; x=1779402409; 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=ZIrwM3YYxVlDXZ9UztplnfGrca1M/xZmJnShxYpBntg=; b=HTPqamg3t9ttbBJWAWze/KY4l+Pve/WCBXBEuAuvLPc75zBB9/XtUzGR9tDWdoovFS Ot20/0G8g/QPZXg/l7q0CH2XGfmrDuMT1DeGgSDd/Lw0rtWSZVX/twkL+2etXzv5RXPU +njr4lzFRxKb99hA3HsJBXFdQH/6+fvMXx88gQczzQahFIQ1HEsiQDEQxHWnS9pVMlLY nOo0nk9gnPNqioDNLYXGMUTAsifAsgzaWXR0ybEsxwN3cEjb7zBIlSKRPT80ozmvEbUh 7Irq5mIbgLhk3d5TGd/f3twRGD4up67hmFEQvHsoMWrUqZwK1pfo5QixRhjXPPRZGobA oEUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778797609; x=1779402409; 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=ZIrwM3YYxVlDXZ9UztplnfGrca1M/xZmJnShxYpBntg=; b=SvrWATll5OorRRwYuuFXe8CExV185B1aYxcvK7Yov1IbvC11JLuuCXcJZCmXW2Kioe GIWiE+ufAy9Ro791amVWnjiZbsfOLYYF75x5P7nCwg3EUxpba+TL+JUobpbMKdPgwGYo xYVIwpA5GMYduIquQSu5FLiErb/uNYbuw+tKfa/0XwZB5A8lmsaPWBwC7bw6ZQOyueMw yI71wkkXaAmGSh7Nn8sMTm6ZlwWNQpV8cQsQK+x156qc6o69Og5YZWPEj4mz7Rj2uNmP sOedVW9uSzMqniydoMKfU4vCHbhjQW2EyRqAGchbaDyJhRIt7vwN5ZL4tZoRV+BnPCsm OIGg== X-Forwarded-Encrypted: i=1; AFNElJ/EObhu9sUJKhdCRBNBHIY8e3GuGkBlEXzo7gX1HUInSHNDTf4AhwY1mC6ZfjQKzlF7GJ6BBnx2EHBEHkI=@vger.kernel.org X-Gm-Message-State: AOJu0YySEyLAg3F1pdrV+cZr0ysjRvvnu4foYkOqEano3XIbTRnVSQRD SLCKhF/7FyN2gQUAifcCrQYEz0NcVL1URp8EqmJvDEleBmZnngY2yiMwsLuTwg2gZ7Y= X-Gm-Gg: Acq92OGGqTEQCG1+V2iKL2bQELWVEHQ3zpLnL/PTopT5zS2Gi0Hr/enxbnUY3PBi962 21Oi0QnN4ZSaW380wWFmROrsjINQhUPPywrmirrhRq8eEqfasueFHHv9Lk2sdWHqVvNcg47cRji TWjMA4WN6/58POIMwprrK60iheK3qIXpjZhRjDh/9Z12W5WEUDotfwRp2NlQdqAZDAroeK//2AD RWmiGcXbi4DgS6NIxYHVVDLsxYHgBZW5CpfpmJ075kQglQt+CmgJTARx0OW7mDuYxm+X4MonQH0 gCycFP6v0cyiCAoKc3iF1XhzzEFFBcKLgLlk0M6uUMKo7NMfEhYnkoGbKMPkylhfuQqDTFmgw/s ALR+E9BeDyI30Vn9NxH/3Z11y1pxKU3dwixUdsSc5L9f2Uf1HaOz308GEDLEl8DOzx7c12lBSft gcNfv9MsEffET8ZVGdhaen8yg/IrDoUge7mAtB/CcUlw7zEVufRzE= X-Received: by 2002:a05:622a:2445:b0:4f1:ab79:fb18 with SMTP id d75a77b69052e-5165a03e931mr18328421cf.25.1778797609141; Thu, 14 May 2026 15:26:49 -0700 (PDT) Received: from plex ([71.181.43.54]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-516456ba92fsm28671901cf.9.2026.05.14.15.26.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2026 15:26: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, linux-kernel@vger.kernel.org, corbet@lwn.net, pasha.tatashin@soleen.com, dmatlack@google.com, kexec@lists.infradead.org, pratyush@kernel.org, skhawaja@google.com, graf@amazon.com Subject: [PATCH v2 10/10] selftests/liveupdate: Add stress-files kexec test Date: Thu, 14 May 2026 22:26:28 +0000 Message-ID: <20260514222628.931312-11-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260514222628.931312-1-pasha.tatashin@soleen.com> References: <20260514222628.931312-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" Add a new luo_stress_files kexec test that verifies preserving and retrieving 500 files across a kexec reboot. Signed-off-by: Pasha Tatashin Reviewed-by: Pratyush Yadav (Google) Acked-by: Mike Rapoport (Microsoft) --- tools/testing/selftests/liveupdate/Makefile | 1 + .../selftests/liveupdate/luo_stress_files.c | 101 ++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 tools/testing/selftests/liveupdate/luo_stress_files.c diff --git a/tools/testing/selftests/liveupdate/Makefile b/tools/testing/se= lftests/liveupdate/Makefile index ed7534468386..30689d22cb02 100644 --- a/tools/testing/selftests/liveupdate/Makefile +++ b/tools/testing/selftests/liveupdate/Makefile @@ -7,6 +7,7 @@ TEST_GEN_PROGS +=3D liveupdate TEST_GEN_PROGS_EXTENDED +=3D luo_kexec_simple TEST_GEN_PROGS_EXTENDED +=3D luo_multi_session TEST_GEN_PROGS_EXTENDED +=3D luo_stress_sessions +TEST_GEN_PROGS_EXTENDED +=3D luo_stress_files =20 TEST_FILES +=3D do_kexec.sh =20 diff --git a/tools/testing/selftests/liveupdate/luo_stress_files.c b/tools/= testing/selftests/liveupdate/luo_stress_files.c new file mode 100644 index 000000000000..b6a0c3899890 --- /dev/null +++ b/tools/testing/selftests/liveupdate/luo_stress_files.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (c) 2026, Google LLC. + * Pasha Tatashin + * + * Validate that LUO can handle a large number of files per session across + * a kexec reboot. + */ + +#include +#include +#include "luo_test_utils.h" + +#define NUM_FILES 500 +#define STATE_SESSION_NAME "kexec_many_files_state" +#define STATE_MEMFD_TOKEN 9999 +#define TEST_SESSION_NAME "many_files_session" + +/* Stage 1: Executed before the kexec reboot. */ +static void run_stage_1(int luo_fd) +{ + int session_fd, ret, i; + + ksft_print_msg("[STAGE 1] Increasing ulimit for open files...\n"); + ret =3D luo_ensure_nofile_limit(NUM_FILES); + if (ret =3D=3D -EPERM) + ksft_exit_skip("Insufficient privileges to set RLIMIT_NOFILE\n"); + if (ret < 0) + ksft_exit_fail_msg("luo_ensure_nofile_limit failed: %s\n", strerror(-ret= )); + + ksft_print_msg("[STAGE 1] Creating state file for next stage (2)...\n"); + create_state_file(luo_fd, STATE_SESSION_NAME, STATE_MEMFD_TOKEN, 2); + + ksft_print_msg("[STAGE 1] Creating test session '%s'...\n", TEST_SESSION_= NAME); + session_fd =3D luo_create_session(luo_fd, TEST_SESSION_NAME); + if (session_fd < 0) + fail_exit("luo_create_session"); + + ksft_print_msg("[STAGE 1] Preserving %d files...\n", NUM_FILES); + for (i =3D 0; i < NUM_FILES; i++) { + char data[64]; + + snprintf(data, sizeof(data), "file-data-%d", i); + if (create_and_preserve_memfd(session_fd, i, data) < 0) + fail_exit("create_and_preserve_memfd for index %d", i); + } + + ksft_print_msg("[STAGE 1] Successfully preserved %d files.\n", NUM_FILES); + + close(luo_fd); + daemonize_and_wait(); +} + +/* Stage 2: Executed after the kexec reboot. */ +static void run_stage_2(int luo_fd, int state_session_fd) +{ + int session_fd; + int i, stage; + + ksft_print_msg("[STAGE 2] Starting post-kexec verification...\n"); + + restore_and_read_stage(state_session_fd, STATE_MEMFD_TOKEN, &stage); + if (stage !=3D 2) { + fail_exit("Expected stage 2, but state file contains %d", + stage); + } + + ksft_print_msg("[STAGE 2] Retrieving test session '%s'...\n", TEST_SESSIO= N_NAME); + session_fd =3D luo_retrieve_session(luo_fd, TEST_SESSION_NAME); + if (session_fd < 0) + fail_exit("luo_retrieve_session"); + + ksft_print_msg("[STAGE 2] Verifying %d files...\n", NUM_FILES); + for (i =3D 0; i < NUM_FILES; i++) { + char data[64]; + + snprintf(data, sizeof(data), "file-data-%d", i); + if (restore_and_verify_memfd(session_fd, i, data) < 0) + fail_exit("restore_and_verify_memfd for index %d", i); + } + + ksft_print_msg("[STAGE 2] Finishing test session...\n"); + if (luo_session_finish(session_fd) < 0) + fail_exit("luo_session_finish for test session"); + close(session_fd); + + ksft_print_msg("[STAGE 2] Finalizing state session...\n"); + if (luo_session_finish(state_session_fd) < 0) + fail_exit("luo_session_finish for state session"); + close(state_session_fd); + + ksft_print_msg("\n--- MANY-FILES KEXEC TEST PASSED (%d files) ---\n", + NUM_FILES); +} + +int main(int argc, char *argv[]) +{ + return luo_test(argc, argv, STATE_SESSION_NAME, + run_stage_1, run_stage_2); +} --=20 2.53.0