public inbox for linux-mm@kvack.org
 help / color / mirror / Atom feed
* [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API
@ 2026-03-27  3:33 Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 01/10] liveupdate: Safely print untrusted strings Pasha Tatashin
                   ` (10 more replies)
  0 siblings, 11 replies; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27  3:33 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

This patch series addresses an issue with how LUO handles module
reference counting and unregistration during a module unload (e.g.,
via rmmod).

Currently, modules that register live update file handlers are pinned
for the entire duration they are registered. This prevents the modules
from being unloaded gracefully, even when no live update session is in
progress.

Furthermore, if a module is forcefully unloaded, the unregistration
functions return an error (e.g. -EBUSY) if a session is active, which
is ignored by the kernel's module unload path, leaving dangling
pointers in the LUO global lists.

To resolve these issues, this series introduces the following changes:
1. Adds a global read-write semaphore (luo_register_rwlock) to protect
   the registration lists for both file handlers and FLBs.
2. Reduces the scope of module reference counting for file handlers and
   FLBs. Instead of pinning modules indefinitely upon registration,
   references are now taken only when they are actively used in a live
   update session (e.g., during preservation, retrieval, or
   deserialization).
3. Removes the global luo_session_quiesce() mechanism since module
   unload behavior now handles active sessions implicitly.
4. Introduces auto-unregistration of FLBs during file handler
   unregistration to prevent leaving dangling resources.
5. Changes the unregistration functions to return void instead of
   an error code.
6. Fixes a data race in luo_flb_get_private() by introducing a spinlock
   for thread-safe lazy initialization.
7. Strengthens security by using %.*s when printing untrusted deserialized
   compatible strings and session names to prevent out-of-bounds reads.

Changelog since v2:
- Reintroduced explicit module refcounting for file handlers from v1 to
  avoid problems during deserialization time and for overall simplicity.
- Simplified the locking model by consolidating luo_file_handler_lock,
  luo_flb_lock, and per-handler flb_lock into a single luo_register_rwlock,
  based on a suggestion from Samiullah Khawaja.
- Replaced scoped_guard() with explicit down/up lock calls in cases where
  goto is used for error handling, as suggested by Mike Rapoport.
- Also add to small hardening fixes: Synchronize lazy initialization of
  FLB private state and Safely print untrusted strings.

[1] https://lore.kernel.org/all/20260303210733.GG972761@nvidia.com
[2] https://lore.kernel.org/all/20260318141637.1870220-10-pasha.tatashin@soleen.com

Pasha Tatashin (10):
  liveupdate: Safely print untrusted strings
  liveupdate: Synchronize lazy initialization of FLB private state
  liveupdate: Protect file handler list with rwsem
  liveupdate: Protect FLB lists with luo_register_rwlock
  liveupdate: Defer FLB module refcounting to active sessions
  liveupdate: Remove luo_session_quiesce()
  liveupdate: Auto unregister FLBs on file handler unregistration
  liveupdate: Remove liveupdate_test_unregister()
  liveupdate: Make unregister functions return void
  liveupdate: Defer file handler module refcounting to active sessions

 include/linux/liveupdate.h       |  15 ++-
 kernel/liveupdate/luo_core.c     |   6 +
 kernel/liveupdate/luo_file.c     |  82 +++++---------
 kernel/liveupdate/luo_flb.c      | 182 ++++++++++++++++---------------
 kernel/liveupdate/luo_internal.h |   7 +-
 kernel/liveupdate/luo_session.c  |  46 +-------
 lib/tests/liveupdate.c           |  18 ---
 7 files changed, 142 insertions(+), 214 deletions(-)


base-commit: 4f1d805a97d6353e4ae468b08ca212641cd26f92
-- 
2.43.0



^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v3 01/10] liveupdate: Safely print untrusted strings
  2026-03-27  3:33 [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Pasha Tatashin
@ 2026-03-27  3:33 ` Pasha Tatashin
  2026-03-27 13:16   ` Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 02/10] liveupdate: Synchronize lazy initialization of FLB private state Pasha Tatashin
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27  3:33 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

Deserialized strings from KHO data (such as file handler compatible
strings and session names) are provided by the previous kernel and
might not be null-terminated if the data is corrupted or maliciously
crafted.

When printing these strings in error messages, use the %.*s format
specifier with the maximum buffer size to prevent out-of-bounds reads
into adjacent kernel memory.

Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
 kernel/liveupdate/luo_file.c    | 3 ++-
 kernel/liveupdate/luo_session.c | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index 5acee4174bf0..a6d98fc75d25 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -785,7 +785,8 @@ int luo_file_deserialize(struct luo_file_set *file_set,
 		}
 
 		if (!handler_found) {
-			pr_warn("No registered handler for compatible '%s'\n",
+			pr_warn("No registered handler for compatible '%.*s'\n",
+				(int)sizeof(file_ser[i].compatible),
 				file_ser[i].compatible);
 			return -ENOENT;
 		}
diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c
index 25ae704d7787..8c76dece679b 100644
--- a/kernel/liveupdate/luo_session.c
+++ b/kernel/liveupdate/luo_session.c
@@ -544,7 +544,8 @@ int luo_session_deserialize(void)
 
 		session = luo_session_alloc(sh->ser[i].name);
 		if (IS_ERR(session)) {
-			pr_warn("Failed to allocate session [%s] during deserialization %pe\n",
+			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);
 		}
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 02/10] liveupdate: Synchronize lazy initialization of FLB private state
  2026-03-27  3:33 [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 01/10] liveupdate: Safely print untrusted strings Pasha Tatashin
@ 2026-03-27  3:33 ` Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 03/10] liveupdate: Protect file handler list with rwsem Pasha Tatashin
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27  3:33 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

The luo_flb_get_private() function, which is responsible for lazily
initializing the private state of FLB objects, can be called
concurrently from multiple threads. This creates a data
race on the 'initialized' flag and can lead to multiple executions of
mutex_init() and INIT_LIST_HEAD() on the same memory.

Introduce a static spinlock (luo_flb_init_lock) local to the function
to synchronize the initialization path. Use smp_load_acquire() and
smp_store_release() for memory ordering between the fast path and the
slow path.

Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
 kernel/liveupdate/luo_flb.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
index 855af655b09b..317c02a94da5 100644
--- a/kernel/liveupdate/luo_flb.c
+++ b/kernel/liveupdate/luo_flb.c
@@ -89,13 +89,18 @@ struct luo_flb_link {
 static struct luo_flb_private *luo_flb_get_private(struct liveupdate_flb *flb)
 {
 	struct luo_flb_private *private = &ACCESS_PRIVATE(flb, private);
+	static DEFINE_SPINLOCK(luo_flb_init_lock);
 
+	if (smp_load_acquire(&private->initialized))
+		return private;
+
+	guard(spinlock)(&luo_flb_init_lock);
 	if (!private->initialized) {
 		mutex_init(&private->incoming.lock);
 		mutex_init(&private->outgoing.lock);
 		INIT_LIST_HEAD(&private->list);
 		private->users = 0;
-		private->initialized = true;
+		smp_store_release(&private->initialized, true);
 	}
 
 	return private;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 03/10] liveupdate: Protect file handler list with rwsem
  2026-03-27  3:33 [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 01/10] liveupdate: Safely print untrusted strings Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 02/10] liveupdate: Synchronize lazy initialization of FLB private state Pasha Tatashin
