[PATCH] liveupdate: initialize incoming FLB state before finish

From: Pratyush Yadav (Google)

Date: Thu Apr 02 2026 - 09:22:05 EST


The state of an incoming FLB object is initialized when it is first
used. The initialization is done via luo_flb_retrieve_one(), which looks
at all the incoming FLBs, matches the FLB to its serialized entry, and
initializes the incoming data and count.

luo_flb_file_finish_one() is called when finish is called for a file
registered with this FLB. If no file handler has used the FLB by this
point, the count stays un-initialized at 0. luo_flb_file_finish_one()
then decrements this un-initialized count, leading to an underflow. This
results in the FLB finish never being called since the count has
underflowed to a very large value.

Fix this by making sure the FLB is retrieved before using its count.

Fixes: cab056f2aae7 ("liveupdate: luo_flb: introduce File-Lifecycle-Bound global state")
Suggested-by: Leo Timmins <leotimmins1974@xxxxxxxxx>
Signed-off-by: Pratyush Yadav (Google) <pratyush@xxxxxxxxxx>
---
kernel/liveupdate/luo_flb.c | 32 +++++++++++++++-----------------
1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
index f52e8114837e..be141620751e 100644
--- a/kernel/liveupdate/luo_flb.c
+++ b/kernel/liveupdate/luo_flb.c
@@ -194,28 +194,26 @@ static void luo_flb_file_finish_one(struct liveupdate_flb *flb)
struct luo_flb_private *private = luo_flb_get_private(flb);
u64 count;

- scoped_guard(mutex, &private->incoming.lock)
- count = --private->incoming.count;
+ if (!private->incoming.retrieved) {
+ int err = luo_flb_retrieve_one(flb);

+ if (WARN_ON(err))
+ return;
+ }
+
+ guard(mutex)(&private->incoming.lock);
+
+ count = --private->incoming.count;
if (!count) {
struct liveupdate_flb_op_args args = {0};

- if (!private->incoming.retrieved) {
- int err = luo_flb_retrieve_one(flb);
+ args.flb = flb;
+ args.obj = private->incoming.obj;
+ flb->ops->finish(&args);

- if (WARN_ON(err))
- return;
- }
-
- scoped_guard(mutex, &private->incoming.lock) {
- args.flb = flb;
- args.obj = private->incoming.obj;
- flb->ops->finish(&args);
-
- private->incoming.data = 0;
- private->incoming.obj = NULL;
- private->incoming.finished = true;
- }
+ private->incoming.data = 0;
+ private->incoming.obj = NULL;
+ private->incoming.finished = true;
}
}

--
Regards,
Pratyush Yadav