From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0A2ACEA719F for ; Mon, 20 Apr 2026 04:32:16 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id DF97C6B012C; Mon, 20 Apr 2026 00:32:15 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id DA9786B012D; Mon, 20 Apr 2026 00:32:15 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id C988A6B012E; Mon, 20 Apr 2026 00:32:15 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id B57806B012C for ; Mon, 20 Apr 2026 00:32:15 -0400 (EDT) Received: from smtpin12.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id 377B8160907 for ; Mon, 20 Apr 2026 04:32:15 +0000 (UTC) X-FDA: 84677662230.12.CD12D0C Received: from out-174.mta1.migadu.com (out-174.mta1.migadu.com [95.215.58.174]) by imf26.hostedemail.com (Postfix) with ESMTP id 09E1C140002 for ; Mon, 20 Apr 2026 04:32:12 +0000 (UTC) Authentication-Results: imf26.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b=G09nrrQe; spf=pass (imf26.hostedemail.com: domain of yanjun.zhu@linux.dev designates 95.215.58.174 as permitted sender) smtp.mailfrom=yanjun.zhu@linux.dev; dmarc=pass (policy=none) header.from=linux.dev ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1776659533; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=5MnYggTyySz4EUQ19/7Dx63B3B6BmxCSuohEE45TtEc=; b=eEL8/p5RwCpnZiZ6xC140WYU174ukdOtyBWEZbMHOhlOvVOazuyzRhTRUwe+0cB81+zQaa NIXM+BhhpEMA5adCMQ5ZQWVppDpZJ2xdgVhvGAvg3ov1kBnvxZlCrrjcOm612IDB90xeBp fRmKbWe7Y6/O45rUmvdAGaqH4ea0HVY= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1776659533; a=rsa-sha256; cv=none; b=GWk+/4gc/o39hppgHweitTugAaVX4JDENORCbxJMiMUUXIl8VR9jFv+lRAyEbQt4wnNNo2 iDW35yg8V6vwoIUGx5GtnHmP88KuN1FfV2+VwctchpjkRatsQtCVvwGflttGkPe4o4sWkG N2/emYnFMHT6ZcYwgHlXENDECt+1iZ4= ARC-Authentication-Results: i=1; imf26.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b=G09nrrQe; spf=pass (imf26.hostedemail.com: domain of yanjun.zhu@linux.dev designates 95.215.58.174 as permitted sender) smtp.mailfrom=yanjun.zhu@linux.dev; dmarc=pass (policy=none) header.from=linux.dev Message-ID: DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1776659530; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5MnYggTyySz4EUQ19/7Dx63B3B6BmxCSuohEE45TtEc=; b=G09nrrQeVAZKf4wksdB8CU5gruoW1QcK0eujZuWYMJmHbys+6aCRTmy3u6R4PYilHIl0DL WutfMtemwFp0vJBJ5tMG6k1QcrxoSNkgbboqQhhRQ7jO9RK9BZwf5o3lakqwRa3equsqgf Kxk+FoZmdL2UPRV3N6s9zt5onjTE1t0= Date: Sun, 19 Apr 2026 21:32:00 -0700 MIME-Version: 1.0 Subject: Re: [PATCH 1/5] liveupdate: Remove limit on the number of sessions To: Pasha Tatashin , "yanjun.zhu@linux.dev" Cc: linux-kselftest@vger.kernel.org, rppt@kernel.org, shuah@kernel.org, akpm@linux-foundation.org, linux-mm@kvack.org, linux-kernel@vger.kernel.org, dmatlack@google.com, kexec@lists.infradead.org, pratyush@kernel.org, skhawaja@google.com, graf@amazon.com References: <20260414200237.444170-1-pasha.tatashin@soleen.com> <20260414200237.444170-2-pasha.tatashin@soleen.com> <4bd21077-8711-4ae7-a695-8bc88ce652d1@linux.dev> X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. From: Zhu Yanjun In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT X-Stat-Signature: bttb7thtcddnuazdjaoid18xp4x384bx X-Rspam-User: X-Rspamd-Queue-Id: 09E1C140002 X-Rspamd-Server: rspam05 X-HE-Tag: 1776659532-275096 X-HE-Meta: U2FsdGVkX19ZL57SxClDDzFeTBRBKDv9ByDd+YpTXhy7npPbEC1IlmQfyhk1MA3uQFb8SUblBSgSGbAl8Xyk49A9x+2C3grK+gqS40Gi4C5oYurRVwRmhLQSxQSff4cTS49bRI318r+6NDKt21nkmy3tSbu+jtVr7JM5cXvCdvUCQj/km5w99ZsrioohpoQ3ejHU1kg8xBCVl092E8TuoPux61W6fAHCoSUnVi/mjkKi/zCniy56Mf2phhIHIGX5RRHEU8e3fNMwuxP34ylRKYJAPrfhdBlMjwTkFNalZZxo92JHp8qCRNtkrDjikZuRTJjX/VLYcVkAPSKasnNT1OlzVWprfiqJOmHjKXgec4s8H7SKAOZD8xhY93to6hmluU/soAmkIuNUY2tHaIr6s7vTUrWlOO69y9j8NsZojBmOX82QT8+D24Yg644J5jJFW+W8sQ8G/6/6P3I2y1xpXgzcsUtx18LGZviIenhz/Z7+7kGLfu5ezjTbn7wfYt6n3RAPK5SFiSGK6Zd/Q4gLYwE0CDyltqOTnFEPRSFhncVr03ICDtsXoj1Ro6Y+qsUMAKpjY1wAp6eI98uuFDRBcKu0XL/98R4usLk+XIqsoyuzEzsHfztclTECpywqxfKY5eO7QcGJLy6mSxJqcIf863s5LionM/zSbEakLpi6yAK3aTadrL+ft/0I7J7gBuTCDcfzXw/XbvtqCzCfqYA5HM6KxET7KGCvKIBkBCcRl5539wqM8AJ9FMwy8sxcvf0ZM61hhHwRAnPz5qTG4/kCPW/ur7xipb4qcYcyTdK8irqpyDTW74zxhkPLDkHOgR5nxhHRYDnIEyDRAtA6zG0TCkJTU6pVquyWCqlib2rEYJ+OULM2Wte25PFZFrjVUcfm4crsO+6cQQMG88elH8RrJi5kis3oiL8FQM62ypv8LbY1rJB9ArO5+EczcZ/6iZPZqq+KCFb6RW9YXuLHVEr SKb8VOut 3NqXveuLgZP5QOh1l4Yp1SB6kErbOwqiFTo/fx5swoLJIKQOZrdwObLRnrkCJhT8HiFAWztMXIhEguUL+3QUdpNp1tK01jtGbqUrn5H/y8pCnV9hO0+2Le1OY6YvQS3wVDKnxFvZiMBQc7Wd0r6uOTVj2XRL7+Ley6ZH56pXGXhCf/A8ZDmBaxLvVSc1y3oQOLIcVJcIW894I1ZUkjnElW1ah5RHqn9myw4rR0BJsK23XWg3yFAugrSWzhUh+505vSGUxEVXp0iMDTkhJ6YaNjlkS4M6fv7qXgK6MrKDaMOFrdpXGcMpZM6ChiS/eFHDpoxGOrURiAqirSe2C3DalHi8pjw== Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: 在 2026/4/14 17:14, Pasha Tatashin 写道: > On Tue, Apr 14, 2026 at 8:06 PM yanjun.zhu wrote: >> On 4/14/26 1:02 PM, Pasha Tatashin wrote: >>> 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. >>> >>> - Bump session ABI version to v3. >>> - Update struct luo_session_header_ser to include a 'next' pointer. >>> - Implement dynamic block allocation in luo_session_insert(). >>> - Update setup, serialization, and deserialization logic to traverse >>> the block chain. >>> - Remove LUO_SESSION_MAX limit. >>> >>> Signed-off-by: Pasha Tatashin >>> --- >>> include/linux/kho/abi/luo.h | 19 +-- >>> kernel/liveupdate/luo_internal.h | 12 +- >>> kernel/liveupdate/luo_session.c | 237 +++++++++++++++++++++++-------- >>> 3 files changed, 197 insertions(+), 71 deletions(-) >>> >>> diff --git a/include/linux/kho/abi/luo.h b/include/linux/kho/abi/luo.h >>> index 46750a0ddf88..f5732958545e 100644 >>> --- a/include/linux/kho/abi/luo.h >>> +++ b/include/linux/kho/abi/luo.h >>> @@ -57,9 +57,10 @@ >>> * - compatible: "luo-session-v1" >>> * Identifies the session ABI version. >>> * - luo-session-header: u64 >>> - * The physical address of a `struct luo_session_header_ser`. This structure >>> - * is the header for a contiguous block of memory containing an array of >>> - * `struct luo_session_ser`, one for each preserved session. >>> + * The physical address of the first `struct luo_session_header_ser`. >>> + * This structure is the header for a block of memory containing an array >>> + * of `struct luo_session_ser` entries. Multiple blocks are linked via >>> + * the `next` field in the header. >>> * >>> * File-Lifecycle-Bound Node (luo-flb): >>> * This node describes all preserved global objects whose lifecycle is bound >>> @@ -77,9 +78,9 @@ >>> * `__packed` structures. These structures contain the actual preserved state. >>> * >>> * - 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. >>> + * Header for the session data block. Contains the physical address of the >>> + * next session data block and the number of `struct luo_session_ser` >>> + * entries that follow this header in the current block. >>> * >>> * - struct luo_session_ser: >>> * Metadata for a single session, including its name and a physical pointer >>> @@ -153,21 +154,23 @@ struct luo_file_set_ser { >>> * luo_session_header_ser >>> */ >>> #define LUO_FDT_SESSION_NODE_NAME "luo-session" >>> -#define LUO_FDT_SESSION_COMPATIBLE "luo-session-v2" >>> +#define LUO_FDT_SESSION_COMPATIBLE "luo-session-v3" >>> #define LUO_FDT_SESSION_HEADER "luo-session-header" >>> >>> /** >>> * struct luo_session_header_ser - Header for the serialized session data block. >>> + * @next: Physical address of the next struct luo_session_header_ser. >>> * @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 >>> + * 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 session entries that follow. >>> * >>> * If this structure is modified, `LUO_FDT_SESSION_COMPATIBLE` must be updated. >>> */ >>> struct luo_session_header_ser { >>> + u64 next; >>> u64 count; >>> } __packed; >>> >>> diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h >>> index 875844d7a41d..a73f42069301 100644 >>> --- a/kernel/liveupdate/luo_internal.h >>> +++ b/kernel/liveupdate/luo_internal.h >>> @@ -11,6 +11,16 @@ >>> #include >>> #include >>> >>> +/* >>> + * 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 ~8.1 million sessions and ~1.2 million files per >>> + * session, which is more than enough for all realistic use cases. >>> + */ >>> +#define LUO_MAX_BLOCKS 10000 >>> + >>> struct luo_ucmd { >>> void __user *ubuffer; >>> u32 user_size; >>> @@ -59,7 +69,6 @@ struct luo_file_set { >>> * struct luo_session - Represents an active or incoming Live Update session. >>> * @name: A unique name for this session, used for identification and >>> * retrieval. >>> - * @ser: Pointer to the serialized data for this session. >>> * @list: A list_head member used to link this session into a global list >>> * of either outgoing (to be preserved) or incoming (restored from >>> * previous kernel) sessions. >>> @@ -70,7 +79,6 @@ struct luo_file_set { >>> */ >>> struct luo_session { >>> char name[LIVEUPDATE_SESSION_NAME_LENGTH]; >>> - struct luo_session_ser *ser; >>> struct list_head list; >>> bool retrieved; >>> struct luo_file_set file_set; >>> diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c >>> index 92b1af791889..007ca34eba79 100644 >>> --- a/kernel/liveupdate/luo_session.c >>> +++ b/kernel/liveupdate/luo_session.c >>> @@ -69,30 +69,39 @@ >>> #include >>> #include "luo_internal.h" >>> >>> -/* 16 4K pages, give space for 744 sessions */ >>> +/* 16 4K pages, give space for 819 sessions per block */ >>> #define LUO_SESSION_PGCNT 16ul >>> -#define LUO_SESSION_MAX (((LUO_SESSION_PGCNT << PAGE_SHIFT) - \ >>> +#define LUO_SESSION_BLOCK_MAX (((LUO_SESSION_PGCNT << PAGE_SHIFT) - \ >>> sizeof(struct luo_session_header_ser)) / \ >>> sizeof(struct luo_session_ser)) >>> >>> +/** >>> + * struct luo_session_block - Internal representation of a session serialization block. >>> + * @list: List head for linking blocks in memory. >>> + * @ser: Pointer to the serialized header in preserved memory. >>> + */ >>> +struct luo_session_block { >>> + struct list_head list; >>> + struct luo_session_header_ser *ser; >>> +}; >>> + >>> /** >>> * struct luo_session_header - Header struct for managing LUO sessions. >>> * @count: The number of sessions currently tracked in the @list. >>> + * @nblocks: The number of allocated serialization blocks. >>> * @list: The head of the linked list of `struct luo_session` instances. >>> * @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`). >>> + * @blocks: The list of serialization blocks (struct luo_session_block). >>> * @active: Set to true when first initialized. If previous kernel did not >>> * send session data, active stays false for incoming. >>> */ >>> struct luo_session_header { >>> long count; >>> + long nblocks; >>> struct list_head list; >>> struct rw_semaphore rwsem; >>> - struct luo_session_header_ser *header_ser; >>> - struct luo_session_ser *ser; >>> + struct list_head blocks; >>> bool active; >>> }; >>> >>> @@ -110,10 +119,12 @@ static struct luo_session_global luo_session_global = { >>> .incoming = { >>> .list = LIST_HEAD_INIT(luo_session_global.incoming.list), >>> .rwsem = __RWSEM_INITIALIZER(luo_session_global.incoming.rwsem), >>> + .blocks = LIST_HEAD_INIT(luo_session_global.incoming.blocks), >>> }, >>> .outgoing = { >>> .list = LIST_HEAD_INIT(luo_session_global.outgoing.list), >>> .rwsem = __RWSEM_INITIALIZER(luo_session_global.outgoing.rwsem), >>> + .blocks = LIST_HEAD_INIT(luo_session_global.outgoing.blocks), >>> }, >>> }; >>> >>> @@ -140,6 +151,70 @@ static void luo_session_free(struct luo_session *session) >>> kfree(session); >>> } >>> >>> +static int luo_session_add_block(struct luo_session_header *sh, >>> + struct luo_session_header_ser *ser) >>> +{ >>> + struct luo_session_block *block; >>> + >>> + if (sh->nblocks >= LUO_MAX_BLOCKS) >>> + return -ENOSPC; >>> + >>> + block = kzalloc_obj(*block); >>> + if (!block) >>> + return -ENOMEM; >>> + >>> + block->ser = ser; >>> + list_add_tail(&block->list, &sh->blocks); >>> + sh->nblocks++; >>> + >>> + return 0; >>> +} >>> + >>> +static int luo_session_create_ser_block(struct luo_session_header *sh) >>> +{ >>> + struct luo_session_block *last = NULL; >>> + struct luo_session_header_ser *ser; >>> + int err; >>> + >>> + ser = kho_alloc_preserve(LUO_SESSION_PGCNT << PAGE_SHIFT); >>> + if (IS_ERR(ser)) >>> + return PTR_ERR(ser); >>> + >>> + if (!list_empty(&sh->blocks)) >>> + last = list_last_entry(&sh->blocks, struct luo_session_block, list); >>> + >>> + err = luo_session_add_block(sh, ser); >>> + if (err) >>> + goto err_unpreserve; >>> + >>> + if (last) >>> + last->ser->next = virt_to_phys(ser); >>> + >>> + return 0; >>> + >>> +err_unpreserve: >>> + kho_unpreserve_free(ser); >>> + return err; >>> +} >>> + >>> +static void luo_session_destroy_ser_blocks(struct luo_session_header *sh, >>> + bool unpreserve) >>> +{ >>> + struct luo_session_block *block, *tmp; >>> + >>> + list_for_each_entry_safe(block, tmp, &sh->blocks, list) { >>> + if (block->ser) { >>> + if (unpreserve) >>> + kho_unpreserve_free(block->ser); >>> + else >>> + kho_restore_free(block->ser); >>> + } >>> + list_del(&block->list); >>> + kfree(block); >>> + sh->nblocks--; >>> + } >>> +} >>> + >>> static int luo_session_insert(struct luo_session_header *sh, >>> struct luo_session *session) >>> { >>> @@ -147,15 +222,6 @@ static int luo_session_insert(struct luo_session_header *sh, >>> >>> guard(rwsem_write)(&sh->rwsem); >>> >>> - /* >>> - * For outgoing we should make sure there is room in serialization array >>> - * for new session. >>> - */ >>> - if (sh == &luo_session_global.outgoing) { >>> - if (sh->count == LUO_SESSION_MAX) >>> - return -ENOMEM; >>> - } >>> - >>> /* >>> * For small number of sessions this loop won't hurt performance >>> * but if we ever start using a lot of sessions, this might >>> @@ -166,6 +232,20 @@ static int luo_session_insert(struct luo_session_header *sh, >>> if (!strncmp(it->name, session->name, sizeof(it->name))) >>> return -EEXIST; >>> } >>> + >>> + /* >>> + * For outgoing we should make sure there is room in serialization array >>> + * for new session. If not, allocate a new block. >>> + */ >>> + if (sh == &luo_session_global.outgoing) { >>> + if (sh->count == sh->nblocks * LUO_SESSION_BLOCK_MAX) { >> I am not sure if "LUO_SESSION_BLOCK_MAX 10000" has special meaning or not. > LUO_SESSION_BLOCK_MAX is calculated based on the number of times > "struct luo_session_ser)" fits into a page-aligned block minus the > luo_session_header_ser. It is not power-of-two, so there is no pretty > way to change this to avoid multiplcation. Maybe we can use if (!(sh->count % LUO_SESSION_BLOCK_MASK) && sh->count > 0) This can avoid multiplcation. Just 2 cent suggestion. Zhu Yanjun > >> If not, we can use the following: >> >> #define LUO_SESSION_BLOCK_SHIFT 13 >> #define LUO_SESSION_BLOCK_MAX (1UL << LUO_SESSION_BLOCK_SHIFT) // 8192 >> #define LUO_SESSION_BLOCK_MASK (LUO_SESSION_BLOCK_MAX - 1) // 0x1FFF >> >> if (!(sh->count & LUO_SESSION_BLOCK_MASK) && sh->count > 0) { >> ... >> } >> >> Zhu Yanjun >> >>> + int err = luo_session_create_ser_block(sh); >>> + >>> + if (err) >>> + return err; >>> + } >>> + } >>> + >>> list_add_tail(&session->list, &sh->list); >>> sh->count++; >>> >>> @@ -444,9 +524,12 @@ int __init luo_session_setup_outgoing(void *fdt_out) >>> u64 header_ser_pa; >>> int err; >>> >>> - header_ser = kho_alloc_preserve(LUO_SESSION_PGCNT << PAGE_SHIFT); >>> - if (IS_ERR(header_ser)) >>> - return PTR_ERR(header_ser); >>> + err = luo_session_create_ser_block(&luo_session_global.outgoing); >>> + if (err) >>> + return err; >>> + >>> + header_ser = list_first_entry(&luo_session_global.outgoing.blocks, >>> + struct luo_session_block, list)->ser; >>> header_ser_pa = virt_to_phys(header_ser); >>> >>> err = fdt_begin_node(fdt_out, LUO_FDT_SESSION_NODE_NAME); >>> @@ -459,19 +542,18 @@ int __init luo_session_setup_outgoing(void *fdt_out) >>> if (err) >>> goto err_unpreserve; >>> >>> - luo_session_global.outgoing.header_ser = header_ser; >>> - luo_session_global.outgoing.ser = (void *)(header_ser + 1); >>> luo_session_global.outgoing.active = true; >>> >>> return 0; >>> >>> err_unpreserve: >>> - kho_unpreserve_free(header_ser); >>> + luo_session_destroy_ser_blocks(&luo_session_global.outgoing, true); >>> return err; >>> } >>> >>> int __init luo_session_setup_incoming(void *fdt_in) >>> { >>> + struct luo_session_header *sh = &luo_session_global.incoming; >>> struct luo_session_header_ser *header_ser; >>> int err, header_size, offset; >>> u64 header_ser_pa; >>> @@ -501,11 +583,14 @@ int __init luo_session_setup_incoming(void *fdt_in) >>> } >>> >>> header_ser_pa = get_unaligned((u64 *)ptr); >>> - header_ser = phys_to_virt(header_ser_pa); >>> - >>> - luo_session_global.incoming.header_ser = header_ser; >>> - luo_session_global.incoming.ser = (void *)(header_ser + 1); >>> - luo_session_global.incoming.active = true; >>> + while (header_ser_pa) { >>> + header_ser = phys_to_virt(header_ser_pa); >>> + err = luo_session_add_block(sh, header_ser); >>> + if (err) >>> + return err; >>> + header_ser_pa = header_ser->next; >>> + } >>> + sh->active = true; >>> >>> return 0; >>> } >>> @@ -513,6 +598,7 @@ int __init luo_session_setup_incoming(void *fdt_in) >>> int luo_session_deserialize(void) >>> { >>> struct luo_session_header *sh = &luo_session_global.incoming; >>> + struct luo_session_block *block; >>> static bool is_deserialized; >>> static int err; >>> >>> @@ -539,40 +625,49 @@ 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 = 0; i < sh->header_ser->count; i++) { >>> - struct luo_session *session; >>> - >>> - session = 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); >>> - err = PTR_ERR(session); >>> - return err; >>> - } >>> + list_for_each_entry(block, &sh->blocks, list) { >>> + struct luo_session_ser *ser = (void *)(block->ser + 1); >>> >>> - err = 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); >>> + if (block->ser->count > LUO_SESSION_BLOCK_MAX) { >>> + pr_warn("Session block contains too many entries: %llu\n", >>> + block->ser->count); >>> + err = -EINVAL; >>> return err; >>> } >>> >>> - scoped_guard(mutex, &session->mutex) { >>> - err = 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)); >>> - return err; >>> + for (int i = 0; i < block->ser->count; i++) { >>> + struct luo_session *session; >>> + >>> + session = luo_session_alloc(ser[i].name); >>> + if (IS_ERR(session)) { >>> + pr_warn("Failed to allocate session [%.*s] during deserialization %pe\n", >>> + (int)sizeof(ser[i].name), >>> + ser[i].name, session); >>> + err = PTR_ERR(session); >>> + return err; >>> + } >>> + >>> + err = 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 = luo_file_deserialize(&session->file_set, >>> + &ser[i].file_set_ser); >>> + } >>> + if (err) { >>> + pr_warn("Failed to deserialize files for session [%s] %pe\n", >>> + session->name, ERR_PTR(err)); >>> + return err; >>> + } >>> } >>> } >>> >>> - kho_restore_free(sh->header_ser); >>> - sh->header_ser = NULL; >>> - sh->ser = NULL; >>> + luo_session_destroy_ser_blocks(sh, false); >>> >>> return 0; >>> } >>> @@ -580,31 +675,51 @@ int luo_session_deserialize(void) >>> int luo_session_serialize(void) >>> { >>> struct luo_session_header *sh = &luo_session_global.outgoing; >>> + struct luo_session_block *block; >>> struct luo_session *session; >>> + struct luo_session_ser *ser; >>> int i = 0; >>> int err; >>> >>> guard(rwsem_write)(&sh->rwsem); >>> + >>> + if (list_empty(&sh->blocks)) >>> + return 0; >>> + >>> + block = list_first_entry(&sh->blocks, struct luo_session_block, list); >>> + ser = (void *)(block->ser + 1); >>> + >>> list_for_each_entry(session, &sh->list, list) { >>> - err = luo_session_freeze_one(session, &sh->ser[i]); >>> + if (i == LUO_SESSION_BLOCK_MAX) { >>> + block->ser->count = i; >>> + block = list_next_entry(block, list); >>> + ser = (void *)(block->ser + 1); >>> + i = 0; >>> + } >>> + >>> + err = luo_session_freeze_one(session, &ser[i]); >>> if (err) >>> goto err_undo; >>> >>> - strscpy(sh->ser[i].name, session->name, >>> - sizeof(sh->ser[i].name)); >>> + strscpy(ser[i].name, session->name, >>> + sizeof(ser[i].name)); >>> i++; >>> } >>> - sh->header_ser->count = sh->count; >>> + block->ser->count = i; >>> >>> return 0; >>> >>> err_undo: >>> 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)); >>> + if (i < 0) { >>> + block = list_prev_entry(block, list); >>> + ser = (void *)(block->ser + 1); >>> + i = LUO_SESSION_BLOCK_MAX - 1; >>> + } >>> + luo_session_unfreeze_one(session, &ser[i]); >>> + memset(ser[i].name, 0, sizeof(ser[i].name)); >>> } >>> >>> return err; >>> } >>> - >> -- Best Regards, Yanjun.Zhu