@ 2026-03-27  3:33 ` Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 04/10] liveupdate: Protect FLB lists with luo_register_rwlock Pasha Tatashin
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27  3:33 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

Because liveupdate file handlers will no longer hold a module reference
when registered, we must ensure that the access to the handler list is
protected against concurrent module unloading.

Utilize the global luo_register_rwlock to protect the global registry of
file handlers. Read locks are taken during list traversals in
luo_preserve_file() and luo_file_deserialize(). Write locks are taken
during registration and unregistration.

Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
 kernel/liveupdate/luo_core.c     |  6 ++++++
 kernel/liveupdate/luo_file.c     | 22 +++++++++++++++++-----
 kernel/liveupdate/luo_internal.h |  2 ++
 3 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c
index dda7bb57d421..f9ae9364a962 100644
--- a/kernel/liveupdate/luo_core.c
+++ b/kernel/liveupdate/luo_core.c
@@ -54,6 +54,7 @@
 #include <linux/liveupdate.h>
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
+#include <linux/rwsem.h>
 #include <linux/sizes.h>
 #include <linux/string.h>
 #include <linux/unaligned.h>
@@ -68,6 +69,11 @@ static struct {
 	u64 liveupdate_num;
 } luo_global;
 
+/*
+ * luo_register_rwlock - Protects registration of file handlers and FLBs.
+ */
+DECLARE_RWSEM(luo_register_rwlock);
+
 static int __init early_liveupdate_param(char *buf)
 {
 	return kstrtobool(buf, &luo_global.enabled);
diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index a6d98fc75d25..4aea17a94b4f 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -277,12 +277,14 @@ int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
 		goto  err_fput;
 
 	err = -ENOENT;
+	down_read(&luo_register_rwlock);
 	list_private_for_each_entry(fh, &luo_file_handler_list, list) {
 		if (fh->ops->can_preserve(fh, file)) {
 			err = 0;
 			break;
 		}
 	}
+	up_read(&luo_register_rwlock);
 
 	/* err is still -ENOENT if no handler was found */
 	if (err)
@@ -777,12 +779,14 @@ int luo_file_deserialize(struct luo_file_set *file_set,
 		bool handler_found = 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)) {
 				handler_found = true;
 				break;
 			}
 		}
+		up_read(&luo_register_rwlock);
 
 		if (!handler_found) {
 			pr_warn("No registered handler for compatible '%.*s'\n",
@@ -851,32 +855,36 @@ int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
 	if (!luo_session_quiesce())
 		return -EBUSY;
 
+	down_write(&luo_register_rwlock);
 	/* Check for duplicate compatible strings */
 	list_private_for_each_entry(fh_iter, &luo_file_handler_list, list) {
 		if (!strcmp(fh_iter->compatible, fh->compatible)) {
 			pr_err("File handler registration failed: Compatible string '%s' already registered.\n",
 			       fh->compatible);
 			err = -EEXIST;
-			goto err_resume;
+			goto err_unlock;
 		}
 	}
 
 	/* Pin the module implementing the handler */
 	if (!try_module_get(fh->ops->owner)) {
 		err = -EAGAIN;
-		goto err_resume;
+		goto err_unlock;
 	}
 
 	INIT_LIST_HEAD(&ACCESS_PRIVATE(fh, flb_list));
 	INIT_LIST_HEAD(&ACCESS_PRIVATE(fh, list));
 	list_add_tail(&ACCESS_PRIVATE(fh, list), &luo_file_handler_list);
+	up_write(&luo_register_rwlock);
+
 	luo_session_resume();
 
 	liveupdate_test_register(fh);
 
 	return 0;
 
-err_resume:
+err_unlock:
+	up_write(&luo_register_rwlock);
 	luo_session_resume();
 	return err;
 }
@@ -910,16 +918,20 @@ int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
 	if (!luo_session_quiesce())
 		goto err_register;
 
+	down_write(&luo_register_rwlock);
 	if (!list_empty(&ACCESS_PRIVATE(fh, flb_list)))
-		goto err_resume;
+		goto err_unlock;
 
 	list_del(&ACCESS_PRIVATE(fh, list));
+	up_write(&luo_register_rwlock);
+
 	module_put(fh->ops->owner);
 	luo_session_resume();
 
 	return 0;
 
-err_resume:
+err_unlock:
+	up_write(&luo_register_rwlock);
 	luo_session_resume();
 err_register:
 	liveupdate_test_register(fh);
diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h
index 8083d8739b09..4bfe00ac8866 100644
--- a/kernel/liveupdate/luo_internal.h
+++ b/kernel/liveupdate/luo_internal.h
@@ -77,6 +77,8 @@ struct luo_session {
 	struct mutex mutex;
 };
 
+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(void *fdt);
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 04/10] liveupdate: Protect FLB lists with luo_register_rwlock
  2026-03-27  3:33 [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Pasha Tatashin
                   ` (2 preceding siblings ...)
  2026-03-27  3:33 ` [PATCH v3 03/10] liveupdate: Protect file handler list with rwsem Pasha Tatashin
@ 2026-03-27  3:33 ` Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 05/10] liveupdate: Defer FLB module refcounting to active sessions Pasha Tatashin
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27  3:33 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

Because liveupdate FLB objects will soon drop their persistent module
references when registered, list traversals must be protected against
concurrent module unloading.

To provide this protection, utilize the global luo_register_rwlock.
It protects the global registry of FLBs and the handler's specific
list of FLB dependencies.

Read locks are used during concurrent list traversals (e.g., during
preservation and serialization). Write locks are taken during registration
and unregistration.

Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
 include/linux/liveupdate.h  |  1 +
 kernel/liveupdate/luo_flb.c | 14 ++++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
index dd11fdc76a5f..73ca84de3eae 100644
--- a/include/linux/liveupdate.h
+++ b/include/linux/liveupdate.h
@@ -12,6 +12,7 @@
 #include <linux/kho/abi/luo.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
+#include <linux/rwsem.h>
 #include <linux/types.h>
 #include <uapi/linux/liveupdate.h>
 
diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
index 317c02a94da5..3c91d0008eb1 100644
--- a/kernel/liveupdate/luo_flb.c
+++ b/kernel/liveupdate/luo_flb.c
@@ -262,17 +262,20 @@ int luo_flb_file_preserve(struct liveupdate_file_handler *fh)
 	struct luo_flb_link *iter;
 	int err = 0;
 
+	down_read(&luo_register_rwlock);
 	list_for_each_entry(iter, flb_list, list) {
 		err = luo_flb_file_preserve_one(iter->flb);
 		if (err)
 			goto exit_err;
 	}
+	up_read(&luo_register_rwlock);
 
 	return 0;
 
 exit_err:
 	list_for_each_entry_continue_reverse(iter, flb_list, list)
 		luo_flb_file_unpreserve_one(iter->flb);
+	up_read(&luo_register_rwlock);
 
 	return err;
 }
@@ -294,6 +297,7 @@ void luo_flb_file_unpreserve(struct liveupdate_file_handler *fh)
 	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
 	struct luo_flb_link *iter;
 
+	guard(rwsem_read)(&luo_register_rwlock);
 	list_for_each_entry_reverse(iter, flb_list, list)
 		luo_flb_file_unpreserve_one(iter->flb);
 }
@@ -314,6 +318,7 @@ void luo_flb_file_finish(struct liveupdate_file_handler *fh)
 	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
 	struct luo_flb_link *iter;
 
+	guard(rwsem_read)(&luo_register_rwlock);
 	list_for_each_entry_reverse(iter, flb_list, list)
 		luo_flb_file_finish_one(iter->flb);
 }
