Implement the LUO file handler (cpu_preserve_handler) and early boot incoming CPU adoption for /sys/devices/system/cpu/cpuX/preserve fds.
Signed-off-by: Pasha Tatashin <[email protected]> --- kernel/liveupdate/cpu_preserve.c | 189 ++++++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 4 deletions(-) diff --git a/kernel/liveupdate/cpu_preserve.c b/kernel/liveupdate/cpu_preserve.c index 2f92dfee82b1..9a039ba9e912 100644 --- a/kernel/liveupdate/cpu_preserve.c +++ b/kernel/liveupdate/cpu_preserve.c @@ -837,8 +837,10 @@ void __cpu_preserved_text cpu_preserved_set_dead(int cpu) { struct cpu_preserved_pcpu_ser *ser = cpu_preserved_get_pcpu_ser(cpu); - if (ser) - WRITE_ONCE(ser->workload, CPU_PRESERVED_DEAD); + if (ser) { + smp_store_release(&ser->workload, CPU_PRESERVED_DEAD); + cpu_preserved_clean(ser); + } } EXPORT_SYMBOL_GPL(cpu_preserved_set_dead); @@ -1097,8 +1099,6 @@ void __cpu_preserved_text cpu_preserved_park_loop(int cpu) switch (READ_ONCE(ser->workload)) { case CPU_PRESERVED_EXITING: case CPU_PRESERVED_DEAD: - WRITE_ONCE(ser->workload, CPU_PRESERVED_DEAD); - cpu_preserved_clean(ser); return; case CPU_PRESERVED_WORKLOAD: cpu_preserved_run_workload(ser, pcpu); @@ -1131,6 +1131,7 @@ void cpu_preserved_park(int cpu) } else { cpu_preserved_park_loop(cpu); arch_cpu_preserved_park_finish(cpu); + cpu_preserved_set_dead(cpu); } } EXPORT_SYMBOL_GPL(cpu_preserved_park); @@ -1498,6 +1499,171 @@ static struct liveupdate_flb cpu_preserved_flb = { .compatible = CPU_PRESERVED_LUO_FLB_COMPATIBLE, }; +/* + * LUO File Handler Callbacks for /sys/devices/system/cpu/cpu<N>/preserve + */ +static int file_to_cpu(struct file *file, unsigned int *cpup) +{ + struct dentry *dentry, *parent; + unsigned int cpu; + + if (!file || !file->f_path.dentry) + return -EINVAL; + + if (file_inode(file)->i_sb->s_magic != SYSFS_MAGIC) + return -EINVAL; + + dentry = file->f_path.dentry; + if (strcmp(dentry->d_name.name, "preserve")) + return -EINVAL; + + parent = dentry->d_parent; + if (!parent || sscanf(parent->d_name.name, "cpu%u", &cpu) != 1) + return -EINVAL; + + if (cpu >= nr_cpu_ids || !cpu_possible(cpu) || + !cpu_is_hotpluggable(cpu)) { + return -EINVAL; + } + + *cpup = cpu; + return 0; +} + +static bool cpu_preserve_can_preserve(struct liveupdate_file_handler *handler, + struct file *file) +{ + unsigned int cpu; + + return IS_ENABLED(CONFIG_LIVEUPDATE_ONCORE) && file_to_cpu(file, &cpu) == 0; +} + +static int cpu_preserve_preserve(struct liveupdate_file_op_args *args) +{ + struct cpu_preserved_file_ser *fser; + unsigned int cpu; + int ret; + + ret = file_to_cpu(args->file, &cpu); + if (ret) + return ret; + + ret = cpu_preserve(cpu); + if (ret) + return ret; + + fser = kho_alloc_preserve(sizeof(*fser)); + if (IS_ERR(fser)) { + cpu_unpreserve(cpu); + return PTR_ERR(fser); + } + + memset(fser, 0, sizeof(*fser)); + fser->cpu = cpu; + + scoped_guard(mutex, &cpu_preserved_lock) + fser->stack_pa = cpu_preserved_outgoing.pcpus[cpu].stack_pa; + + args->serialized_data = virt_to_phys(fser); + return 0; +} + +static void cpu_preserve_unpreserve(struct liveupdate_file_op_args *args) +{ + struct cpu_preserved_file_ser *fser; + unsigned int cpu; + + if (!args->serialized_data) + return; + + fser = phys_to_virt(args->serialized_data); + cpu = fser->cpu; + + cpu_unpreserve(cpu); + + kho_unpreserve_free(fser); +} + +static void cpu_preserve_restore_incoming_cpu(struct liveupdate_session *session, + struct cpu_preserved_file_ser *fser) +{ + unsigned int cpu = fser->cpu; + + scoped_guard(mutex, &cpu_preserved_lock) { + cpumask_set_cpu(cpu, &cpu_preserved_incoming.mask); + cpumask_set_cpu(cpu, &cpu_preserved_mask); + + if (!cpu_preserved_incoming.pcpus) { + cpu_preserved_incoming.pcpus = + kcalloc(nr_cpu_ids, + sizeof(*cpu_preserved_incoming.pcpus), + GFP_KERNEL); + WRITE_ONCE(cpu_preserved_host_pcpus_va, + cpu_preserved_incoming.pcpus); + cpu_preserved_clean(&cpu_preserved_host_pcpus_va); + } + + if (cpu_preserved_incoming.pcpus) + cpu_preserved_incoming.pcpus[cpu].stack_pa = fser->stack_pa; + + cpu_preserved_clean(&cpu_preserved_mask); + } +} + +static int cpu_preserve_retrieve(struct liveupdate_file_op_args *args) +{ + struct cpu_preserved_file_ser *fser; + struct file *file; + char path[64]; + + if (!args->serialized_data) + return -EINVAL; + + fser = phys_to_virt(args->serialized_data); + + snprintf(path, sizeof(path), + "/sys/devices/system/cpu/cpu%u/preserve", fser->cpu); + file = filp_open(path, O_RDONLY, 0); + if (IS_ERR(file)) + return PTR_ERR(file); + + args->file = file; + cpu_preserve_restore_incoming_cpu(args->session, fser); + cpu_preserved_detach_workload(fser->cpu); + + return 0; +} + +static void cpu_preserve_finish(struct liveupdate_file_op_args *args) +{ + struct cpu_preserved_file_ser *fser; + + if (!args->serialized_data) + return; + + fser = phys_to_virt(args->serialized_data); + if (args->retrieve_status <= 0) + cpu_preserve_restore_incoming_cpu(args->session, fser); + + cpu_unpreserve(fser->cpu); + + kho_restore_free(fser); +} + +static const struct liveupdate_file_ops cpu_preserve_file_ops = { + .can_preserve = cpu_preserve_can_preserve, + .preserve = cpu_preserve_preserve, + .retrieve = cpu_preserve_retrieve, + .unpreserve = cpu_preserve_unpreserve, + .finish = cpu_preserve_finish, + .owner = THIS_MODULE, +}; + +static struct liveupdate_file_handler cpu_preserve_handler = { + .ops = &cpu_preserve_file_ops, + .compatible = CPU_PRESERVED_LUO_FH_COMPATIBLE, +}; + static int cpu_preserve_reboot_notify(struct notifier_block *nb, unsigned long action, void *data) { @@ -1555,6 +1721,21 @@ static int __init cpu_preserve_early_init(void) cpu_preserved_incoming.pcpus_ser = NULL; cpu_preserved_global_ser = NULL; + err = liveupdate_register_file_handler(&cpu_preserve_handler); + if (err && err != -EOPNOTSUPP) { + pr_err("Could not register cpu_preserve file handler: %pe\n", + ERR_PTR(err)); + return err; + } + + err = liveupdate_register_flb(&cpu_preserve_handler, + &cpu_preserved_flb); + if (err && err != -EOPNOTSUPP) { + pr_err("Could not register cpu_preserved FLB: %pe\n", + ERR_PTR(err)); + return err; + } + /* Retrieve incoming preserved CPUs before secondary CPU bringup */ if (liveupdate_enabled()) liveupdate_flb_get_incoming(&cpu_preserved_flb, &obj); -- 2.55.0.1082.g2b9226bbc0-goog

