]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
LoongArch: Fix calling smp_processor_id() in preemptible code
authorXi Ruoyao <xry111@xry111.site>
Mon, 16 Mar 2026 02:36:01 +0000 (10:36 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Mon, 16 Mar 2026 02:36:01 +0000 (10:36 +0800)
Fix the warning:

  BUG: using smp_processor_id() in preemptible [00000000] code: systemd/1
  caller is larch_insn_text_copy+0x40/0xf0

Simply changing it to raw_smp_processor_id() is not enough: if preempt
and CPU hotplug happens after raw_smp_processor_id() but before calling
stop_machine(), the CPU where raw_smp_processor_id() has run may become
offline when stop_machine() and no CPU will run copy_to_kernel_nofault()
in text_copy_cb().  Thus guard the larch_insn_text_copy() calls with
cpus_read_lock() and change stop_machine() to stop_machine_cpuslocked()
to prevent this.

I've considered moving the locks inside larch_insn_text_copy() but
doing so seems not an easy hack. In bpf_arch_text_poke() obviously the
memcpy() call must be guarded by text_mutex, so we have to leave the
acquire of text_mutex out of larch_insn_text_copy(). But in the entire
kernel the acquire of mutexes is always after cpus_read_lock(), so we
cannot put cpus_read_lock() into larch_insn_text_copy() while leaving
the text_mutex acquire out (or we risk a deadlock due to inconsistent
lock acquire order). So let's fix the bug first and leave the posssible
refactor as future work.

Fixes: 9fbd18cf4c69 ("LoongArch: BPF: Add dynamic code modification support")
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
arch/loongarch/kernel/inst.c
arch/loongarch/net/bpf_jit.c

index bf037f0c6b26c9dd0fa7c2c12e392be2175f5962..25fdb933119d0531e4a84b505d264e8f611b2f56 100644 (file)
@@ -263,14 +263,20 @@ int larch_insn_text_copy(void *dst, void *src, size_t len)
                .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);
+       ret = stop_machine_cpuslocked(text_copy_cb, &copy, cpu_online_mask);
        set_memory_rox(start, (end - start) / PAGE_SIZE);
 
        return ret;
index 3bd89f55960d98da1eb015405badc8c03d0a24c7..e8e0ad34928c3b50ced4ee1a2893feb5c2357370 100644 (file)
@@ -1379,9 +1379,11 @@ void *bpf_arch_text_copy(void *dst, void *src, size_t len)
 {
        int ret;
 
+       cpus_read_lock();
        mutex_lock(&text_mutex);
        ret = larch_insn_text_copy(dst, src, len);
        mutex_unlock(&text_mutex);
+       cpus_read_unlock();
 
        return ret ? ERR_PTR(-EINVAL) : dst;
 }
@@ -1429,10 +1431,12 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
        if (ret)
                return ret;
 
+       cpus_read_lock();
        mutex_lock(&text_mutex);
        if (memcmp(ip, new_insns, LOONGARCH_LONG_JUMP_NBYTES))
                ret = larch_insn_text_copy(ip, new_insns, LOONGARCH_LONG_JUMP_NBYTES);
        mutex_unlock(&text_mutex);
+       cpus_read_unlock();
 
        return ret;
 }
@@ -1450,10 +1454,12 @@ int bpf_arch_text_invalidate(void *dst, size_t len)
        for (i = 0; i < (len / sizeof(u32)); i++)
                inst[i] = INSN_BREAK;
 
+       cpus_read_lock();
        mutex_lock(&text_mutex);
        if (larch_insn_text_copy(dst, inst, len))
                ret = -EINVAL;
        mutex_unlock(&text_mutex);
+       cpus_read_unlock();
 
        kvfree(inst);