@@ -377,6 +382,8 @@ int liveupdate_register_flb(struct liveupdate_file_handler *fh,
 	if (!luo_session_quiesce())
 		return -EBUSY;
 
+	down_write(&luo_register_rwlock);
+
 	/* Check that this FLB is not already linked to this file handler */
 	err = -EEXIST;
 	list_for_each_entry(iter, flb_list, list) {
@@ -418,11 +425,13 @@ int liveupdate_register_flb(struct liveupdate_file_handler *fh,
 	private->users++;
 	link->flb = flb;
 	list_add_tail(&no_free_ptr(link)->list, flb_list);
+	up_write(&luo_register_rwlock);
 	luo_session_resume();
 
 	return 0;
 
 err_resume:
+	up_write(&luo_register_rwlock);
 	luo_session_resume();
 	return err;
 }
@@ -466,6 +475,8 @@ int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
 	if (!luo_session_quiesce())
 		return -EBUSY;
 
+	down_write(&luo_register_rwlock);
+
 	/* Find and remove the link from the file handler's list */
 	list_for_each_entry(iter, flb_list, list) {
 		if (iter->flb == flb) {
@@ -490,11 +501,13 @@ int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
 		module_put(flb->ops->owner);
 	}
 
+	up_write(&luo_register_rwlock);
 	luo_session_resume();
 
 	return 0;
 
 err_resume:
+	up_write(&luo_register_rwlock);
 	luo_session_resume();
 	return err;
 }
@@ -660,6 +673,7 @@ void luo_flb_serialize(void)
 	struct liveupdate_flb *gflb;
 	int i = 0;
 
+	guard(rwsem_read)(&luo_register_rwlock);
 	list_private_for_each_entry(gflb, &luo_flb_global.list, private.list) {
 		struct luo_flb_private *private = luo_flb_get_private(gflb);
 
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 05/10] liveupdate: Defer FLB module refcounting to active sessions
  2026-03-27  3:33 [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Pasha Tatashin
                   ` (3 preceding siblings ...)
  2026-03-27  3:33 ` [PATCH v3 04/10] liveupdate: Protect FLB lists with luo_register_rwlock Pasha Tatashin
@ 2026-03-27  3:33 ` Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 06/10] liveupdate: Remove luo_session_quiesce() Pasha Tatashin
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27  3:33 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

Stop pinning modules indefinitely upon FLB registration.
Instead, dynamically take a module reference when the FLB is actively
used in a session (e.g., during preserve and retrieve) and release it
when the session concludes.

This allows modules providing FLB operations to be cleanly unloaded
when not in active use by the live update orchestrator.

Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
 kernel/liveupdate/luo_flb.c | 27 +++++++++++++++++----------
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
index 3c91d0008eb1..ce28ce9b113e 100644
--- a/kernel/liveupdate/luo_flb.c
+++ b/kernel/liveupdate/luo_flb.c
@@ -115,10 +115,15 @@ static int luo_flb_file_preserve_one(struct liveupdate_flb *flb)
 			struct liveupdate_flb_op_args args = {0};
 			int err;
 
+			if (!try_module_get(flb->ops->owner))
+				return -ENODEV;
+
 			args.flb = flb;
 			err = flb->ops->preserve(&args);
-			if (err)
+			if (err) {
+				module_put(flb->ops->owner);
 				return err;
+			}
 			private->outgoing.data = args.data;
 			private->outgoing.obj = args.obj;
 		}
@@ -146,6 +151,7 @@ static void luo_flb_file_unpreserve_one(struct liveupdate_flb *flb)
 
 			private->outgoing.data = 0;
 			private->outgoing.obj = NULL;
+			module_put(flb->ops->owner);
 		}
 	}
 }
@@ -181,12 +187,17 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
 	if (!found)
 		return -ENOENT;
 
+	if (!try_module_get(flb->ops->owner))
+		return -ENODEV;
+
 	args.flb = flb;
 	args.data = private->incoming.data;
 
 	err = flb->ops->retrieve(&args);
-	if (err)
+	if (err) {
+		module_put(flb->ops->owner);
 		return err;
+	}
 
 	private->incoming.obj = args.obj;
 	private->incoming.retrieved = true;
@@ -237,6 +248,7 @@ static void luo_flb_file_finish_one(struct liveupdate_flb *flb)
 			private->incoming.data = 0;
 			private->incoming.obj = NULL;
 			private->incoming.finished = true;
+			module_put(flb->ops->owner);
 		}
 	}
 }
@@ -412,11 +424,6 @@ int liveupdate_register_flb(struct liveupdate_file_handler *fh,
 				goto err_resume;
 		}
 
-		if (!try_module_get(flb->ops->owner)) {
-			err = -EAGAIN;
-			goto err_resume;
-		}
-
 		list_add_tail(&private->list, &luo_flb_global.list);
 		luo_flb_global.count++;
 	}
@@ -493,12 +500,11 @@ int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
 	private->users--;
 	/*
 	 * If this is the last file-handler with which we are registred, remove
-	 * from the global list, and relese module reference.
+	 * from the global list.
 	 */
 	if (!private->users) {
 		list_del_init(&private->list);
 		luo_flb_global.count--;
-		module_put(flb->ops->owner);
 	}
 
 	up_write(&luo_register_rwlock);
@@ -527,7 +533,8 @@ int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
  *
  * Return: 0 on success, or a negative errno on failure. -ENODATA means no
  * incoming FLB data, -ENOENT means specific flb not found in the incoming
- * data, and -EOPNOTSUPP when live update is disabled or not configured.
+ * data, -ENODEV if the FLB's module is unloading, and -EOPNOTSUPP when
+ * live update is disabled or not configured.
  */
 int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp)
 {
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 06/10] liveupdate: Remove luo_session_quiesce()
  2026-03-27  3:33 [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Pasha Tatashin
                   ` (4 preceding siblings ...)
  2026-03-27  3:33 ` [PATCH v3 05/10] liveupdate: Defer FLB module refcounting to active sessions Pasha Tatashin
@ 2026-03-27  3:33 ` Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 07/10] liveupdate: Auto unregister FLBs on file handler unregistration Pasha Tatashin
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27  3:33 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

Now that FLB module references are handled dynamically during active
sessions, we can safely remove the luo_session_quiesce() and
luo_session_resume() mechanism.

Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
 kernel/liveupdate/luo_file.c     | 21 +-----------
 kernel/liveupdate/luo_flb.c      | 59 ++++++--------------------------
 kernel/liveupdate/luo_internal.h |  2 --
 kernel/liveupdate/luo_session.c  | 43 -----------------------
 4 files changed, 11 insertions(+), 114 deletions(-)

diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index 4aea17a94b4f..439177c10723 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -847,14 +847,6 @@ int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
 		return -EINVAL;
 	}
 
-	/*
-	 * Ensure the system is quiescent (no active sessions).
-	 * This prevents registering new handlers while sessions are active or
-	 * while deserialization is in progress.
-	 */
-	if (!luo_session_quiesce())
-		return -EBUSY;
-
 	down_write(&luo_register_rwlock);
 	/* Check for duplicate compatible strings */
 	list_private_for_each_entry(fh_iter, &luo_file_handler_list, list) {
@@ -877,15 +869,12 @@ int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
 	list_add_tail(&ACCESS_PRIVATE(fh, list), &luo_file_handler_list);
 	up_write(&luo_register_rwlock);
 
-	luo_session_resume();
-
 	liveupdate_test_register(fh);
 
 	return 0;
 
 err_unlock:
 	up_write(&luo_register_rwlock);
-	luo_session_resume();
 	return err;
 }
 
@@ -897,14 +886,12 @@ int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
  * reverses the operations of liveupdate_register_file_handler().
  *
  * It ensures safe removal by checking that:
- * No live update session is currently in progress.
  * No FLB registered with this file handler.
  *
  * If the unregistration fails, the internal test state is reverted.
  *
  * Return: 0 Success. -EOPNOTSUPP when live update is not enabled. -EBUSY A live
- * update is in progress, can't quiesce live update or FLB is registred with
- * this file handler.
+ * update is in progress, FLB is registred with this file handler.
  */
 int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
 {
@@ -915,9 +902,6 @@ int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
 
 	liveupdate_test_unregister(fh);
 
-	if (!luo_session_quiesce())
-		goto err_register;
-
 	down_write(&luo_register_rwlock);
 	if (!list_empty(&ACCESS_PRIVATE(fh, flb_list)))
 		goto err_unlock;
@@ -926,14 +910,11 @@ int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
 	up_write(&luo_register_rwlock);
 
 	module_put(fh->ops->owner);
-	luo_session_resume();
 
 	return 0;
 
 err_unlock:
 	up_write(&luo_register_rwlock);
-	luo_session_resume();
-err_register:
 	liveupdate_test_register(fh);
 	return err;
 }
diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
index ce28ce9b113e..ac6fa5b34b43 100644
--- a/kernel/liveupdate/luo_flb.c
+++ b/kernel/liveupdate/luo_flb.c
@@ -365,7 +365,6 @@ int liveupdate_register_flb(struct liveupdate_file_handler *fh,
 	struct luo_flb_link *link __free(kfree) = NULL;
 	struct liveupdate_flb *gflb;
 	struct luo_flb_link *iter;
-	int err;
 
 	if (!liveupdate_enabled())
 		return -EOPNOTSUPP;
@@ -386,21 +385,12 @@ int liveupdate_register_flb(struct liveupdate_file_handler *fh,
 	if (!link)
 		return -ENOMEM;
 
-	/*
-	 * Ensure the system is quiescent (no active sessions).
-	 * This acts as a global lock for registration: no other thread can
-	 * be in this section, and no sessions can be creating/using FDs.
-	 */
-	if (!luo_session_quiesce())
-		return -EBUSY;
-
-	down_write(&luo_register_rwlock);
+	guard(rwsem_write)(&luo_register_rwlock);
 
 	/* Check that this FLB is not already linked to this file handler */
-	err = -EEXIST;
 	list_for_each_entry(iter, flb_list, list) {
 		if (iter->flb == flb)
-			goto err_resume;
+			return -EEXIST;
 	}
 
 	/*
@@ -408,20 +398,16 @@ int liveupdate_register_flb(struct liveupdate_file_handler *fh,
 	 * is registered
 	 */
 	if (!private->users) {
-		if (WARN_ON(!list_empty(&private->list))) {
-			err = -EINVAL;
-			goto err_resume;
-		}
+		if (WARN_ON(!list_empty(&private->list)))
+			return -EINVAL;
 
-		if (luo_flb_global.count == LUO_FLB_MAX) {
-			err = -ENOSPC;
-			goto err_resume;
-		}
+		if (luo_flb_global.count == LUO_FLB_MAX)
+			return -ENOSPC;
 
 		/* Check that compatible string is unique in global list */
 		list_private_for_each_entry(gflb, &luo_flb_global.list, private.list) {
 			if (!strcmp(gflb->compatible, flb->compatible))
-				goto err_resume;
+				return -EEXIST;
 		}
 
 		list_add_tail(&private->list, &luo_flb_global.list);
@@ -432,15 +418,8 @@ int liveupdate_register_flb(struct liveupdate_file_handler *fh,
 	private->users++;
 	link->flb = flb;
 	list_add_tail(&no_free_ptr(link)->list, flb_list);
-	up_write(&luo_register_rwlock);
-	luo_session_resume();
 
 	return 0;
-
-err_resume:
-	up_write(&luo_register_rwlock);
-	luo_session_resume();
-	return err;
 }
 
 /**
@@ -456,12 +435,9 @@ int liveupdate_register_flb(struct liveupdate_file_handler *fh,
  * the FLB is removed from the global registry and the reference to its
  * owner module (acquired during registration) is released.
  *
- * Context: This function ensures the session is quiesced (no active FDs
- *          being created) during the update. It is typically called from a
- *          subsystem's module exit function.
+ * Context: It is typically called from a subsystem's module exit function.
  * Return: 0 on success.
  *         -EOPNOTSUPP if live update is disabled.
- *         -EBUSY if the live update session is active and cannot be quiesced.
  *         -ENOENT if the FLB was not found in the file handler's list.
  */
 int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
@@ -475,14 +451,7 @@ int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
 	if (!liveupdate_enabled())
 		return -EOPNOTSUPP;
 
-	/*
-	 * Ensure the system is quiescent (no active sessions).
-	 * This acts as a global lock for unregistration.
-	 */
-	if (!luo_session_quiesce())
-		return -EBUSY;
-
-	down_write(&luo_register_rwlock);
+	guard(rwsem_write)(&luo_register_rwlock);
 
 	/* Find and remove the link from the file handler's list */
 	list_for_each_entry(iter, flb_list, list) {
@@ -495,7 +464,7 @@ int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
 	}
 
 	if (err)
-		goto err_resume;
+		return err;
 
 	private->users--;
 	/*
@@ -507,15 +476,7 @@ int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
 		luo_flb_global.count--;
 	}
 
-	up_write(&luo_register_rwlock);
-	luo_session_resume();
-
 	return 0;
-
-err_resume:
-	up_write(&luo_register_rwlock);
-	luo_session_resume();
-	return err;
 }
 
 /**
diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h
index 4bfe00ac8866..40a011bdfa55 100644
--- a/kernel/liveupdate/luo_internal.h
+++ b/kernel/liveupdate/luo_internal.h
@@ -85,8 +85,6 @@ int __init luo_session_setup_outgoing(void *fdt);
 int __init luo_session_setup_incoming(void *fdt);
 int luo_session_serialize(void);
 int luo_session_deserialize(void);
-bool luo_session_quiesce(void);
-void luo_session_resume(void);
 
 int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd);
 void luo_file_unpreserve_files(struct luo_file_set *file_set);
diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c
index 8c76dece679b..a3327a28fc1f 100644
--- a/kernel/liveupdate/luo_session.c
+++ b/kernel/liveupdate/luo_session.c
@@ -607,46 +607,3 @@ int luo_session_serialize(void)
 	return err;
 }
 
-/**
- * luo_session_quiesce - Ensure no active sessions exist and lock session lists.
- *
- * Acquires exclusive write locks on both incoming and outgoing session lists.
- * It then validates no sessions exist in either list.
- *
- * This mechanism is used during file handler un/registration to ensure that no
- * sessions are currently using the handler, and no new sessions can be created
- * while un/registration is in progress.
- *
- * This prevents registering new handlers while sessions are active or
- * while deserialization is in progress.
- *
- * Return:
- * true  - System is quiescent (0 sessions) and locked.
- * false - Active sessions exist. The locks are released internally.
- */
-bool luo_session_quiesce(void)
-{
-	down_write(&luo_session_global.incoming.rwsem);
-	down_write(&luo_session_global.outgoing.rwsem);
-
-	if (luo_session_global.incoming.count ||
-	    luo_session_global.outgoing.count) {
-		up_write(&luo_session_global.outgoing.rwsem);
-		up_write(&luo_session_global.incoming.rwsem);
-		return false;
-	}
-
-	return true;
-}
-
-/**
- * luo_session_resume - Unlock session lists and resume normal activity.
- *
- * Releases the exclusive locks acquired by a successful call to
- * luo_session_quiesce().
- */
-void luo_session_resume(void)
-{
-	up_write(&luo_session_global.outgoing.rwsem);
-	up_write(&luo_session_global.incoming.rwsem);
-}
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 07/10] liveupdate: Auto unregister FLBs on file handler unregistration
  2026-03-27  3:33 [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Pasha Tatashin
                   ` (5 preceding siblings ...)
  2026-03-27  3:33 ` [PATCH v3 06/10] liveupdate: Remove luo_session_quiesce() Pasha Tatashin
@ 2026-03-27  3:33 ` Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 08/10] liveupdate: Remove liveupdate_test_unregister() Pasha Tatashin
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27  3:33 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

To ensure that unregistration is always successful and doesn't leave
dangling resources, introduce auto-unregistration of FLBs: when a file
handler is unregistered, all FLBs associated with it are automatically
unregistered.

Introduce a new helper luo_flb_unregister_all() which unregisters all
FLBs linked to the given file handler.

Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
 kernel/liveupdate/luo_file.c     | 14 +-----
 kernel/liveupdate/luo_flb.c      | 84 ++++++++++++++++++++++----------
 kernel/liveupdate/luo_internal.h |  1 +
 3 files changed, 60 insertions(+), 39 deletions(-)

diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index 439177c10723..80f4e3b796a6 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -895,26 +895,16 @@ int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
  */
 int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
 {
-	int err = -EBUSY;
-
 	if (!liveupdate_enabled())
 		return -EOPNOTSUPP;
 
 	liveupdate_test_unregister(fh);
 
-	down_write(&luo_register_rwlock);
-	if (!list_empty(&ACCESS_PRIVATE(fh, flb_list)))
-		goto err_unlock;
-
+	guard(rwsem_write)(&luo_register_rwlock);
+	luo_flb_unregister_all(fh);
 	list_del(&ACCESS_PRIVATE(fh, list));
-	up_write(&luo_register_rwlock);
 
 	module_put(fh->ops->owner);
 
 	return 0;
-
-err_unlock:
-	up_write(&luo_register_rwlock);
-	liveupdate_test_register(fh);
-	return err;
 }
diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
index ac6fa5b34b43..f8348138de70 100644
--- a/kernel/liveupdate/luo_flb.c
+++ b/kernel/liveupdate/luo_flb.c
@@ -335,6 +335,62 @@ void luo_flb_file_finish(struct liveupdate_file_handler *fh)
 		luo_flb_file_finish_one(iter->flb);
 }
 
+static void luo_flb_unregister_one(struct liveupdate_file_handler *fh,
+				   struct liveupdate_flb *flb)
+{
+	struct luo_flb_private *private = luo_flb_get_private(flb);
+	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
+	struct luo_flb_link *iter;
+	bool found = false;
+
+	/* Find and remove the link from the file handler's list */
+	list_for_each_entry(iter, flb_list, list) {
+		if (iter->flb == flb) {
+			list_del(&iter->list);
+			kfree(iter);
+			found = true;
+			break;
+		}
+	}
+
+	if (!found) {
+		pr_warn("Failed to unregister FLB '%s': not found in file handler '%s'\n",
+			flb->compatible, fh->compatible);
+		return;
+	}
+
+	private->users--;
+
+	/*
+	 * If this is the last file-handler with which we are registred, remove
+	 * from the global list.
+	 */
+	if (!private->users) {
+		list_del_init(&private->list);
+		luo_flb_global.count--;
+	}
+}
+
+/**
+ * luo_flb_unregister_all - Unregister all FLBs associated with a file handler.
+ * @fh: The file handler whose FLBs should be unregistered.
+ *
+ * This function iterates through the list of FLBs associated with the given
+ * file handler and unregisters them all one by one.
+ */
+void luo_flb_unregister_all(struct liveupdate_file_handler *fh)
+{
+	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
+	struct luo_flb_link *iter, *tmp;
+
+	if (!liveupdate_enabled())
+		return;
+
+	lockdep_assert_held_write(&luo_register_rwlock);
+	list_for_each_entry_safe(iter, tmp, flb_list, list)
+		luo_flb_unregister_one(fh, iter->flb);
+}
+
 /**
  * liveupdate_register_flb - Associate an FLB with a file handler and register it globally.
  * @fh:   The file handler that will now depend on the FLB.
@@ -443,38 +499,12 @@ int liveupdate_register_flb(struct liveupdate_file_handler *fh,
 int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
 			      struct liveupdate_flb *flb)
 {
-	struct luo_flb_private *private = luo_flb_get_private(flb);
-	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
-	struct luo_flb_link *iter;
-	int err = -ENOENT;
-
 	if (!liveupdate_enabled())
 		return -EOPNOTSUPP;
 
 	guard(rwsem_write)(&luo_register_rwlock);
 
-	/* Find and remove the link from the file handler's list */
-	list_for_each_entry(iter, flb_list, list) {
-		if (iter->flb == flb) {
-			list_del(&iter->list);
-			kfree(iter);
-			err = 0;
-			break;
-		}
-	}
-
-	if (err)
-		return err;
-
-	private->users--;
-	/*
-	 * If this is the last file-handler with which we are registred, remove
-	 * from the global list.
-	 */
-	if (!private->users) {
-		list_del_init(&private->list);
-		luo_flb_global.count--;
-	}
+	luo_flb_unregister_one(fh, flb);
 
 	return 0;
 }
diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h
index 40a011bdfa55..22f6901f89ed 100644
--- a/kernel/liveupdate/luo_internal.h
+++ b/kernel/liveupdate/luo_internal.h
@@ -103,6 +103,7 @@ void luo_file_set_destroy(struct luo_file_set *file_set);
 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);
+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);
 void luo_flb_serialize(void);
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 08/10] liveupdate: Remove liveupdate_test_unregister()
  2026-03-27  3:33 [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Pasha Tatashin
                   ` (6 preceding siblings ...)
  2026-03-27  3:33 ` [PATCH v3 07/10] liveupdate: Auto unregister FLBs on file handler unregistration Pasha Tatashin
@ 2026-03-27  3:33 ` Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 09/10] liveupdate: Make unregister functions return void Pasha Tatashin
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27  3:33 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

Now that file handler unregistration automatically unregisters all
associated file handlers (FLBs), the liveupdate_test_unregister()
function is no longer needed. Remove it along with its usages
and declarations.

Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
 kernel/liveupdate/luo_file.c     |  2 --
 kernel/liveupdate/luo_internal.h |  2 --
 lib/tests/liveupdate.c           | 18 ------------------
 3 files changed, 22 deletions(-)

diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index 80f4e3b796a6..dd55e5e74d69 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -898,8 +898,6 @@ int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
 	if (!liveupdate_enabled())
 		return -EOPNOTSUPP;
 
-	liveupdate_test_unregister(fh);
-
 	guard(rwsem_write)(&luo_register_rwlock);
 	luo_flb_unregister_all(fh);
 	list_del(&ACCESS_PRIVATE(fh, list));
diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h
index 22f6901f89ed..875844d7a41d 100644
--- a/kernel/liveupdate/luo_internal.h
+++ b/kernel/liveupdate/luo_internal.h
@@ -110,10 +110,8 @@ void luo_flb_serialize(void);
 
 #ifdef CONFIG_LIVEUPDATE_TEST
 void liveupdate_test_register(struct liveupdate_file_handler *fh);
-void liveupdate_test_unregister(struct liveupdate_file_handler *fh);
 #else
 static inline void liveupdate_test_register(struct liveupdate_file_handler *fh) { }
-static inline void liveupdate_test_unregister(struct liveupdate_file_handler *fh) { }
 #endif
 
 #endif /* _LINUX_LUO_INTERNAL_H */
diff --git a/lib/tests/liveupdate.c b/lib/tests/liveupdate.c
index 496d6ef91a30..e4b0ecbee32f 100644
--- a/lib/tests/liveupdate.c
+++ b/lib/tests/liveupdate.c
@@ -135,24 +135,6 @@ void liveupdate_test_register(struct liveupdate_file_handler *fh)
 		TEST_NFLBS, fh->compatible);
 }
 
-void liveupdate_test_unregister(struct liveupdate_file_handler *fh)
-{
-	int err, i;
-
-	for (i = 0; i < TEST_NFLBS; i++) {
-		struct liveupdate_flb *flb = &test_flbs[i];
-
-		err = liveupdate_unregister_flb(fh, flb);
-		if (err) {
-			pr_err("Failed to unregister %s %pe\n",
-			       flb->compatible, ERR_PTR(err));
-		}
-	}
-
-	pr_info("Unregistered %d FLBs from file handler: [%s]\n",
-		TEST_NFLBS, fh->compatible);
-}
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Pasha Tatashin <pasha.tatashin@soleen.com>");
 MODULE_DESCRIPTION("In-kernel test for LUO mechanism");
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 09/10] liveupdate: Make unregister functions return void
  2026-03-27  3:33 [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Pasha Tatashin
                   ` (7 preceding siblings ...)
  2026-03-27  3:33 ` [PATCH v3 08/10] liveupdate: Remove liveupdate_test_unregister() Pasha Tatashin
@ 2026-03-27  3:33 ` Pasha Tatashin
  2026-03-27 14:41   ` Pasha Tatashin
  2026-03-27  3:33 ` [PATCH v3 10/10] liveupdate: Defer file handler module refcounting to active sessions Pasha Tatashin
  2026-03-27 17:24 ` [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Andrew Morton
  10 siblings, 1 reply; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27  3:33 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

Change liveupdate_unregister_file_handler and liveupdate_unregister_flb
to return void instead of an error code. This follows the design
principle that unregistration during module unload should not fail,
as the unload cannot be stopped at that point.

Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
 include/linux/liveupdate.h   | 14 ++++++--------
 kernel/liveupdate/luo_file.c | 14 ++------------
 kernel/liveupdate/luo_flb.c  | 11 +++--------
 3 files changed, 11 insertions(+), 28 deletions(-)

diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
index 73ca84de3eae..2ae27711ac41 100644
--- a/include/linux/liveupdate.h
+++ b/include/linux/liveupdate.h
@@ -229,12 +229,12 @@ bool liveupdate_enabled(void);
 int liveupdate_reboot(void);
 
 int liveupdate_register_file_handler(struct liveupdate_file_handler *fh);
-int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh);
+void liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh);
 
 int liveupdate_register_flb(struct liveupdate_file_handler *fh,
 			    struct liveupdate_flb *flb);
