summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPasha Tatashin <pasha.tatashin@soleen.com>2026-06-03 15:43:57 +0000
committerMike Rapoport (Microsoft) <rppt@kernel.org>2026-06-03 21:15:46 +0300
commitb5a58a922e6f2f9f40faddd8e0e1fe3ce0ea9c56 (patch)
treea15ab86fd8463866b64688bfbf80f204a28b2d10
parent0349ff2887059112ce06831ab29aec47a2a7285a (diff)
downloadlinux-b5a58a922e6f2f9f40faddd8e0e1fe3ce0ea9c56.tar.gz
linux-b5a58a922e6f2f9f40faddd8e0e1fe3ce0ea9c56.zip
liveupdate: defer session block allocation and physical address setting
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. Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Reviewed-by: Pratyush Yadav (Google) <pratyush@kernel.org> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com> Link: https://patch.msgid.link/20260603154402.468928-9-pasha.tatashin@soleen.com Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
-rw-r--r--kernel/liveupdate/luo_core.c4
-rw-r--r--kernel/liveupdate/luo_internal.h2
-rw-r--r--kernel/liveupdate/luo_session.c68
3 files changed, 45 insertions, 29 deletions
diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c
index 69b00e7d0f8f..1b2bda22902d 100644
--- a/kernel/liveupdate/luo_core.c
+++ b/kernel/liveupdate/luo_core.c
@@ -165,9 +165,7 @@ static int __init luo_state_setup(void)
strscpy(luo_ser->compatible, LUO_ABI_COMPATIBLE, sizeof(luo_ser->compatible));
luo_ser->liveupdate_num = luo_global.liveupdate_num + 1;
- err = luo_session_setup_outgoing(&luo_ser->sessions_pa);
- if (err)
- goto exit_free_luo_ser;
+ luo_session_setup_outgoing(&luo_ser->sessions_pa);
err = luo_flb_setup_outgoing(&luo_ser->flbs_pa);
if (err)
diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h
index fe22086bfbeb..ee18f9a11b91 100644
--- a/kernel/liveupdate/luo_internal.h
+++ b/kernel/liveupdate/luo_internal.h
@@ -79,7 +79,7 @@ extern struct rw_semaphore luo_register_rwlock;
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_session.c
index 1cd315e0f6de..2411849a34e3 100644
--- a/kernel/liveupdate/luo_session.c
+++ b/kernel/liveupdate/luo_session.c
@@ -108,15 +108,16 @@ static DECLARE_RWSEM(luo_session_serialize_rwsem);
/**
* 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` 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`).
- * @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` 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`).
+ * @sessions_pa: Points to the location of sessions_pa within struct luo_ser.
+ * @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;
@@ -124,6 +125,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;
};
@@ -171,10 +173,30 @@ static void luo_session_free(struct luo_session *session)
kfree(session);
}
+static int luo_session_grow_ser(struct luo_session_header *sh)
+{
+ struct luo_session_header_ser *header_ser;
+
+ if (sh->count == LUO_SESSION_MAX)
+ return -ENOMEM;
+
+ if (sh->header_ser)
+ return 0;
+
+ header_ser = kho_alloc_preserve(LUO_SESSION_PGCNT << PAGE_SHIFT);
+ if (IS_ERR(header_ser))
+ return PTR_ERR(header_ser);
+
+ sh->header_ser = header_ser;
+ sh->ser = (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;
guard(rwsem_write)(&sh->rwsem);
@@ -183,8 +205,9 @@ static int luo_session_insert(struct luo_session_header *sh,
* for new session.
*/
if (sh == &luo_session_global.outgoing) {
- if (sh->count == LUO_SESSION_MAX)
- return -ENOMEM;
+ err = luo_session_grow_ser(sh);
+ if (err)
+ return err;
}
/*
@@ -524,21 +547,10 @@ int luo_session_retrieve(const char *name, struct file **filep)
return err;
}
-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 = kho_alloc_preserve(LUO_SESSION_PGCNT << PAGE_SHIFT);
- if (IS_ERR(header_ser))
- return PTR_ERR(header_ser);
-
- *sessions_pa = virt_to_phys(header_ser);
-
- luo_session_global.outgoing.header_ser = header_ser;
- luo_session_global.outgoing.ser = (void *)(header_ser + 1);
+ luo_session_global.outgoing.sessions_pa = sessions_pa;
luo_session_global.outgoing.active = true;
-
- return 0;
}
int __init luo_session_setup_incoming(u64 sessions_pa)
@@ -644,6 +656,8 @@ int luo_session_serialize(void)
down_write(&luo_session_serialize_rwsem);
down_write(&sh->rwsem);
+ *sh->sessions_pa = 0;
+
list_for_each_entry(session, &sh->list, list) {
err = luo_session_freeze_one(session, &sh->ser[i]);
if (err)
@@ -653,7 +667,11 @@ int luo_session_serialize(void)
sizeof(sh->ser[i].name));
i++;
}
- sh->header_ser->count = sh->count;
+
+ if (sh->header_ser && sh->count > 0) {
+ sh->header_ser->count = sh->count;
+ *sh->sessions_pa = virt_to_phys(sh->header_ser);
+ }
up_write(&sh->rwsem);
return 0;