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 static DEFINE_SPINLOCK(luo_flb_init_lock); 93 94 if (smp_load_acquire(&private->initialized)) 95 return private; 96 97 guard(spinlock)(&luo_flb_init_lock); 98 if (!private->initialized) { 99 mutex_init(&private->incoming.lock); 100 mutex_init(&private->outgoing.lock); 101 INIT_LIST_HEAD(&private->list); 102 private->users = 0; 103 smp_store_release(&private->initialized, true); 104 } 105 106 return private; 107 } 108 109 static int luo_flb_file_preserve_one(struct liveupdate_flb *flb) 110 { 111 struct luo_flb_private *private = luo_flb_get_private(flb); 112 113 scoped_guard(mutex, &private->outgoing.lock) { 114 if (!private->outgoing.count) { 115 struct liveupdate_flb_op_args args = {0}; 116 int err; 117 118 if (!try_module_get(flb->ops->owner)) 119 return -ENODEV; 120 121 args.flb = flb; 122 err = flb->ops->preserve(&args); 123 if (err) { 124 module_put(flb->ops->owner); 125 return err; 126 } 127 private->outgoing.data = args.data; 128 private->outgoing.obj = args.obj; 129 } 130 private->outgoing.count++; 131 } 132 133 return 0; 134 } 135 136 static void luo_flb_file_unpreserve_one(struct liveupdate_flb *flb) 137 { 138 struct luo_flb_private *private = luo_flb_get_private(flb); 139 140 scoped_guard(mutex, &private->outgoing.lock) { 141 private->outgoing.count--; 142 if (!private->outgoing.count) { 143 struct liveupdate_flb_op_args args = {0}; 144 145 args.flb = flb; 146 args.data = private->outgoing.data; 147 args.obj = private->outgoing.obj; 148 149 if (flb->ops->unpreserve) 150 flb->ops->unpreserve(&args); 151 152 private->outgoing.data = 0; 153 private->outgoing.obj = NULL; 154 module_put(flb->ops->owner); 155 } 156 } 157 } 158 159 static int luo_flb_retrieve_one(struct liveupdate_flb *flb) 160 { 161 struct luo_flb_private *private = luo_flb_get_private(flb); 162 struct luo_flb_header *fh = &luo_flb_global.incoming; 163 struct liveupdate_flb_op_args args = {0}; 164 bool found = false; 165 int err; 166 167 guard(mutex)(&private->incoming.lock); 168 169 if (private->incoming.finished) 170 return -ENODATA; 171 172 if (private->incoming.retrieved) 173 return 0; 174 175 if (!fh->active) 176 return -ENODATA; 177 178 for (int i = 0; i < fh->header_ser->count; i++) { 179 if (!strcmp(fh->ser[i].name, flb->compatible)) { 180 private->incoming.data = fh->ser[i].data; 181 private->incoming.count = fh->ser[i].count; 182 found = true; 183 break; 184 } 185 } 186 187 if (!found) 188 return -ENOENT; 189 190 if (!try_module_get(flb->ops->owner)) 191 return -ENODEV; 192 193 args.flb = flb; 194 args.data = private->incoming.data; 195 196 err = flb->ops->retrieve(&args); 197 if (err) { 198 module_put(flb->ops->owner); 199 return err; 200 } 201 202 private->incoming.obj = args.obj; 203 private->incoming.retrieved = true; 204 205 return 0; 206 } 207 208 static void luo_flb_file_finish_one(struct liveupdate_flb *flb) 209 { 210 struct luo_flb_private *private = luo_flb_get_private(flb); 211 u64 count; 212 213 scoped_guard(mutex, &private->incoming.lock) 214 count = --private->incoming.count; 215 216 if (!count) { 217 struct liveupdate_flb_op_args args = {0}; 218 219 if (!private->incoming.retrieved) { 220 int err = luo_flb_retrieve_one(flb); 221 222 if (WARN_ON(err)) 223 return; 224 } 225 226 scoped_guard(mutex, &private->incoming.lock) { 227 args.flb = flb; 228 args.obj = private->incoming.obj; 229 flb->ops->finish(&args); 230 231 private->incoming.data = 0; 232 private->incoming.obj = NULL; 233 private->incoming.finished = true; 234 module_put(flb->ops->owner); 235 } 236 } 237 } 238 239 /** 240 * luo_flb_file_preserve - Notifies FLBs that a file is about to be preserved. 241 * @fh: The file handler for the preserved file. 242 * 243 * This function iterates through all FLBs associated with the given file 244 * handler. It increments the reference count for each FLB. If the count becomes 245 * 1, it triggers the FLB's .preserve() callback to save the global state. 246 * 247 * This operation is atomic. If any FLB's .preserve() op fails, it will roll 248 * back by calling .unpreserve() on any FLBs that were successfully preserved 249 * during this call. 250 * 251 * Context: Called from luo_preserve_file() 252 * Return: 0 on success, or a negative errno on failure. 253 */ 254 int luo_flb_file_preserve(struct liveupdate_file_handler *fh) 255 { 256 struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list); 257 struct luo_flb_link *iter; 258 int err = 0; 259 260 down_read(&luo_register_rwlock); 261 list_for_each_entry(iter, flb_list, list) { 262 err = luo_flb_file_preserve_one(iter->flb); 263 if (err) 264 goto exit_err; 265 } 266 up_read(&luo_register_rwlock); 267 268 return 0; 269 270 exit_err: 271 list_for_each_entry_continue_reverse(iter, flb_list, list) 272 luo_flb_file_unpreserve_one(iter->flb); 273 up_read(&luo_register_rwlock); 274 275 return err; 276 } 277 278 /** 279 * luo_flb_file_unpreserve - Notifies FLBs that a dependent file was unpreserved. 280 * @fh: The file handler for the unpreserved file. 281 * 282 * This function iterates through all FLBs associated with the given file 283 * handler, in reverse order of registration. It decrements the reference count 284 * for each FLB. If the count becomes 0, it triggers the FLB's .unpreserve() 285 * callback to clean up the global state. 286 * 287 * Context: Called when a preserved file is being cleaned up before reboot 288 * (e.g., from luo_file_unpreserve_files()). 289 */ 290 void luo_flb_file_unpreserve(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 guard(rwsem_read)(&luo_register_rwlock); 296 list_for_each_entry_reverse(iter, flb_list, list) 297 luo_flb_file_unpreserve_one(iter->flb); 298 } 299 300 /** 301 * luo_flb_file_finish - Notifies FLBs that a dependent file has been finished. 302 * @fh: The file handler for the finished file. 303 * 304 * This function iterates through all FLBs associated with the given file 305 * handler, in reverse order of registration. It decrements the incoming 306 * reference count for each FLB. If the count becomes 0, it triggers the FLB's 307 * .finish() callback for final cleanup in the new kernel. 308 * 309 * Context: Called from luo_file_finish() for each file being finished. 310 */ 311 void luo_flb_file_finish(struct liveupdate_file_handler *fh) 312 { 313 struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list); 314 struct luo_flb_link *iter; 315 316 guard(rwsem_read)(&luo_register_rwlock); 317 list_for_each_entry_reverse(iter, flb_list, list) 318 luo_flb_file_finish_one(iter->flb); 319 } 320 321 static void luo_flb_unregister_one(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 *iter; 327 bool found = false; 328 329 /* Find and remove the link from the file handler's list */ 330 list_for_each_entry(iter, flb_list, list) { 331 if (iter->flb == flb) { 332 list_del(&iter->list); 333 kfree(iter); 334 found = true; 335 break; 336 } 337 } 338 339 if (!found) { 340 pr_warn("Failed to unregister FLB '%s': not found in file handler '%s'\n", 341 flb->compatible, fh->compatible); 342 return; 343 } 344 345 private->users--; 346 347 /* 348 * If this is the last file-handler with which we are registred, remove 349 * from the global list. 350 */ 351 if (!private->users) { 352 list_del_init(&private->list); 353 luo_flb_global.count--; 354 } 355 } 356 357 /** 358 * luo_flb_unregister_all - Unregister all FLBs associated with a file handler. 359 * @fh: The file handler whose FLBs should be unregistered. 360 * 361 * This function iterates through the list of FLBs associated with the given 362 * file handler and unregisters them all one by one. 363 */ 364 void luo_flb_unregister_all(struct liveupdate_file_handler *fh) 365 { 366 struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list); 367 struct luo_flb_link *iter, *tmp; 368 369 if (!liveupdate_enabled()) 370 return; 371 372 lockdep_assert_held_write(&luo_register_rwlock); 373 list_for_each_entry_safe(iter, tmp, flb_list, list) 374 luo_flb_unregister_one(fh, iter->flb); 375 } 376 377 /** 378 * liveupdate_register_flb - Associate an FLB with a file handler and register it globally. 379 * @fh: The file handler that will now depend on the FLB. 380 * @flb: The File-Lifecycle-Bound object to associate. 381 * 382 * Establishes a dependency, informing the LUO core that whenever a file of 383 * type @fh is preserved, the state of @flb must also be managed. 384 * 385 * On the first registration of a given @flb object, it is added to a global 386 * registry. This function checks for duplicate registrations, both for a 387 * specific handler and globally, and ensures the total number of unique 388 * FLBs does not exceed the system limit. 389 * 390 * Context: Typically called from a subsystem's module init function after 391 * both the handler and the FLB have been defined and initialized. 392 * Return: 0 on success. Returns a negative errno on failure: 393 * -EINVAL if arguments are NULL or not initialized. 394 * -ENOMEM on memory allocation failure. 395 * -EEXIST if this FLB is already registered with this handler. 396 * -ENOSPC if the maximum number of global FLBs has been reached. 397 * -EOPNOTSUPP if live update is disabled or not configured. 398 */ 399 int liveupdate_register_flb(struct liveupdate_file_handler *fh, 400 struct liveupdate_flb *flb) 401 { 402 struct luo_flb_private *private = luo_flb_get_private(flb); 403 struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list); 404 struct luo_flb_link *link __free(kfree) = NULL; 405 struct liveupdate_flb *gflb; 406 struct luo_flb_link *iter; 407 408 if (!liveupdate_enabled()) 409 return -EOPNOTSUPP; 410 411 if (WARN_ON(!flb->ops->preserve || !flb->ops->unpreserve || 412 !flb->ops->retrieve || !flb->ops->finish)) { 413 return -EINVAL; 414 } 415 416 /* 417 * File handler must already be registered, as it initializes the 418 * flb_list 419 */ 420 if (WARN_ON(list_empty(&ACCESS_PRIVATE(fh, list)))) 421 return -EINVAL; 422 423 link = kzalloc_obj(*link); 424 if (!link) 425 return -ENOMEM; 426 427 guard(rwsem_write)(&luo_register_rwlock); 428 429 /* Check that this FLB is not already linked to this file handler */ 430 list_for_each_entry(iter, flb_list, list) { 431 if (iter->flb == flb) 432 return -EEXIST; 433 } 434 435 /* 436 * If this FLB is not linked to global list it's the first time the FLB 437 * is registered 438 */ 439 if (!private->users) { 440 if (WARN_ON(!list_empty(&private->list))) 441 return -EINVAL; 442 443 if (luo_flb_global.count == LUO_FLB_MAX) 444 return -ENOSPC; 445 446 /* Check that compatible string is unique in global list */ 447 list_private_for_each_entry(gflb, &luo_flb_global.list, private.list) { 448 if (!strcmp(gflb->compatible, flb->compatible)) 449 return -EEXIST; 450 } 451 452 list_add_tail(&private->list, &luo_flb_global.list); 453 luo_flb_global.count++; 454 } 455 456 /* Finally, link the FLB to the file handler */ 457 private->users++; 458 link->flb = flb; 459 list_add_tail(&no_free_ptr(link)->list, flb_list); 460 461 return 0; 462 } 463 464 /** 465 * liveupdate_unregister_flb - Remove an FLB dependency from a file handler. 466 * @fh: The file handler that is currently depending on the FLB. 467 * @flb: The File-Lifecycle-Bound object to remove. 468 * 469 * Removes the association between the specified file handler and the FLB 470 * previously established by liveupdate_register_flb(). 471 * 472 * This function manages the global lifecycle of the FLB. It decrements the 473 * FLB's usage count. If this was the last file handler referencing this FLB, 474 * the FLB is removed from the global registry and the reference to its 475 * owner module (acquired during registration) is released. 476 * 477 * Context: It is typically called from a subsystem's module exit function. 478 * Return: 0 on success. 479 * -EOPNOTSUPP if live update is disabled. 480 * -ENOENT if the FLB was not found in the file handler's list. 481 */ 482 int liveupdate_unregister_flb(struct liveupdate_file_handler *fh, 483 struct liveupdate_flb *flb) 484 { 485 if (!liveupdate_enabled()) 486 return -EOPNOTSUPP; 487 488 guard(rwsem_write)(&luo_register_rwlock); 489 490 luo_flb_unregister_one(fh, flb); 491 492 return 0; 493 } 494 495 /** 496 * liveupdate_flb_get_incoming - Retrieve the incoming FLB object. 497 * @flb: The FLB definition. 498 * @objp: Output parameter; will be populated with the live shared object. 499 * 500 * Returns a pointer to its shared live object for the incoming (post-reboot) 501 * path. 502 * 503 * If this is the first time the object is requested in the new kernel, this 504 * function will trigger the FLB's .retrieve() callback to reconstruct the 505 * object from its preserved state. Subsequent calls will return the same 506 * cached object. 507 * 508 * Return: 0 on success, or a negative errno on failure. -ENODATA means no 509 * incoming FLB data, -ENOENT means specific flb not found in the incoming 510 * data, -ENODEV if the FLB's module is unloading, and -EOPNOTSUPP when 511 * live update is disabled or not configured. 512 */ 513 int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp) 514 { 515 struct luo_flb_private *private = luo_flb_get_private(flb); 516 517 if (!liveupdate_enabled()) 518 return -EOPNOTSUPP; 519 520 if (!private->incoming.obj) { 521 int err = luo_flb_retrieve_one(flb); 522 523 if (err) 524 return err; 525 } 526 527 guard(mutex)(&private->incoming.lock); 528 *objp = private->incoming.obj; 529 530 return 0; 531 } 532 533 /** 534 * liveupdate_flb_get_outgoing - Retrieve the outgoing FLB object. 535 * @flb: The FLB definition. 536 * @objp: Output parameter; will be populated with the live shared object. 537 * 538 * Returns a pointer to its shared live object for the outgoing (pre-reboot) 539 * path. 540 * 541 * This function assumes the object has already been created by the FLB's 542 * .preserve() callback, which is triggered when the first dependent file 543 * is preserved. 544 * 545 * Return: 0 on success, or a negative errno on failure. 546 */ 547 int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp) 548 { 549 struct luo_flb_private *private = luo_flb_get_private(flb); 550 551 if (!liveupdate_enabled()) 552 return -EOPNOTSUPP; 553 554 guard(mutex)(&private->outgoing.lock); 555 *objp = private->outgoing.obj; 556 557 return 0; 558 } 559 560 int __init luo_flb_setup_outgoing(void *fdt_out) 561 { 562 struct luo_flb_header_ser *header_ser; 563 u64 header_ser_pa; 564 int err; 565 566 header_ser = kho_alloc_preserve(LUO_FLB_PGCNT << PAGE_SHIFT); 567 if (IS_ERR(header_ser)) 568 return PTR_ERR(header_ser); 569 570 header_ser_pa = virt_to_phys(header_ser); 571 572 err = fdt_begin_node(fdt_out, LUO_FDT_FLB_NODE_NAME); 573 err |= fdt_property_string(fdt_out, "compatible", 574 LUO_FDT_FLB_COMPATIBLE); 575 err |= fdt_property(fdt_out, LUO_FDT_FLB_HEADER, &header_ser_pa, 576 sizeof(header_ser_pa)); 577 err |= fdt_end_node(fdt_out); 578 579 if (err) 580 goto err_unpreserve; 581 582 header_ser->pgcnt = LUO_FLB_PGCNT; 583 luo_flb_global.outgoing.header_ser = header_ser; 584 luo_flb_global.outgoing.ser = (void *)(header_ser + 1); 585 luo_flb_global.outgoing.active = true; 586 587 return 0; 588 589 err_unpreserve: 590 kho_unpreserve_free(header_ser); 591 592 return err; 593 } 594 595 int __init luo_flb_setup_incoming(void *fdt_in) 596 { 597 struct luo_flb_header_ser *header_ser; 598 int err, header_size, offset; 599 const void *ptr; 600 u64 header_ser_pa; 601 602 offset = fdt_subnode_offset(fdt_in, 0, LUO_FDT_FLB_NODE_NAME); 603 if (offset < 0) { 604 pr_err("Unable to get FLB node [%s]\n", LUO_FDT_FLB_NODE_NAME); 605 606 return -ENOENT; 607 } 608 609 err = fdt_node_check_compatible(fdt_in, offset, 610 LUO_FDT_FLB_COMPATIBLE); 611 if (err) { 612 pr_err("FLB node is incompatible with '%s' [%d]\n", 613 LUO_FDT_FLB_COMPATIBLE, err); 614 615 return -EINVAL; 616 } 617 618 header_size = 0; 619 ptr = fdt_getprop(fdt_in, offset, LUO_FDT_FLB_HEADER, &header_size); 620 if (!ptr || header_size != sizeof(u64)) { 621 pr_err("Unable to get FLB header property '%s' [%d]\n", 622 LUO_FDT_FLB_HEADER, header_size); 623 624 return -EINVAL; 625 } 626 627 header_ser_pa = get_unaligned((u64 *)ptr); 628 header_ser = phys_to_virt(header_ser_pa); 629 630 luo_flb_global.incoming.header_ser = header_ser; 631 luo_flb_global.incoming.ser = (void *)(header_ser + 1); 632 luo_flb_global.incoming.active = true; 633 634 return 0; 635 } 636 637 /** 638 * luo_flb_serialize - Serializes all active FLB objects for KHO. 639 * 640 * This function is called from the reboot path. It iterates through all 641 * registered File-Lifecycle-Bound (FLB) objects. For each FLB that has been 642 * preserved (i.e., its reference count is greater than zero), it writes its 643 * metadata into the memory region designated for Kexec Handover. 644 * 645 * The serialized data includes the FLB's compatibility string, its opaque 646 * data handle, and the final reference count. This allows the new kernel to 647 * find the appropriate handler and reconstruct the FLB's state. 648 * 649 * Context: Called from liveupdate_reboot() just before kho_finalize(). 650 */ 651 void luo_flb_serialize(void) 652 { 653 struct luo_flb_header *fh = &luo_flb_global.outgoing; 654 struct liveupdate_flb *gflb; 655 int i = 0; 656 657 guard(rwsem_read)(&luo_register_rwlock); 658 list_private_for_each_entry(gflb, &luo_flb_global.list, private.list) { 659 struct luo_flb_private *private = luo_flb_get_private(gflb); 660 661 if (private->outgoing.count > 0) { 662 strscpy(fh->ser[i].name, gflb->compatible, 663 sizeof(fh->ser[i].name)); 664 fh->ser[i].data = private->outgoing.data; 665 fh->ser[i].count = private->outgoing.count; 666 i++; 667 } 668 } 669 670 fh->header_ser->count = i; 671 } 672