-int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
-			      struct liveupdate_flb *flb);
+void liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
+			       struct liveupdate_flb *flb);
 
 int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp);
 int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp);
@@ -256,9 +256,8 @@ static inline int liveupdate_register_file_handler(struct liveupdate_file_handle
 	return -EOPNOTSUPP;
 }
 
-static inline int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
+static inline void liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
 {
-	return -EOPNOTSUPP;
 }
 
 static inline int liveupdate_register_flb(struct liveupdate_file_handler *fh,
@@ -267,10 +266,9 @@ static inline int liveupdate_register_flb(struct liveupdate_file_handler *fh,
 	return -EOPNOTSUPP;
 }
 
-static inline int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
-					    struct liveupdate_flb *flb)
+static inline void liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
+					     struct liveupdate_flb *flb)
 {
-	return -EOPNOTSUPP;
 }
 
 static inline int liveupdate_flb_get_incoming(struct liveupdate_flb *flb,
diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index dd55e5e74d69..761e8f7cfc82 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -884,25 +884,15 @@ int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
  *
  * Unregisters the file handler from the liveupdate core. This function
  * reverses the operations of liveupdate_register_file_handler().
- *
- * It ensures safe removal by checking that:
- * No FLB registered with this file handler.
- *
- * If the unregistration fails, the internal test state is reverted.
- *
- * Return: 0 Success. -EOPNOTSUPP when live update is not enabled. -EBUSY A live
- * update is in progress, FLB is registred with this file handler.
  */
-int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
+void liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
 {
 	if (!liveupdate_enabled())
-		return -EOPNOTSUPP;
+		return;
 
 	guard(rwsem_write)(&luo_register_rwlock);
 	luo_flb_unregister_all(fh);
 	list_del(&ACCESS_PRIVATE(fh, list));
 
 	module_put(fh->ops->owner);
-
-	return 0;
 }
diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
index f8348138de70..8f3c9c63e320 100644
--- a/kernel/liveupdate/luo_flb.c
+++ b/kernel/liveupdate/luo_flb.c
@@ -492,21 +492,16 @@ int liveupdate_register_flb(struct liveupdate_file_handler *fh,
  * owner module (acquired during registration) is released.
  *
  * Context: It is typically called from a subsystem's module exit function.
- * Return: 0 on success.
- *         -EOPNOTSUPP if live update is disabled.
- *         -ENOENT if the FLB was not found in the file handler's list.
  */
-int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
-			      struct liveupdate_flb *flb)
+void liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
+			       struct liveupdate_flb *flb)
 {
 	if (!liveupdate_enabled())
-		return -EOPNOTSUPP;
+		return;
 
 	guard(rwsem_write)(&luo_register_rwlock);
 
 	luo_flb_unregister_one(fh, flb);
-
-	return 0;
 }
 
 /**
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 10/10] liveupdate: Defer file handler module refcounting to active sessions
  2026-03-27  3:33 [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Pasha Tatashin
                   ` (8 preceding siblings ...)
  2026-03-27  3:33 ` [PATCH v3 09/10] liveupdate: Make unregister functions return void Pasha Tatashin
@ 2026-03-27  3:33 ` Pasha Tatashin
  2026-03-27 17:14   ` Andrew Morton
  2026-03-27 17:24 ` [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Andrew Morton
  10 siblings, 1 reply; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27  3:33 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

Stop pinning modules indefinitely upon file handler registration.
Instead, dynamically increment the module reference count only when a
live update session actively uses the file handler (e.g., during
preservation or deserialization), and release it when the session ends.

This allows modules providing live update handlers to be gracefully
unloaded when no live update is in progress.

Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
 kernel/liveupdate/luo_file.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index 761e8f7cfc82..619465358798 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -280,7 +280,8 @@ int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
 	down_read(&luo_register_rwlock);
 	list_private_for_each_entry(fh, &luo_file_handler_list, list) {
 		if (fh->ops->can_preserve(fh, file)) {
-			err = 0;
+			if (try_module_get(fh->ops->owner))
+				err = 0;
 			break;
 		}
 	}
@@ -292,7 +293,7 @@ int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
 
 	err = luo_flb_file_preserve(fh);
 	if (err)
-		goto err_free_files_mem;
+		goto err_module_put;
 
 	luo_file = kzalloc_obj(*luo_file);
 	if (!luo_file) {
@@ -322,6 +323,8 @@ int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
 	kfree(luo_file);
 err_flb_unpreserve:
 	luo_flb_file_unpreserve(fh);
+err_module_put:
+	module_put(fh->ops->owner);
 err_free_files_mem:
 	luo_free_files_mem(file_set);
 err_fput:
@@ -364,6 +367,7 @@ void luo_file_unpreserve_files(struct luo_file_set *file_set)
 		args.private_data = luo_file->private_data;
 		luo_file->fh->ops->unpreserve(&args);
 		luo_flb_file_unpreserve(luo_file->fh);
+		module_put(luo_file->fh->ops->owner);
 
 		list_del(&luo_file->list);
 		file_set->count--;
@@ -648,6 +652,7 @@ static void luo_file_finish_one(struct luo_file_set *file_set,
 
 	luo_file->fh->ops->finish(&args);
 	luo_flb_file_finish(luo_file->fh);
+	module_put(luo_file->fh->ops->owner);
 }
 
 /**
@@ -782,7 +787,8 @@ int luo_file_deserialize(struct luo_file_set *file_set,
 		down_read(&luo_register_rwlock);
 		list_private_for_each_entry(fh, &luo_file_handler_list, list) {
 			if (!strcmp(fh->compatible, file_ser[i].compatible)) {
-				handler_found = true;
+				if (try_module_get(fh->ops->owner))
+					handler_found = true;
 				break;
 			}
 		}
@@ -796,8 +802,10 @@ int luo_file_deserialize(struct luo_file_set *file_set,
 		}
 
 		luo_file = kzalloc_obj(*luo_file);
-		if (!luo_file)
+		if (!luo_file) {
+			module_put(fh->ops->owner);
 			return -ENOMEM;
+		}
 
 		luo_file->fh = fh;
 		luo_file->file = NULL;
@@ -858,12 +866,6 @@ int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
 		}
 	}
 
-	/* Pin the module implementing the handler */
-	if (!try_module_get(fh->ops->owner)) {
-		err = -EAGAIN;
-		goto err_unlock;
-	}
-
 	INIT_LIST_HEAD(&ACCESS_PRIVATE(fh, flb_list));
 	INIT_LIST_HEAD(&ACCESS_PRIVATE(fh, list));
 	list_add_tail(&ACCESS_PRIVATE(fh, list), &luo_file_handler_list);
