[PATCH v2 3/8] liveupdate: Remove file handler module refcounting
From: Pasha Tatashin
Date: Wed Mar 18 2026 - 10:33:25 EST
File handlers do not need to pin modules indefinitely or during active
live update sessions. The VFS 'struct file' pins the file handler's module
via f_op->owner during active sessions, making dynamic reference counting
unnecessary for handlers.
When a file is preserved, the live update core obtains a 'struct file'
via fdget(). As long as the file is kept open within the live update
session, the module is pinned by the VFS and cannot be unloaded.
Similarly, during deserialization, file handlers are matched based on
the compatible string. Because the handler list is protected by
luo_file_handler_lock, there is no race that requires dynamic
module refcounting.
Removing these module references ensures that modules implementing file
handlers can be unloaded when no longer providing active files.
Suggested-by: David Matlack <dmatlack@xxxxxxxxxx>
Signed-off-by: Pasha Tatashin <pasha.tatashin@xxxxxxxxxx>
---
kernel/liveupdate/luo_file.c | 28 +++++++---------------------
1 file changed, 7 insertions(+), 21 deletions(-)
diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index 96fdd5790dcc..b124fd747841 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -836,7 +836,6 @@ void luo_file_set_destroy(struct luo_file_set *file_set)
int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
{
struct liveupdate_file_handler *fh_iter;
- int err;
if (!liveupdate_enabled())
return -EOPNOTSUPP;
@@ -861,17 +860,11 @@ int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
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;
+ luo_session_resume();
+ return -EEXIST;
}
}
- /* Pin the module implementing the handler */
- if (!try_module_get(fh->ops->owner)) {
- err = -EAGAIN;
- goto err_resume;
- }
-
INIT_LIST_HEAD(&ACCESS_PRIVATE(fh, flb_list));
init_rwsem(&ACCESS_PRIVATE(fh, flb_lock));
INIT_LIST_HEAD(&ACCESS_PRIVATE(fh, list));
@@ -882,10 +875,6 @@ int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
liveupdate_test_register(fh);
return 0;
-
-err_resume:
- luo_session_resume();
- return err;
}
/**
@@ -907,8 +896,6 @@ 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;
@@ -918,19 +905,18 @@ int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
goto err_register;
scoped_guard(rwsem_write, &luo_file_handler_lock) {
- if (!list_empty(&ACCESS_PRIVATE(fh, flb_list)))
- goto err_resume;
+ if (!list_empty(&ACCESS_PRIVATE(fh, flb_list))) {
+ luo_session_resume();
+ goto err_register;
+ }
list_del(&ACCESS_PRIVATE(fh, list));
}
- module_put(fh->ops->owner);
luo_session_resume();
return 0;
-err_resume:
- luo_session_resume();
err_register:
liveupdate_test_register(fh);
- return err;
+ return -EBUSY;
}
--
2.53.0.851.ga537e3e6e9-goog