This commit is contained in:
Mark Brown
2026-07-31 13:59:43 +01:00
4 changed files with 45 additions and 16 deletions
+9 -2
View File
@@ -173,7 +173,9 @@ struct liveupdate_flb_ops {
* @lock: A mutex that protects all fields within this structure, providing
* the synchronization service for the FLB's ops.
* @finished: True once the FLB's finish() callback has run.
* @retrieved: True once the FLB's retrieve() callback has run.
* @retrieve_status: Status code indicating whether retrieve() has been
* attempted. 0 means not attempted, 1 means successful,
* and negative value means it failed with that error code.
*/
struct luo_flb_private_state {
refcount_t count;
@@ -181,7 +183,7 @@ struct luo_flb_private_state {
void *obj;
struct mutex lock;
bool finished;
bool retrieved;
int retrieve_status;
};
/*
@@ -243,6 +245,7 @@ int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp);
void liveupdate_flb_put_incoming(struct liveupdate_flb *flb);
int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp);
void liveupdate_flb_put_outgoing(struct liveupdate_flb *flb);
#else /* CONFIG_LIVEUPDATE */
@@ -292,5 +295,9 @@ static inline int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb,
return -EOPNOTSUPP;
}
static inline void liveupdate_flb_put_outgoing(struct liveupdate_flb *flb)
{
}
#endif /* CONFIG_LIVEUPDATE */
#endif /* _LINUX_LIVEUPDATE_H */
+17 -7
View File
@@ -38,6 +38,16 @@
#include "../kexec_internal.h"
#include "kexec_handover_internal.h"
/*
* This is the minimal alignment required by deferred struct page init.
* deferred_init_memmap_chunk frees memory to the buddy allocator, which looks
* at the neighboring pages (up to MAX_PAGE_ORDER) to merge them.
* If KHO scratch is not aligned to that value, buddy can access uninitialized
* struct pages, which can cause a crash.
*/
#define SCRATCH_ALIGNMENT_BYTES (PAGE_SIZE * MAX_ORDER_NR_PAGES)
static_assert(SCRATCH_ALIGNMENT_BYTES >= CMA_MIN_ALIGNMENT_BYTES);
/* The magic token for preserved pages */
#define KHO_PAGE_MAGIC 0x4b484f50U /* ASCII for 'KHOP' */
@@ -491,7 +501,7 @@ static int __init kho_preserved_memory_reserve(phys_addr_t phys,
struct page *page;
u64 sz;
sz = 1 << (order + PAGE_SHIFT);
sz = 1UL << (order + PAGE_SHIFT);
page = kho_get_preserved_page(phys, order);
/* Reserve the memory preserved in KHO in memblock */
@@ -640,8 +650,8 @@ static void __init scratch_size_update(void)
* Scratch areas are released as MIGRATE_CMA. Round them up to the right
* size.
*/
scratch_size_lowmem = round_up(scratch_size_lowmem, CMA_MIN_ALIGNMENT_BYTES);
scratch_size_global = round_up(scratch_size_global, CMA_MIN_ALIGNMENT_BYTES);
scratch_size_lowmem = round_up(scratch_size_lowmem, SCRATCH_ALIGNMENT_BYTES);
scratch_size_global = round_up(scratch_size_global, SCRATCH_ALIGNMENT_BYTES);
}
static phys_addr_t __init scratch_size_node(int nid)
@@ -656,7 +666,7 @@ static phys_addr_t __init scratch_size_node(int nid)
size = scratch_size_pernode;
}
return round_up(size, CMA_MIN_ALIGNMENT_BYTES);
return round_up(size, SCRATCH_ALIGNMENT_BYTES);
}
/**
@@ -692,7 +702,7 @@ static void __init kho_reserve_scratch(void)
* next kernel
*/
size = scratch_size_lowmem;
addr = memblock_phys_alloc_range(size, CMA_MIN_ALIGNMENT_BYTES, 0,
addr = memblock_phys_alloc_range(size, SCRATCH_ALIGNMENT_BYTES, 0,
ARCH_LOW_ADDRESS_LIMIT);
if (!addr) {
pr_err("Failed to reserve lowmem scratch buffer\n");
@@ -705,7 +715,7 @@ static void __init kho_reserve_scratch(void)
/* reserve large contiguous area for allocations without nid */
size = scratch_size_global;
addr = memblock_phys_alloc(size, CMA_MIN_ALIGNMENT_BYTES);
addr = memblock_phys_alloc(size, SCRATCH_ALIGNMENT_BYTES);
if (!addr) {
pr_err("Failed to reserve global scratch buffer\n");
goto err_free_scratch_areas;
@@ -721,7 +731,7 @@ static void __init kho_reserve_scratch(void)
*/
for_each_node_state(nid, N_MEMORY) {
size = scratch_size_node(nid);
addr = memblock_alloc_range_nid(size, CMA_MIN_ALIGNMENT_BYTES,
addr = memblock_alloc_range_nid(size, SCRATCH_ALIGNMENT_BYTES,
0, MEMBLOCK_ALLOC_ACCESSIBLE,
nid, true);
if (!addr) {
+14 -6
View File
@@ -133,7 +133,7 @@ static int luo_flb_file_preserve_one(struct liveupdate_flb *flb)
return 0;
}
static void luo_flb_file_unpreserve_one(struct liveupdate_flb *flb)
void liveupdate_flb_put_outgoing(struct liveupdate_flb *flb)
{
struct luo_flb_private *private = luo_flb_get_private(flb);
@@ -168,7 +168,10 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
if (private->incoming.finished)
return -ENODATA;
if (private->incoming.retrieved)
if (private->incoming.retrieve_status < 0)
return private->incoming.retrieve_status;
if (private->incoming.retrieve_status > 0)
return 0;
if (!fh->active)
@@ -194,12 +197,13 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb)
err = flb->ops->retrieve(&args);
if (err) {
private->incoming.retrieve_status = err;
module_put(flb->ops->owner);
return err;
}
private->incoming.obj = args.obj;
private->incoming.retrieved = true;
private->incoming.retrieve_status = 1;
return 0;
}
@@ -213,7 +217,7 @@ void liveupdate_flb_put_incoming(struct liveupdate_flb *flb)
if (!refcount_dec_and_test(&private->incoming.count))
return;
if (!private->incoming.retrieved) {
if (private->incoming.retrieve_status <= 0) {
int err = luo_flb_retrieve_one(flb);
if (WARN_ON(err))
@@ -264,7 +268,7 @@ int luo_flb_file_preserve(struct liveupdate_file_handler *fh)
exit_err:
list_for_each_entry_continue_reverse(iter, flb_list, list)
luo_flb_file_unpreserve_one(iter->flb);
liveupdate_flb_put_outgoing(iter->flb);
up_read(&luo_register_rwlock);
return err;
@@ -289,7 +293,7 @@ void luo_flb_file_unpreserve(struct liveupdate_file_handler *fh)
guard(rwsem_read)(&luo_register_rwlock);
list_for_each_entry_reverse(iter, flb_list, list)
luo_flb_file_unpreserve_one(iter->flb);
liveupdate_flb_put_outgoing(iter->flb);
}
/**
@@ -544,6 +548,10 @@ int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp)
return -EOPNOTSUPP;
guard(mutex)(&private->outgoing.lock);
if (!private->outgoing.obj)
return -ENOENT;
refcount_inc(&private->outgoing.count);
*objp = private->outgoing.obj;
return 0;
+5 -1
View File
@@ -316,8 +316,12 @@ static int luo_session_finish(struct luo_session *session,
struct luo_ucmd *ucmd)
{
struct liveupdate_session_finish *argp = ucmd->cmd;
int err = luo_session_finish_one(session);
int err;
if (argp->reserved)
return -EINVAL;
err = luo_session_finish_one(session);
if (err)
return err;