Thread (2 messages) 2 messages, 2 authors, 2025-11-21

Re: [PATCH v6 04/20] liveupdate: luo_session: add sessions support

From: Pasha Tatashin <pasha.tatashin@soleen.com>
Date: 2025-11-21 21:31:24
Also in: linux-doc, linux-fsdevel, linux-mm, lkml

quoted
 /*
  * The LUO FDT hooks all LUO state for sessions, fds, etc.
- * In the root it allso carries "liveupdate-number" 64-bit property that
+ * In the root it also carries "liveupdate-number" 64-bit property that
Nit: This needs a bit of patch massaging. Patch 2 added the typo, and
this patch fixes it. It would be better to just update patch 2.
Yeap, this is fixed.

quoted
+ * 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.
+ */
+struct luo_session_header_ser {
+     u64 pgcnt;
Why do you need pgcnt here? Can't the size be inferred from count? And
since you use contiguous memory block, the folio will know its page
count anyway, right? The less we have in the ABI the better IMO.
Right, I had pgnct because my allocators were using size as an
argument, but we removed that, so pgcnt can also be removed.
Same for other structures below.
quoted
+     u64 count;
+} __packed;
+
+/**
+ * struct luo_session_ser - Represents the serialized metadata for a LUO session.
+ * @name:    The unique name of the session, copied from the `luo_session`
+ *           structure.
+ * @files:   The physical address of a contiguous memory block that holds
+ *           the serialized state of files.
+ * @pgcnt:   The number of pages occupied by the `files` memory block.
+ * @count:   The total number of files that were part of this session during
+ *           serialization. Used for iteration and validation during
+ *           restoration.
+ *
+ * This structure is used to package session-specific metadata for transfer
+ * between kernels via Kexec Handover. An array of these structures (one per
+ * session) is created and passed to the new kernel, allowing it to reconstruct
+ * the session context.
+ *
+ * If this structure is modified, LUO_SESSION_COMPATIBLE must be updated.
+ */
+struct luo_session_ser {
+     char name[LIVEUPDATE_SESSION_NAME_LENGTH];
+     u64 files;
+     u64 pgcnt;
+     u64 count;
+} __packed;
+
 #endif /* _LINUX_LIVEUPDATE_ABI_LUO_H */
[...]
quoted
+/* Create a "struct file" for session */
+static int luo_session_getfile(struct luo_session *session, struct file **filep)
+{
+     char name_buf[128];
+     struct file *file;
+
+     guard(mutex)(&session->mutex);
+     snprintf(name_buf, sizeof(name_buf), "[luo_session] %s", session->name);
+     file = anon_inode_getfile(name_buf, &luo_session_fops, session, O_RDWR);
Nit: You can return the file directly and get rid of filep.
I prefer returning error here.
quoted
+     if (IS_ERR(file))
+             return PTR_ERR(file);
+
+     *filep = file;
+
+     return 0;
+}
[...]
quoted
+int __init luo_session_setup_outgoing(void *fdt_out)
+{
+     struct luo_session_header_ser *header_ser;
+     u64 header_ser_pa;
+     int err;
+
+     header_ser = kho_alloc_preserve(LUO_SESSION_PGCNT << PAGE_SHIFT);
Nit: The naming is a bit confusing here. At first glance I thought this
was just allocating the header, but it allocates the whole session
serialization buffer.
I made it a little clearer by adding "outgoing_buffer" local variable,
and then assigning head_ser to this local variable.
quoted
+     if (IS_ERR(header_ser))
+             return PTR_ERR(header_ser);
+     header_ser_pa = virt_to_phys(header_ser);
+
+     err = fdt_begin_node(fdt_out, LUO_FDT_SESSION_NODE_NAME);
+     err |= fdt_property_string(fdt_out, "compatible",
+                                LUO_FDT_SESSION_COMPATIBLE);
+     err |= fdt_property(fdt_out, LUO_FDT_SESSION_HEADER, &header_ser_pa,
+                         sizeof(header_ser_pa));
+     err |= fdt_end_node(fdt_out);
+
+     if (err)
+             goto err_unpreserve;
+
+     header_ser->pgcnt = LUO_SESSION_PGCNT;
+     INIT_LIST_HEAD(&luo_session_global.outgoing.list);
+     init_rwsem(&luo_session_global.outgoing.rwsem);
+     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);
+     return err;
+}
[...]
quoted
+int luo_session_deserialize(void)
+{
+     struct luo_session_header *sh = &luo_session_global.incoming;
+     int err;
+
+     if (luo_session_is_deserialized())
+             return 0;
+
+     luo_session_global.deserialized = true;
+     if (!sh->active) {
+             INIT_LIST_HEAD(&sh->list);
+             init_rwsem(&sh->rwsem);
Nit: it would be a bit simpler if LUO init always initialized this. And
then luo_session_setup_incoming() can fill the list if it has any data.
Slight reduction in code duplication and mental load.
These are now statically initialized.
quoted
+             return 0;
+     }
+
+     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",
+                             sh->ser[i].name, session);
+                     return PTR_ERR(session);
+             }
+
+             err = luo_session_insert(sh, session);
+             if (err) {
+                     luo_session_free(session);
+                     pr_warn("Failed to insert session [%s] %pe\n",
+                             session->name, ERR_PTR(err));
+                     return err;
+             }
+
+             session->count = sh->ser[i].count;
+             session->files = sh->ser[i].files ? phys_to_virt(sh->ser[i].files) : 0;
+             session->pgcnt = sh->ser[i].pgcnt;
+     }
+
+     kho_restore_free(sh->header_ser);
+     sh->header_ser = NULL;
+     sh->ser = NULL;
+
+     return 0;
+}
[...]

--
Regards,
Pratyush Yadav
Thanks!

Pasha
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help