@@ -893,6 +895,4 @@ void liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
 	guard(rwsem_write)(&luo_register_rwlock);
 	luo_flb_unregister_all(fh);
 	list_del(&ACCESS_PRIVATE(fh, list));
-
-	module_put(fh->ops->owner);
 }
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 01/10] liveupdate: Safely print untrusted strings
  2026-03-27  3:33 ` [PATCH v3 01/10] liveupdate: Safely print untrusted strings Pasha Tatashin
@ 2026-03-27 13:16   ` Pasha Tatashin
  0 siblings, 0 replies; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27 13:16 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

On Thu, Mar 26, 2026 at 11:33 PM Pasha Tatashin
<pasha.tatashin@soleen.com> wrote:
>
> Deserialized strings from KHO data (such as file handler compatible
> strings and session names) are provided by the previous kernel and
> might not be null-terminated if the data is corrupted or maliciously
> crafted.
>
> When printing these strings in error messages, use the %.*s format
> specifier with the maximum buffer size to prevent out-of-bounds reads
> into adjacent kernel memory.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> ---
>  kernel/liveupdate/luo_file.c    | 3 ++-
>  kernel/liveupdate/luo_session.c | 3 ++-
>  2 files changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
> index 5acee4174bf0..a6d98fc75d25 100644
> --- a/kernel/liveupdate/luo_file.c
> +++ b/kernel/liveupdate/luo_file.c
> @@ -785,7 +785,8 @@ int luo_file_deserialize(struct luo_file_set *file_set,
>                 }
>
>                 if (!handler_found) {
> -                       pr_warn("No registered handler for compatible '%s'\n",
> +                       pr_warn("No registered handler for compatible '%.*s'\n",
> +                               (int)sizeof(file_ser[i].compatible),
>                                 file_ser[i].compatible);
>                         return -ENOENT;
>                 }
> diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c
> index 25ae704d7787..8c76dece679b 100644
> --- a/kernel/liveupdate/luo_session.c
> +++ b/kernel/liveupdate/luo_session.c
> @@ -544,7 +544,8 @@ int luo_session_deserialize(void)
>
>                 session = luo_session_alloc(sh->ser[i].name);
>                 if (IS_ERR(session)) {
> -                       pr_warn("Failed to allocate session [%s] during deserialization %pe\n",
> +                       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);
>                 }

Lol, Sashiko went a little overboard and gave this patch two
"Critical" findings:

1. If a registered file handler uses a compatible string equal to or longer than
the buffer, and the untrusted string matches it without a null terminator,
strcmp() could read past the bounds of file_ser[i].compatible.

B.S.: The length of the string is ABI, and fh->compatible is a
NULL-terminated string provided by the current kernel. In the future,
we can replace strcmp() with strncmp(), but it is not a high-priority
issue.

2. By returning PTR_ERR(session) directly without updating the static err
variable, subsequent calls will see is_deserialized as true and return 0.

This is regarding luo_session_deserialize(), that is the intended
behavior. We attempt deserialization exactly once, and if it fails,
some resources stay "leaked" and inaccessible to the user until the
next reboot. This is the safest approach to avoid data leaks.


> --
> 2.43.0
>


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 09/10] liveupdate: Make unregister functions return void
  2026-03-27  3:33 ` [PATCH v3 09/10] liveupdate: Make unregister functions return void Pasha Tatashin
@ 2026-03-27 14:41   ` Pasha Tatashin
  0 siblings, 0 replies; 15+ messages in thread
