percpu, module: implement and use is_kernel/module_percpu_address()

lockdep has custom code to check whether a pointer belongs to static
percpu area which is somewhat broken.  Implement proper
is_kernel/module_percpu_address() and replace the custom code.

On UP, percpu variables are regular static variables and can't be
distinguished from them.  Always return %false on UP.

Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Ingo Molnar <mingo@redhat.com>
This commit is contained in:
Tejun Heo
2010-03-10 18:57:54 +09:00
parent 259354deaa
commit 10fad5e46f
5 changed files with 77 additions and 16 deletions

View File

@@ -582,9 +582,6 @@ static int static_obj(void *obj)
unsigned long start = (unsigned long) &_stext,
end = (unsigned long) &_end,
addr = (unsigned long) obj;
#ifdef CONFIG_SMP
int i;
#endif
/*
* static variable?
@@ -595,24 +592,16 @@ static int static_obj(void *obj)
if (arch_is_kernel_data(addr))
return 1;
#ifdef CONFIG_SMP
/*
* percpu var?
* in-kernel percpu var?
*/
for_each_possible_cpu(i) {
start = (unsigned long) &__per_cpu_start + per_cpu_offset(i);
end = (unsigned long) &__per_cpu_start + PERCPU_ENOUGH_ROOM
+ per_cpu_offset(i);
if ((addr >= start) && (addr < end))
return 1;
}
#endif
if (is_kernel_percpu_address(addr))
return 1;
/*
* module var?
* module static or percpu var?
*/
return is_module_address(addr);
return is_module_address(addr) || is_module_percpu_address(addr);
}
/*

View File

@@ -415,6 +415,40 @@ static void percpu_modcopy(struct module *mod,
memcpy(per_cpu_ptr(mod->percpu, cpu), from, size);
}
/**
* is_module_percpu_address - test whether address is from module static percpu
* @addr: address to test
*
* Test whether @addr belongs to module static percpu area.
*
* RETURNS:
* %true if @addr is from module static percpu area
*/
bool is_module_percpu_address(unsigned long addr)
{
struct module *mod;
unsigned int cpu;
preempt_disable();
list_for_each_entry_rcu(mod, &modules, list) {
if (!mod->percpu_size)
continue;
for_each_possible_cpu(cpu) {
void *start = per_cpu_ptr(mod->percpu, cpu);
if ((void *)addr >= start &&
(void *)addr < start + mod->percpu_size) {
preempt_enable();
return true;
}
}
}
preempt_enable();
return false;
}
#else /* ... !CONFIG_SMP */
static inline void __percpu *mod_percpu(struct module *mod)
@@ -441,6 +475,10 @@ static inline void percpu_modcopy(struct module *mod,
/* pcpusec should be 0, and size of that section should be 0. */
BUG_ON(size != 0);
}
bool is_module_percpu_address(unsigned long addr)
{
return false;
}
#endif /* CONFIG_SMP */