hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/arch/riscv/kernel/patch.c
....@@ -11,6 +11,7 @@
1111 #include <asm/kprobes.h>
1212 #include <asm/cacheflush.h>
1313 #include <asm/fixmap.h>
14
+#include <asm/ftrace.h>
1415 #include <asm/patch.h>
1516
1617 struct patch_insn {
....@@ -18,6 +19,8 @@
1819 u32 insn;
1920 atomic_t cpu_count;
2021 };
22
+
23
+int riscv_patch_in_stop_machine = false;
2124
2225 #ifdef CONFIG_MMU
2326 static void *patch_map(void *addr, int fixmap)
....@@ -55,8 +58,15 @@
5558 * Before reaching here, it was expected to lock the text_mutex
5659 * already, so we don't need to give another lock here and could
5760 * ensure that it was safe between each cores.
61
+ *
62
+ * We're currently using stop_machine() for ftrace & kprobes, and while
63
+ * that ensures text_mutex is held before installing the mappings it
64
+ * does not ensure text_mutex is held by the calling thread. That's
65
+ * safe but triggers a lockdep failure, so just elide it for that
66
+ * specific case.
5867 */
59
- lockdep_assert_held(&text_mutex);
68
+ if (!riscv_patch_in_stop_machine)
69
+ lockdep_assert_held(&text_mutex);
6070
6171 if (across_pages)
6272 patch_map(addr + len, FIX_TEXT_POKE1);
....@@ -117,13 +127,25 @@
117127
118128 int patch_text(void *addr, u32 insn)
119129 {
130
+ int ret;
120131 struct patch_insn patch = {
121132 .addr = addr,
122133 .insn = insn,
123134 .cpu_count = ATOMIC_INIT(0),
124135 };
125136
126
- return stop_machine_cpuslocked(patch_text_cb,
127
- &patch, cpu_online_mask);
137
+ /*
138
+ * kprobes takes text_mutex, before calling patch_text(), but as we call
139
+ * calls stop_machine(), the lockdep assertion in patch_insn_write()
140
+ * gets confused by the context in which the lock is taken.
141
+ * Instead, ensure the lock is held before calling stop_machine(), and
142
+ * set riscv_patch_in_stop_machine to skip the check in
143
+ * patch_insn_write().
144
+ */
145
+ lockdep_assert_held(&text_mutex);
146
+ riscv_patch_in_stop_machine = true;
147
+ ret = stop_machine_cpuslocked(patch_text_cb, &patch, cpu_online_mask);
148
+ riscv_patch_in_stop_machine = false;
149
+ return ret;
128150 }
129151 NOKPROBE_SYMBOL(patch_text);