You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branches 'perf-fixes-for-linus' and 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: jump label: Add work around to i386 gcc asm goto bug x86, ftrace: Use safe noops, drop trap test jump_label: Fix unaligned traps on sparc. jump label: Make arch_jump_label_text_poke_early() optional jump label: Fix error with preempt disable holding mutex oprofile: Remove deprecated use of flush_scheduled_work() oprofile: Fix the hang while taking the cpu offline jump label: Fix deadlock b/w jump_label_mutex vs. text_mutex jump label: Fix module __init section race * 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: x86: Check irq_remapped instead of remapping_enabled in destroy_irq()
This commit is contained in:
+66
-11
@@ -39,6 +39,16 @@ struct jump_label_module_entry {
|
||||
struct module *mod;
|
||||
};
|
||||
|
||||
void jump_label_lock(void)
|
||||
{
|
||||
mutex_lock(&jump_label_mutex);
|
||||
}
|
||||
|
||||
void jump_label_unlock(void)
|
||||
{
|
||||
mutex_unlock(&jump_label_mutex);
|
||||
}
|
||||
|
||||
static int jump_label_cmp(const void *a, const void *b)
|
||||
{
|
||||
const struct jump_entry *jea = a;
|
||||
@@ -152,7 +162,7 @@ void jump_label_update(unsigned long key, enum jump_label_type type)
|
||||
struct jump_label_module_entry *e_module;
|
||||
int count;
|
||||
|
||||
mutex_lock(&jump_label_mutex);
|
||||
jump_label_lock();
|
||||
entry = get_jump_label_entry((jump_label_t)key);
|
||||
if (entry) {
|
||||
count = entry->nr_entries;
|
||||
@@ -168,13 +178,14 @@ void jump_label_update(unsigned long key, enum jump_label_type type)
|
||||
count = e_module->nr_entries;
|
||||
iter = e_module->table;
|
||||
while (count--) {
|
||||
if (kernel_text_address(iter->code))
|
||||
if (iter->key &&
|
||||
kernel_text_address(iter->code))
|
||||
arch_jump_label_transform(iter, type);
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&jump_label_mutex);
|
||||
jump_label_unlock();
|
||||
}
|
||||
|
||||
static int addr_conflict(struct jump_entry *entry, void *start, void *end)
|
||||
@@ -231,6 +242,7 @@ out:
|
||||
* overlaps with any of the jump label patch addresses. Code
|
||||
* that wants to modify kernel text should first verify that
|
||||
* it does not overlap with any of the jump label addresses.
|
||||
* Caller must hold jump_label_mutex.
|
||||
*
|
||||
* returns 1 if there is an overlap, 0 otherwise
|
||||
*/
|
||||
@@ -241,7 +253,6 @@ int jump_label_text_reserved(void *start, void *end)
|
||||
struct jump_entry *iter_stop = __start___jump_table;
|
||||
int conflict = 0;
|
||||
|
||||
mutex_lock(&jump_label_mutex);
|
||||
iter = iter_start;
|
||||
while (iter < iter_stop) {
|
||||
if (addr_conflict(iter, start, end)) {
|
||||
@@ -256,10 +267,16 @@ int jump_label_text_reserved(void *start, void *end)
|
||||
conflict = module_conflict(start, end);
|
||||
#endif
|
||||
out:
|
||||
mutex_unlock(&jump_label_mutex);
|
||||
return conflict;
|
||||
}
|
||||
|
||||
/*
|
||||
* Not all archs need this.
|
||||
*/
|
||||
void __weak arch_jump_label_text_poke_early(jump_label_t addr)
|
||||
{
|
||||
}
|
||||
|
||||
static __init int init_jump_label(void)
|
||||
{
|
||||
int ret;
|
||||
@@ -267,7 +284,7 @@ static __init int init_jump_label(void)
|
||||
struct jump_entry *iter_stop = __stop___jump_table;
|
||||
struct jump_entry *iter;
|
||||
|
||||
mutex_lock(&jump_label_mutex);
|
||||
jump_label_lock();
|
||||
ret = build_jump_label_hashtable(__start___jump_table,
|
||||
__stop___jump_table);
|
||||
iter = iter_start;
|
||||
@@ -275,7 +292,7 @@ static __init int init_jump_label(void)
|
||||
arch_jump_label_text_poke_early(iter->code);
|
||||
iter++;
|
||||
}
|
||||
mutex_unlock(&jump_label_mutex);
|
||||
jump_label_unlock();
|
||||
return ret;
|
||||
}
|
||||
early_initcall(init_jump_label);
|
||||
@@ -366,6 +383,39 @@ static void remove_jump_label_module(struct module *mod)
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_jump_label_module_init(struct module *mod)
|
||||
{
|
||||
struct hlist_head *head;
|
||||
struct hlist_node *node, *node_next, *module_node, *module_node_next;
|
||||
struct jump_label_entry *e;
|
||||
struct jump_label_module_entry *e_module;
|
||||
struct jump_entry *iter;
|
||||
int i, count;
|
||||
|
||||
/* if the module doesn't have jump label entries, just return */
|
||||
if (!mod->num_jump_entries)
|
||||
return;
|
||||
|
||||
for (i = 0; i < JUMP_LABEL_TABLE_SIZE; i++) {
|
||||
head = &jump_label_table[i];
|
||||
hlist_for_each_entry_safe(e, node, node_next, head, hlist) {
|
||||
hlist_for_each_entry_safe(e_module, module_node,
|
||||
module_node_next,
|
||||
&(e->modules), hlist) {
|
||||
if (e_module->mod != mod)
|
||||
continue;
|
||||
count = e_module->nr_entries;
|
||||
iter = e_module->table;
|
||||
while (count--) {
|
||||
if (within_module_init(iter->code, mod))
|
||||
iter->key = 0;
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
jump_label_module_notify(struct notifier_block *self, unsigned long val,
|
||||
void *data)
|
||||
@@ -375,16 +425,21 @@ jump_label_module_notify(struct notifier_block *self, unsigned long val,
|
||||
|
||||
switch (val) {
|
||||
case MODULE_STATE_COMING:
|
||||
mutex_lock(&jump_label_mutex);
|
||||
jump_label_lock();
|
||||
ret = add_jump_label_module(mod);
|
||||
if (ret)
|
||||
remove_jump_label_module(mod);
|
||||
mutex_unlock(&jump_label_mutex);
|
||||
jump_label_unlock();
|
||||
break;
|
||||
case MODULE_STATE_GOING:
|
||||
mutex_lock(&jump_label_mutex);
|
||||
jump_label_lock();
|
||||
remove_jump_label_module(mod);
|
||||
mutex_unlock(&jump_label_mutex);
|
||||
jump_label_unlock();
|
||||
break;
|
||||
case MODULE_STATE_LIVE:
|
||||
jump_label_lock();
|
||||
remove_jump_label_module_init(mod);
|
||||
jump_label_unlock();
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
||||
+16
-10
@@ -1145,14 +1145,13 @@ int __kprobes register_kprobe(struct kprobe *p)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
jump_label_lock();
|
||||
preempt_disable();
|
||||
if (!kernel_text_address((unsigned long) p->addr) ||
|
||||
in_kprobes_functions((unsigned long) p->addr) ||
|
||||
ftrace_text_reserved(p->addr, p->addr) ||
|
||||
jump_label_text_reserved(p->addr, p->addr)) {
|
||||
preempt_enable();
|
||||
return -EINVAL;
|
||||
}
|
||||
jump_label_text_reserved(p->addr, p->addr))
|
||||
goto fail_with_jump_label;
|
||||
|
||||
/* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */
|
||||
p->flags &= KPROBE_FLAG_DISABLED;
|
||||
@@ -1166,10 +1165,9 @@ int __kprobes register_kprobe(struct kprobe *p)
|
||||
* We must hold a refcount of the probed module while updating
|
||||
* its code to prohibit unexpected unloading.
|
||||
*/
|
||||
if (unlikely(!try_module_get(probed_mod))) {
|
||||
preempt_enable();
|
||||
return -EINVAL;
|
||||
}
|
||||
if (unlikely(!try_module_get(probed_mod)))
|
||||
goto fail_with_jump_label;
|
||||
|
||||
/*
|
||||
* If the module freed .init.text, we couldn't insert
|
||||
* kprobes in there.
|
||||
@@ -1177,16 +1175,18 @@ int __kprobes register_kprobe(struct kprobe *p)
|
||||
if (within_module_init((unsigned long)p->addr, probed_mod) &&
|
||||
probed_mod->state != MODULE_STATE_COMING) {
|
||||
module_put(probed_mod);
|
||||
preempt_enable();
|
||||
return -EINVAL;
|
||||
goto fail_with_jump_label;
|
||||
}
|
||||
}
|
||||
preempt_enable();
|
||||
jump_label_unlock();
|
||||
|
||||
p->nmissed = 0;
|
||||
INIT_LIST_HEAD(&p->list);
|
||||
mutex_lock(&kprobe_mutex);
|
||||
|
||||
jump_label_lock(); /* needed to call jump_label_text_reserved() */
|
||||
|
||||
get_online_cpus(); /* For avoiding text_mutex deadlock. */
|
||||
mutex_lock(&text_mutex);
|
||||
|
||||
@@ -1214,12 +1214,18 @@ int __kprobes register_kprobe(struct kprobe *p)
|
||||
out:
|
||||
mutex_unlock(&text_mutex);
|
||||
put_online_cpus();
|
||||
jump_label_unlock();
|
||||
mutex_unlock(&kprobe_mutex);
|
||||
|
||||
if (probed_mod)
|
||||
module_put(probed_mod);
|
||||
|
||||
return ret;
|
||||
|
||||
fail_with_jump_label:
|
||||
preempt_enable();
|
||||
jump_label_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_kprobe);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user