From: Pasha Tatashin @ 2026-03-27 14:41 UTC (permalink / raw)
  To: rppt, akpm, linux-mm, linux-kernel, pasha.tatashin, dmatlack,
	pratyush, skhawaja

On Thu, Mar 26, 2026 at 11:33 PM Pasha Tatashin
<pasha.tatashin@soleen.com> wrote:
>
> Change liveupdate_unregister_file_handler and liveupdate_unregister_flb
> to return void instead of an error code. This follows the design
> principle that unregistration during module unload should not fail,
> as the unload cannot be stopped at that point.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
> ---
>  include/linux/liveupdate.h   | 14 ++++++--------
>  kernel/liveupdate/luo_file.c | 14 ++------------
>  kernel/liveupdate/luo_flb.c  | 11 +++--------
>  3 files changed, 11 insertions(+), 28 deletions(-)
>
> diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
> index 73ca84de3eae..2ae27711ac41 100644
> --- a/include/linux/liveupdate.h
> +++ b/include/linux/liveupdate.h
> @@ -229,12 +229,12 @@ bool liveupdate_enabled(void);
>  int liveupdate_reboot(void);
>
>  int liveupdate_register_file_handler(struct liveupdate_file_handler *fh);
> -int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh);
> +void liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh);
>
>  int liveupdate_register_flb(struct liveupdate_file_handler *fh,
>                             struct liveupdate_flb *flb);
> -int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
> -                             struct liveupdate_flb *flb);
> +void liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
> +                              struct liveupdate_flb *flb);
>
>  int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp);
>  int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp);
> @@ -256,9 +256,8 @@ static inline int liveupdate_register_file_handler(struct liveupdate_file_handle
>         return -EOPNOTSUPP;
>  }
>
> -static inline int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
> +static inline void liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
>  {
> -       return -EOPNOTSUPP;
>  }
>
>  static inline int liveupdate_register_flb(struct liveupdate_file_handler *fh,
> @@ -267,10 +266,9 @@ static inline int liveupdate_register_flb(struct liveupdate_file_handler *fh,
>         return -EOPNOTSUPP;
>  }
>
> -static inline int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
> -                                           struct liveupdate_flb *flb)
> +static inline void liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
> +                                            struct liveupdate_flb *flb)
>  {
> -       return -EOPNOTSUPP;
>  }
>
>  static inline int liveupdate_flb_get_incoming(struct liveupdate_flb *flb,
> diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
> index dd55e5e74d69..761e8f7cfc82 100644
> --- a/kernel/liveupdate/luo_file.c
> +++ b/kernel/liveupdate/luo_file.c
> @@ -884,25 +884,15 @@ int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
>   *
>   * Unregisters the file handler from the liveupdate core. This function
>   * reverses the operations of liveupdate_register_file_handler().
> - *
> - * It ensures safe removal by checking that:
> - * No FLB registered with this file handler.
> - *
> - * If the unregistration fails, the internal test state is reverted.
> - *
> - * Return: 0 Success. -EOPNOTSUPP when live update is not enabled. -EBUSY A live
> - * update is in progress, FLB is registred with this file handler.
>   */
> -int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
> +void liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
>  {
>         if (!liveupdate_enabled())
> -               return -EOPNOTSUPP;
> +               return;
>
>         guard(rwsem_write)(&luo_register_rwlock);
>         luo_flb_unregister_all(fh);
>         list_del(&ACCESS_PRIVATE(fh, list));
>
>         module_put(fh->ops->owner);
> -
> -       return 0;
>  }
> diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
> index f8348138de70..8f3c9c63e320 100644
> --- a/kernel/liveupdate/luo_flb.c
> +++ b/kernel/liveupdate/luo_flb.c
> @@ -492,21 +492,16 @@ int liveupdate_register_flb(struct liveupdate_file_handler *fh,
>   * owner module (acquired during registration) is released.
>   *
>   * Context: It is typically called from a subsystem's module exit function.
> - * Return: 0 on success.
> - *         -EOPNOTSUPP if live update is disabled.
> - *         -ENOENT if the FLB was not found in the file handler's list.
>   */
> -int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
> -                             struct liveupdate_flb *flb)
> +void liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
> +                              struct liveupdate_flb *flb)
>  {
>         if (!liveupdate_enabled())
> -               return -EOPNOTSUPP;
> +               return;
>
>         guard(rwsem_write)(&luo_register_rwlock);
>
>         luo_flb_unregister_one(fh, flb);
> -
> -       return 0;
>  }

