summaryrefslogtreecommitdiff
path: root/arch/loongarch/kernel/inst.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/loongarch/kernel/inst.c')
-rw-r--r--arch/loongarch/kernel/inst.c31
1 files changed, 25 insertions, 6 deletions
diff --git a/arch/loongarch/kernel/inst.c b/arch/loongarch/kernel/inst.c
index bf037f0c6b26..1a728082944c 100644
--- a/arch/loongarch/kernel/inst.c
+++ b/arch/loongarch/kernel/inst.c
@@ -246,32 +246,51 @@ static int text_copy_cb(void *data)
if (smp_processor_id() == copy->cpu) {
ret = copy_to_kernel_nofault(copy->dst, copy->src, copy->len);
- if (ret)
+ if (ret) {
pr_err("%s: operation failed\n", __func__);
+ return ret;
+ }
}
flush_icache_range((unsigned long)copy->dst, (unsigned long)copy->dst + copy->len);
- return ret;
+ return 0;
}
int larch_insn_text_copy(void *dst, void *src, size_t len)
{
int ret = 0;
+ int err = 0;
size_t start, end;
struct insn_copy copy = {
.dst = dst,
.src = src,
.len = len,
- .cpu = smp_processor_id(),
+ .cpu = raw_smp_processor_id(),
};
+ /*
+ * Ensure copy.cpu won't be hot removed before stop_machine.
+ * If it is removed nobody will really update the text.
+ */
+ lockdep_assert_cpus_held();
+
start = round_down((size_t)dst, PAGE_SIZE);
end = round_up((size_t)dst + len, PAGE_SIZE);
- set_memory_rw(start, (end - start) / PAGE_SIZE);
- ret = stop_machine(text_copy_cb, &copy, cpu_online_mask);
- set_memory_rox(start, (end - start) / PAGE_SIZE);
+ err = set_memory_rw(start, (end - start) / PAGE_SIZE);
+ if (err) {
+ pr_info("%s: set_memory_rw() failed\n", __func__);
+ return err;
+ }
+
+ ret = stop_machine_cpuslocked(text_copy_cb, &copy, cpu_online_mask);
+
+ err = set_memory_rox(start, (end - start) / PAGE_SIZE);
+ if (err) {
+ pr_info("%s: set_memory_rox() failed\n", __func__);
+ return err;
+ }
return ret;
}