xref: /linux/kernel/liveupdate/luo_flb.c (revision 23b0f90ba871f096474e1c27c3d14f455189d2d9)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 /*
4  * Copyright (c) 2025, Google LLC.
5  * Pasha Tatashin <pasha.tatashin@soleen.com>
6  */
7 
8 /**
9  * DOC: LUO File Lifecycle Bound Global Data
10  *
11  * File-Lifecycle-Bound (FLB) objects provide a mechanism for managing global
12  * state that is shared across multiple live-updatable files. The lifecycle of
13  * this shared state is tied to the preservation of the files that depend on it.
14  *
15  * An FLB represents a global resource, such as the IOMMU core state, that is
16  * required by multiple file descriptors (e.g., all VFIO fds).
17  *
18  * The preservation of the FLB's state is triggered when the *first* file
19  * depending on it is preserved. The cleanup of this state (unpreserve or
20  * finish) is triggered when the *last* file depending on it is unpreserved or
21  * finished.
22  *
23  * Handler Dependency: A file handler declares its dependency on one or more
24  * FLBs by registering them via liveupdate_register_flb().
25  *
26  * Callback Model: Each FLB is defined by a set of operations
27  * (&struct liveupdate_flb_ops) that LUO invokes at key points:
28  *
29  *     - .preserve(): Called for the first file. Saves global state.
30  *     - .unpreserve(): Called for the last file (if aborted pre-reboot).
31  *     - .retrieve(): Called on-demand in the new kernel to restore the state.
32  *     - .finish(): Called for the last file in the new kernel for cleanup.
33  *
34  * This reference-counted approach ensures that shared state is saved exactly
35  * once and restored exactly once, regardless of how many files depend on it,
36  * and that its lifecycle is correctly managed across the kexec transition.
37  */
38 
39 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
40 
41 #include <linux/cleanup.h>
42 #include <linux/err.h>
43 #include <linux/errno.h>
44 #include <linux/io.h>
45 #include <linux/kexec_handover.h>
46 #include <linux/kho/abi/luo.h>
47 #include <linux/libfdt.h>
48 #include <linux/list_private.h>
49 #include <linux/liveupdate.h>
50 #include <linux/module.h>
51 #include <linux/mutex.h>
52 #include <linux/slab.h>
53 #include <linux/unaligned.h>
54 #include "luo_internal.h"
55 
56 #define LUO_FLB_PGCNT		1ul
57 #define LUO_FLB_MAX		(((LUO_FLB_PGCNT << PAGE_SHIFT) -	\
58 		sizeof(struct luo_flb_header_ser)) / sizeof(struct luo_flb_ser))
59 
60 struct luo_flb_header {
61 	struct luo_flb_header_ser *header_ser;
62 	struct luo_flb_ser *ser;
63 	bool active;
64 };
65 
66 struct luo_flb_global {
67 	struct luo_flb_header incoming;
68 	struct luo_flb_header outgoing;
69 	struct list_head list;
70 	long count;
71 };
72 
73 static struct luo_flb_global luo_flb_global = {
74 	.list = LIST_HEAD_INIT(luo_flb_global.list),
75 };
76 
77 /*
78  * struct luo_flb_link - Links an FLB definition to a file handler's internal
79  * list of dependencies.
80  * @flb:  A pointer to the registered &struct liveupdate_flb definition.
81  * @list: The list_head for linking.
82  */
83 struct luo_flb_link {
84 	struct liveupdate_flb *flb;
85 	struct list_head list;
86 };
87 
88 /* luo_flb_get_private - Access private field, and if needed initialize it. */
89 static struct luo_flb_private *luo_flb_get_private(struct liveupdate_flb *flb)
90 {
91 	struct luo_flb_private *private = &ACCESS_PRIVATE(flb, private);
92 
93 	if (!private->initialized) {
94 		mutex_init(&private->incoming.lock);
95 		mutex_init(&private->outgoing.lock);
96 		INIT_LIST_HEAD(&private->list);
97 		private->users = 0;
98 		private->initialized = true;
99 	}
100 
101 	return private;
102 }
103 
104 static int luo_flb_file_preserve_one(struct liveupdate_flb *flb)
105 {
106 	struct luo_flb_private *private = luo_flb_get_private(flb);
107 
108 	scoped_guard(mutex, &private->outgoing.lock) {
109 		if (!private->outgoing.count) {
110 			struct liveupdate_flb_op_args args = {0};
111 			int err;
112 
113 			args.flb = flb;
114 			err = flb->ops->preserve(&args);
115 			if (err)
116 				return err;
117 			private->outgoing.data = args.data;
118 			private->outgoing.obj = args.obj;
119 		}
120 		private->outgoing.count++;
121 	}
122 
123 	return 0;
124 }
125 
126 static void luo_flb_file_unpreserve_one(struct liveupdate_flb *flb)
127 {
128 	struct luo_flb_private *private = luo_flb_get_private(flb);
129 
130 	scoped_guard(mutex, &private->outgoing.lock) {
131 		private->outgoing.count--;
132 		if (!private->outgoing.count) {
133 			struct liveupdate_flb_op_args args = {0};
134 
135 			args.flb = flb;
136 			args.data = private->outgoing.data;
137 			args.obj = private->outgoing.obj;
138 
139 			if (flb->ops->unpreserve)
140 				flb->ops->unpreserve(&args);
141 
142 			private->outgoing.data = 0;
143 			private->outgoing.obj = NULL;
144 		}
145 	}
146 }
147 
148 static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
149 {
150 	struct luo_flb_private *private = luo_flb_get_private(flb);
151 	struct luo_flb_header *fh = &luo_flb_global.incoming;
152 	struct liveupdate_flb_op_args args = {0};
153 	bool found = false;
154 	int err;
155 
156 	guard(mutex)(&private->incoming.lock);
157 
158 	if (private->incoming.finished)
159 		return -ENODATA;
160 
161 	if (private->incoming.retrieved)
162 		return 0;
163 
164 	if (!fh->active)
165 		return -ENODATA;
166 
167 	for (int i = 0; i < fh->header_ser->count; i++) {
168 		if (!strcmp(fh->ser[i].name, flb->compatible)) {
169 			private->incoming.data = fh->ser[i].data;
170 			private->incoming.count = fh->ser[i].count;
171 			found = true;
172 			break;
173 		}
174 	}
175 
176 	if (!found)
177 		return -ENOENT;
178 
179 	args.flb = flb;
180 	args.data = private->incoming.data;
181 
182 	err = flb->ops->retrieve(&args);
183 	if (err)
184 		return err;
185 
186 	private->incoming.obj = args.obj;
187 	private->incoming.retrieved = true;
188 
189 	return 0;
190 }
191 
192 static void luo_flb_file_finish_one(struct liveupdate_flb *flb)
193 {
194 	struct luo_flb_private *private = luo_flb_get_private(flb);
195 	u64 count;
196 
197 	scoped_guard(mutex, &private->incoming.lock)
198 		count = --private->incoming.count;
199 
200 	if (!count) {
201 		struct liveupdate_flb_op_args args = {0};
202 
203 		if (!private->incoming.retrieved) {
204 			int err = luo_flb_retrieve_one(flb);
205 
206 			if (WARN_ON(err))
207 				return;
208 		}
209 
210 		scoped_guard(mutex, &private->incoming.lock) {
211 			args.flb = flb;
212 			args.obj = private->incoming.obj;
213 			flb->ops->finish(&args);
214 
215 			private->incoming.data = 0;
216 			private->incoming.obj = NULL;
217 			private->incoming.finished = true;
218 		}
219 	}
220 }
221 
222 /**
223  * luo_flb_file_preserve - Notifies FLBs that a file is about to be preserved.
224  * @fh: The file handler for the preserved file.
225  *
226  * This function iterates through all FLBs associated with the given file
227  * handler. It increments the reference count for each FLB. If the count becomes
228  * 1, it triggers the FLB's .preserve() callback to save the global state.
229  *
230  * This operation is atomic. If any FLB's .preserve() op fails, it will roll
231  * back by calling .unpreserve() on any FLBs that were successfully preserved
232  * during this call.
233  *
234  * Context: Called from luo_preserve_file()
235  * Return: 0 on success, or a negative errno on failure.
236  */
237 int luo_flb_file_preserve(struct liveupdate_file_handler *fh)
238 {
239 	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
240 	struct luo_flb_link *iter;
241 	int err = 0;
242 
243 	list_for_each_entry(iter, flb_list, list) {
244 		err = luo_flb_file_preserve_one(iter->flb);
245 		if (err)
246 			goto exit_err;
247 	}
248 
249 	return 0;
250 
251 exit_err:
252 	list_for_each_entry_continue_reverse(iter, flb_list, list)
253 		luo_flb_file_unpreserve_one(iter->flb);
254 
255 	return err;
256 }
257 
258 /**
259  * luo_flb_file_unpreserve - Notifies FLBs that a dependent file was unpreserved.
260  * @fh: The file handler for the unpreserved file.
261  *
262  * This function iterates through all FLBs associated with the given file
263  * handler, in reverse order of registration. It decrements the reference count
264  * for each FLB. If the count becomes 0, it triggers the FLB's .unpreserve()
265  * callback to clean up the global state.
266  *
267  * Context: Called when a preserved file is being cleaned up before reboot
268  *          (e.g., from luo_file_unpreserve_files()).
269  */
270 void luo_flb_file_unpreserve(struct liveupdate_file_handler *fh)
271 {
272 	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
273 	struct luo_flb_link *iter;
274 
275 	list_for_each_entry_reverse(iter, flb_list, list)
276 		luo_flb_file_unpreserve_one(iter->flb);
277 }
278 
279 /**
280  * luo_flb_file_finish - Notifies FLBs that a dependent file has been finished.
281  * @fh: The file handler for the finished file.
282  *
283  * This function iterates through all FLBs associated with the given file
284  * handler, in reverse order of registration. It decrements the incoming
285  * reference count for each FLB. If the count becomes 0, it triggers the FLB's
286  * .finish() callback for final cleanup in the new kernel.
287  *
288  * Context: Called from luo_file_finish() for each file being finished.
289  */
290 void luo_flb_file_finish(struct liveupdate_file_handler *fh)
291 {
292 	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
293 	struct luo_flb_link *iter;
294 
295 	list_for_each_entry_reverse(iter, flb_list, list)
296 		luo_flb_file_finish_one(iter->flb);
297 }
298 
299 /**
300  * liveupdate_register_flb - Associate an FLB with a file handler and register it globally.
301  * @fh:   The file handler that will now depend on the FLB.
302  * @flb:  The File-Lifecycle-Bound object to associate.
303  *
304  * Establishes a dependency, informing the LUO core that whenever a file of
305  * type @fh is preserved, the state of @flb must also be managed.
306  *
307  * On the first registration of a given @flb object, it is added to a global
308  * registry. This function checks for duplicate registrations, both for a
309  * specific handler and globally, and ensures the total number of unique
310  * FLBs does not exceed the system limit.
311  *
312  * Context: Typically called from a subsystem's module init function after
313  *          both the handler and the FLB have been defined and initialized.
314  * Return: 0 on success. Returns a negative errno on failure:
315  *         -EINVAL if arguments are NULL or not initialized.
316  *         -ENOMEM on memory allocation failure.
317  *         -EEXIST if this FLB is already registered with this handler.
318  *         -ENOSPC if the maximum number of global FLBs has been reached.
319  *         -EOPNOTSUPP if live update is disabled or not configured.
320  */
321 int liveupdate_register_flb(struct liveupdate_file_handler *fh,
322 			    struct liveupdate_flb *flb)
323 {
324 	struct luo_flb_private *private = luo_flb_get_private(flb);
325 	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
326 	struct luo_flb_link *link __free(kfree) = NULL;
327 	struct liveupdate_flb *gflb;
328 	struct luo_flb_link *iter;
329 	int err;
330 
331 	if (!liveupdate_enabled())
332 		return -EOPNOTSUPP;
333 
334 	if (WARN_ON(!flb->ops->preserve || !flb->ops->unpreserve ||
335 		    !flb->ops->retrieve || !flb->ops->finish)) {
336 		return -EINVAL;
337 	}
338 
339 	/*
340 	 * File handler must already be registered, as it initializes the
341 	 * flb_list
342 	 */
343 	if (WARN_ON(list_empty(&ACCESS_PRIVATE(fh, list))))
344 		return -EINVAL;
345 
346 	link = kzalloc(sizeof(*link), GFP_KERNEL);
347 	if (!link)
348 		return -ENOMEM;
349 
350 	/*
351 	 * Ensure the system is quiescent (no active sessions).
352 	 * This acts as a global lock for registration: no other thread can
353 	 * be in this section, and no sessions can be creating/using FDs.
354 	 */
355 	if (!luo_session_quiesce())
356 		return -EBUSY;
357 
358 	/* Check that this FLB is not already linked to this file handler */
359 	err = -EEXIST;
360 	list_for_each_entry(iter, flb_list, list) {
361 		if (iter->flb == flb)
362 			goto err_resume;
363 	}
364 
365 	/*
366 	 * If this FLB is not linked to global list it's the first time the FLB
367 	 * is registered
368 	 */
369 	if (!private->users) {
370 		if (WARN_ON(!list_empty(&private->list))) {
371 			err = -EINVAL;
372 			goto err_resume;
373 		}
374 
375 		if (luo_flb_global.count == LUO_FLB_MAX) {
376 			err = -ENOSPC;
377 			goto err_resume;
378 		}
379 
380 		/* Check that compatible string is unique in global list */
381 		list_private_for_each_entry(gflb, &luo_flb_global.list, private.list) {
382 			if (!strcmp(gflb->compatible, flb->compatible))
383 				goto err_resume;
384 		}
385 
386 		if (!try_module_get(flb->ops->owner)) {
387 			err = -EAGAIN;
388 			goto err_resume;
389 		}
390 
391 		list_add_tail(&private->list, &luo_flb_global.list);
392 		luo_flb_global.count++;
393 	}
394 
395 	/* Finally, link the FLB to the file handler */
396 	private->users++;
397 	link->flb = flb;
398 	list_add_tail(&no_free_ptr(link)->list, flb_list);
399 	luo_session_resume();
400 
401 	return 0;
402 
403 err_resume:
404 	luo_session_resume();
405 	return err;
406 }
407 
408 /**
409  * liveupdate_unregister_flb - Remove an FLB dependency from a file handler.
410  * @fh:   The file handler that is currently depending on the FLB.
411  * @flb:  The File-Lifecycle-Bound object to remove.
412  *
413  * Removes the association between the specified file handler and the FLB
414  * previously established by liveupdate_register_flb().
415  *
416  * This function manages the global lifecycle of the FLB. It decrements the
417  * FLB's usage count. If this was the last file handler referencing this FLB,
418  * the FLB is removed from the global registry and the reference to its
419  * owner module (acquired during registration) is released.
420  *
421  * Context: This function ensures the session is quiesced (no active FDs
422  *          being created) during the update. It is typically called from a
423  *          subsystem's module exit function.
424  * Return: 0 on success.
425  *         -EOPNOTSUPP if live update is disabled.
426  *         -EBUSY if the live update session is active and cannot be quiesced.
427  *         -ENOENT if the FLB was not found in the file handler's list.
428  */
429 int liveupdate_unregister_flb(struct liveupdate_file_handler *fh,
430 			      struct liveupdate_flb *flb)
431 {
432 	struct luo_flb_private *private = luo_flb_get_private(flb);
433 	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
434 	struct luo_flb_link *iter;
435 	int err = -ENOENT;
436 
437 	if (!liveupdate_enabled())
438 		return -EOPNOTSUPP;
439 
440 	/*
441 	 * Ensure the system is quiescent (no active sessions).
442 	 * This acts as a global lock for unregistration.
443 	 */
444 	if (!luo_session_quiesce())
445 		return -EBUSY;
446 
447 	/* Find and remove the link from the file handler's list */
448 	list_for_each_entry(iter, flb_list, list) {
449 		if (iter->flb == flb) {
450 			list_del(&iter->list);
451 			kfree(iter);
452 			err = 0;
453 			break;
454 		}
455 	}
456 
457 	if (err)
458 		goto err_resume;
459 
460 	private->users--;
461 	/*
462 	 * If this is the last file-handler with which we are registred, remove
463 	 * from the global list, and relese module reference.
464 	 */
465 	if (!private->users) {
466 		list_del_init(&private->list);
467 		luo_flb_global.count--;
468 		module_put(flb->ops->owner);
469 	}
470 
471 	luo_session_resume();
472 
473 	return 0;
474 
475 err_resume:
476 	luo_session_resume();
477 	return err;
478 }
479 
480 /**
481  * liveupdate_flb_get_incoming - Retrieve the incoming FLB object.
482  * @flb:  The FLB definition.
483  * @objp: Output parameter; will be populated with the live shared object.
484  *
485  * Returns a pointer to its shared live object for the incoming (post-reboot)
486  * path.
487  *
488  * If this is the first time the object is requested in the new kernel, this
489  * function will trigger the FLB's .retrieve() callback to reconstruct the
490  * object from its preserved state. Subsequent calls will return the same
491  * cached object.
492  *
493  * Return: 0 on success, or a negative errno on failure. -ENODATA means no
494  * incoming FLB data, -ENOENT means specific flb not found in the incoming
495  * data, and -EOPNOTSUPP when live update is disabled or not configured.
496  */
497 int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp)
498 {
499 	struct luo_flb_private *private = luo_flb_get_private(flb);
500 
501 	if (!liveupdate_enabled())
502 		return -EOPNOTSUPP;
503 
504 	if (!private->incoming.obj) {
505 		int err = luo_flb_retrieve_one(flb);
506 
507 		if (err)
508 			return err;
509 	}
510 
511 	guard(mutex)(&private->incoming.lock);
512 	*objp = private->incoming.obj;
513 
514 	return 0;
515 }
516 
517 /**
518  * liveupdate_flb_get_outgoing - Retrieve the outgoing FLB object.
519  * @flb:  The FLB definition.
520  * @objp: Output parameter; will be populated with the live shared object.
521  *
522  * Returns a pointer to its shared live object for the outgoing (pre-reboot)
523  * path.
524  *
525  * This function assumes the object has already been created by the FLB's
526  * .preserve() callback, which is triggered when the first dependent file
527  * is preserved.
528  *
529  * Return: 0 on success, or a negative errno on failure.
530  */
531 int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp)
532 {
533 	struct luo_flb_private *private = luo_flb_get_private(flb);
534 
535 	if (!liveupdate_enabled())
536 		return -EOPNOTSUPP;
537 
538 	guard(mutex)(&private->outgoing.lock);
539 	*objp = private->outgoing.obj;
540 
541 	return 0;
542 }
543 
544 int __init luo_flb_setup_outgoing(void *fdt_out)
545 {
546 	struct luo_flb_header_ser *header_ser;
547 	u64 header_ser_pa;
548 	int err;
549 
550 	header_ser = kho_alloc_preserve(LUO_FLB_PGCNT << PAGE_SHIFT);
551 	if (IS_ERR(header_ser))
552 		return PTR_ERR(header_ser);
553 
554 	header_ser_pa = virt_to_phys(header_ser);
555 
556 	err = fdt_begin_node(fdt_out, LUO_FDT_FLB_NODE_NAME);
557 	err |= fdt_property_string(fdt_out, "compatible",
558 				   LUO_FDT_FLB_COMPATIBLE);
559 	err |= fdt_property(fdt_out, LUO_FDT_FLB_HEADER, &header_ser_pa,
560 			    sizeof(header_ser_pa));
561 	err |= fdt_end_node(fdt_out);
562 
563 	if (err)
564 		goto err_unpreserve;
565 
566 	header_ser->pgcnt = LUO_FLB_PGCNT;
567 	luo_flb_global.outgoing.header_ser = header_ser;
568 	luo_flb_global.outgoing.ser = (void *)(header_ser + 1);
569 	luo_flb_global.outgoing.active = true;
570 
571 	return 0;
572 
573 err_unpreserve:
574 	kho_unpreserve_free(header_ser);
575 
576 	return err;
577 }
578 
579 int __init luo_flb_setup_incoming(void *fdt_in)
580 {
581 	struct luo_flb_header_ser *header_ser;
582 	int err, header_size, offset;
583 	const void *ptr;
584 	u64 header_ser_pa;
585 
586 	offset = fdt_subnode_offset(fdt_in, 0, LUO_FDT_FLB_NODE_NAME);
587 	if (offset < 0) {
588 		pr_err("Unable to get FLB node [%s]\n", LUO_FDT_FLB_NODE_NAME);
589 
590 		return -ENOENT;
591 	}
592 
593 	err = fdt_node_check_compatible(fdt_in, offset,
594 					LUO_FDT_FLB_COMPATIBLE);
595 	if (err) {
596 		pr_err("FLB node is incompatible with '%s' [%d]\n",
597 		       LUO_FDT_FLB_COMPATIBLE, err);
598 
599 		return -EINVAL;
600 	}
601 
602 	header_size = 0;
603 	ptr = fdt_getprop(fdt_in, offset, LUO_FDT_FLB_HEADER, &header_size);
604 	if (!ptr || header_size != sizeof(u64)) {
605 		pr_err("Unable to get FLB header property '%s' [%d]\n",
606 		       LUO_FDT_FLB_HEADER, header_size);
607 
608 		return -EINVAL;
609 	}
610 
611 	header_ser_pa = get_unaligned((u64 *)ptr);
612 	header_ser = phys_to_virt(header_ser_pa);
613 
614 	luo_flb_global.incoming.header_ser = header_ser;
615 	luo_flb_global.incoming.ser = (void *)(header_ser + 1);
616 	luo_flb_global.incoming.active = true;
617 
618 	return 0;
619 }
620 
621 /**
622  * luo_flb_serialize - Serializes all active FLB objects for KHO.
623  *
624  * This function is called from the reboot path. It iterates through all
625  * registered File-Lifecycle-Bound (FLB) objects. For each FLB that has been
626  * preserved (i.e., its reference count is greater than zero), it writes its
627  * metadata into the memory region designated for Kexec Handover.
628  *
629  * The serialized data includes the FLB's compatibility string, its opaque
630  * data handle, and the final reference count. This allows the new kernel to
631  * find the appropriate handler and reconstruct the FLB's state.
632  *
633  * Context: Called from liveupdate_reboot() just before kho_finalize().
634  */
635 void luo_flb_serialize(void)
636 {
637 	struct luo_flb_header *fh = &luo_flb_global.outgoing;
638 	struct liveupdate_flb *gflb;
639 	int i = 0;
640 
641 	list_private_for_each_entry(gflb, &luo_flb_global.list, private.list) {
642 		struct luo_flb_private *private = luo_flb_get_private(gflb);
643 
644 		if (private->outgoing.count > 0) {
645 			strscpy(fh->ser[i].name, gflb->compatible,
646 				sizeof(fh->ser[i].name));
647 			fh->ser[i].data = private->outgoing.data;
648 			fh->ser[i].count = private->outgoing.count;
649 			i++;
650 		}
651 	}
652 
653 	fh->header_ser->count = i;
654 }
655