|
@@ -591,17 +591,21 @@ static atomic_t stop_machine_first;
|
|
static int wrote_text;
|
|
static int wrote_text;
|
|
|
|
|
|
struct text_poke_params {
|
|
struct text_poke_params {
|
|
- void *addr;
|
|
|
|
- const void *opcode;
|
|
|
|
- size_t len;
|
|
|
|
|
|
+ struct text_poke_param *params;
|
|
|
|
+ int nparams;
|
|
};
|
|
};
|
|
|
|
|
|
static int __kprobes stop_machine_text_poke(void *data)
|
|
static int __kprobes stop_machine_text_poke(void *data)
|
|
{
|
|
{
|
|
struct text_poke_params *tpp = data;
|
|
struct text_poke_params *tpp = data;
|
|
|
|
+ struct text_poke_param *p;
|
|
|
|
+ int i;
|
|
|
|
|
|
if (atomic_dec_and_test(&stop_machine_first)) {
|
|
if (atomic_dec_and_test(&stop_machine_first)) {
|
|
- text_poke(tpp->addr, tpp->opcode, tpp->len);
|
|
|
|
|
|
+ for (i = 0; i < tpp->nparams; i++) {
|
|
|
|
+ p = &tpp->params[i];
|
|
|
|
+ text_poke(p->addr, p->opcode, p->len);
|
|
|
|
+ }
|
|
smp_wmb(); /* Make sure other cpus see that this has run */
|
|
smp_wmb(); /* Make sure other cpus see that this has run */
|
|
wrote_text = 1;
|
|
wrote_text = 1;
|
|
} else {
|
|
} else {
|
|
@@ -610,8 +614,12 @@ static int __kprobes stop_machine_text_poke(void *data)
|
|
smp_mb(); /* Load wrote_text before following execution */
|
|
smp_mb(); /* Load wrote_text before following execution */
|
|
}
|
|
}
|
|
|
|
|
|
- flush_icache_range((unsigned long)tpp->addr,
|
|
|
|
- (unsigned long)tpp->addr + tpp->len);
|
|
|
|
|
|
+ for (i = 0; i < tpp->nparams; i++) {
|
|
|
|
+ p = &tpp->params[i];
|
|
|
|
+ flush_icache_range((unsigned long)p->addr,
|
|
|
|
+ (unsigned long)p->addr + p->len);
|
|
|
|
+ }
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -631,10 +639,13 @@ static int __kprobes stop_machine_text_poke(void *data)
|
|
void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len)
|
|
void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len)
|
|
{
|
|
{
|
|
struct text_poke_params tpp;
|
|
struct text_poke_params tpp;
|
|
|
|
+ struct text_poke_param p;
|
|
|
|
|
|
- tpp.addr = addr;
|
|
|
|
- tpp.opcode = opcode;
|
|
|
|
- tpp.len = len;
|
|
|
|
|
|
+ p.addr = addr;
|
|
|
|
+ p.opcode = opcode;
|
|
|
|
+ p.len = len;
|
|
|
|
+ tpp.params = &p;
|
|
|
|
+ tpp.nparams = 1;
|
|
atomic_set(&stop_machine_first, 1);
|
|
atomic_set(&stop_machine_first, 1);
|
|
wrote_text = 0;
|
|
wrote_text = 0;
|
|
/* Use __stop_machine() because the caller already got online_cpus. */
|
|
/* Use __stop_machine() because the caller already got online_cpus. */
|
|
@@ -642,6 +653,26 @@ void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len)
|
|
return addr;
|
|
return addr;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * text_poke_smp_batch - Update instructions on a live kernel on SMP
|
|
|
|
+ * @params: an array of text_poke parameters
|
|
|
|
+ * @n: the number of elements in params.
|
|
|
|
+ *
|
|
|
|
+ * Modify multi-byte instruction by using stop_machine() on SMP. Since the
|
|
|
|
+ * stop_machine() is heavy task, it is better to aggregate text_poke requests
|
|
|
|
+ * and do it once if possible.
|
|
|
|
+ *
|
|
|
|
+ * Note: Must be called under get_online_cpus() and text_mutex.
|
|
|
|
+ */
|
|
|
|
+void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n)
|
|
|
|
+{
|
|
|
|
+ struct text_poke_params tpp = {.params = params, .nparams = n};
|
|
|
|
+
|
|
|
|
+ atomic_set(&stop_machine_first, 1);
|
|
|
|
+ wrote_text = 0;
|
|
|
|
+ stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
|
|
|
|
+}
|
|
|
|
+
|
|
#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
|
|
#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
|
|
|
|
|
|
#ifdef CONFIG_X86_64
|
|
#ifdef CONFIG_X86_64
|