A question from Sashiko:
If the file handler is unregistered and freed by its owner, its dependent
FLBs might still retain a stale pointer to it. When an FLB is later
unregistered and calls liveupdate_unregister_flb() with this stale fh
pointer, could luo_flb_unregister_one() dereference the freed memory and
cause a use-after-free?

No, there is no UAF possability here.

1. FLBs do not keep pointers to file handlers.
The relationship between file handlers and FLBs is asymmetric. A
struct liveupdate_file_handler maintains a list of its dependent FLBs
in its flb_list. And, the struct liveupdate_flb only tracks the number
of handlers using it and its position in a global list. It does not
store pointers back to the file handlers.

2. Manual FLB unregistration: When a subsystem calls
liveupdate_unregister_flb, it is responsible for providing a valid fh
pointer. Since the subsystem typically owns the lifetime of the fh (a
static structure in the module), it is the caller's responsibility not
to pass a stale pointer.

3. Atomatic FLB unregistration during
liveupdate_unregister_file_handler function, explicitly calls
luo_flb_unregister_all(fh): luo_flb_unregister_all(fh) iterates
through the handler's flb_list, calls luo_flb_unregister_one for each,
which removes the luo_flb_link from the handler and frees it. This
ensures that when the handler is gone, all its associations with FLBs
are already destroyed.

Pasha


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 10/10] liveupdate: Defer file handler module refcounting to active sessions
  2026-03-27  3:33 ` [PATCH v3 10/10] liveupdate: Defer file handler module refcounting to active sessions Pasha Tatashin
@ 2026-03-27 17:14   ` Andrew Morton
  0 siblings, 0 replies; 15+ messages in thread
From: Andrew Morton @ 2026-03-27 17:14 UTC (permalink / raw)
  To: Pasha Tatashin; +Cc: rppt, linux-mm, linux-kernel, dmatlack, pratyush, skhawaja

On Fri, 27 Mar 2026 03:33:34 +0000 Pasha Tatashin <pasha.tatashin@soleen.com> wrote:

> Stop pinning modules indefinitely upon file handler registration.
> Instead, dynamically increment the module reference count only when a
> live update session actively uses the file handler (e.g., during
> preservation or deserialization), and release it when the session ends.
> 
> This allows modules providing live update handlers to be gracefully
> unloaded when no live update is in progress.
> 
> ...
>
> @@ -322,6 +323,8 @@ int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
>  	kfree(luo_file);
>  err_flb_unpreserve:
>  	luo_flb_file_unpreserve(fh);
> +err_module_put:
> +	module_put(fh->ops->owner);
>  err_free_files_mem:
>  	luo_free_files_mem(file_set);
>  err_fput:

This didn't anticipate your "liveupdate: prevent double management of
files".  I resolved it thusly:

err_kfree:
	kfree(luo_file);
err_flb_unpreserve:
	luo_flb_file_unpreserve(fh);
err_erase_xa:
	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);

	return err;
}




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API
  2026-03-27  3:33 [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Pasha Tatashin
                   ` (9 preceding siblings ...)
  2026-03-27  3:33 ` [PATCH v3 10/10] liveupdate: Defer file handler module refcounting to active sessions Pasha Tatashin
@ 2026-03-27 17:24 ` Andrew Morton
  10 siblings, 0 replies; 15+ messages in thread
From: Andrew Morton @ 2026-03-27 17:24 UTC (permalink / raw)
  To: Pasha Tatashin; +Cc: rppt, linux-mm, linux-kernel, dmatlack, pratyush, skhawaja

On Fri, 27 Mar 2026 03:33:24 +0000 Pasha Tatashin <pasha.tatashin@soleen.com> wrote:

> This patch series addresses an issue with how LUO handles module
> reference counting and unregistration during a module unload (e.g.,
> via rmmod).

Thanks.  I've added this to mm.git's mm-new branch.

It's getting late, but the series fixes things and LUO is still under
heavy development and is a bit experimental (yes?).  External testing
and prompt review (please) will help things along.


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-03-27 17:25 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-27  3:33 [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Pasha Tatashin
2026-03-27  3:33 ` [PATCH v3 01/10] liveupdate: Safely print untrusted strings Pasha Tatashin
2026-03-27 13:16   ` Pasha Tatashin
2026-03-27  3:33 ` [PATCH v3 02/10] liveupdate: Synchronize lazy initialization of FLB private state Pasha Tatashin
2026-03-27  3:33 ` [PATCH v3 03/10] liveupdate: Protect file handler list with rwsem Pasha Tatashin
2026-03-27  3:33 ` [PATCH v3 04/10] liveupdate: Protect FLB lists with luo_register_rwlock Pasha Tatashin
2026-03-27  3:33 ` [PATCH v3 05/10] liveupdate: Defer FLB module refcounting to active sessions Pasha Tatashin
2026-03-27  3:33 ` [PATCH v3 06/10] liveupdate: Remove luo_session_quiesce() Pasha Tatashin
2026-03-27  3:33 ` [PATCH v3 07/10] liveupdate: Auto unregister FLBs on file handler unregistration Pasha Tatashin
2026-03-27  3:33 ` [PATCH v3 08/10] liveupdate: Remove liveupdate_test_unregister() Pasha Tatashin
2026-03-27  3:33 ` [PATCH v3 09/10] liveupdate: Make unregister functions return void Pasha Tatashin
2026-03-27 14:41   ` Pasha Tatashin
2026-03-27  3:33 ` [PATCH v3 10/10] liveupdate: Defer file handler module refcounting to active sessions Pasha Tatashin
2026-03-27 17:14   ` Andrew Morton
2026-03-27 17:24 ` [PATCH v3 00/10] liveupdate: Fix module unloading and unregister API Andrew Morton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox