Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus: module: convert to stop_machine_create/destroy. stop_machine: introduce stop_machine_create/destroy. parisc: fix module loading failure of large kernel modules module: fix module loading failure of large kernel modules for parisc module: fix warning of unused function when !CONFIG_PROC_FS kernel/module.c: compare symbol values when marking symbols as exported in /proc/kallsyms. remove CONFIG_KMOD
This commit is contained in:
@@ -269,8 +269,11 @@ out_release:
|
||||
|
||||
int __ref cpu_down(unsigned int cpu)
|
||||
{
|
||||
int err = 0;
|
||||
int err;
|
||||
|
||||
err = stop_machine_create();
|
||||
if (err)
|
||||
return err;
|
||||
cpu_maps_update_begin();
|
||||
|
||||
if (cpu_hotplug_disabled) {
|
||||
@@ -297,6 +300,7 @@ int __ref cpu_down(unsigned int cpu)
|
||||
|
||||
out:
|
||||
cpu_maps_update_done();
|
||||
stop_machine_destroy();
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(cpu_down);
|
||||
|
@@ -757,8 +757,16 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
|
||||
return -EFAULT;
|
||||
name[MODULE_NAME_LEN-1] = '\0';
|
||||
|
||||
if (mutex_lock_interruptible(&module_mutex) != 0)
|
||||
return -EINTR;
|
||||
/* Create stop_machine threads since free_module relies on
|
||||
* a non-failing stop_machine call. */
|
||||
ret = stop_machine_create();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (mutex_lock_interruptible(&module_mutex) != 0) {
|
||||
ret = -EINTR;
|
||||
goto out_stop;
|
||||
}
|
||||
|
||||
mod = find_module(name);
|
||||
if (!mod) {
|
||||
@@ -817,10 +825,12 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
|
||||
|
||||
out:
|
||||
mutex_unlock(&module_mutex);
|
||||
out_stop:
|
||||
stop_machine_destroy();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void print_unload_info(struct seq_file *m, struct module *mod)
|
||||
static inline void print_unload_info(struct seq_file *m, struct module *mod)
|
||||
{
|
||||
struct module_use *use;
|
||||
int printed_something = 0;
|
||||
@@ -893,7 +903,7 @@ void module_put(struct module *module)
|
||||
EXPORT_SYMBOL(module_put);
|
||||
|
||||
#else /* !CONFIG_MODULE_UNLOAD */
|
||||
static void print_unload_info(struct seq_file *m, struct module *mod)
|
||||
static inline void print_unload_info(struct seq_file *m, struct module *mod)
|
||||
{
|
||||
/* We don't know the usage count, or what modules are using. */
|
||||
seq_printf(m, " - -");
|
||||
@@ -1578,11 +1588,21 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Additional bytes needed by arch in front of individual sections */
|
||||
unsigned int __weak arch_mod_section_prepend(struct module *mod,
|
||||
unsigned int section)
|
||||
{
|
||||
/* default implementation just returns zero */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update size with this section: return offset. */
|
||||
static long get_offset(unsigned int *size, Elf_Shdr *sechdr)
|
||||
static long get_offset(struct module *mod, unsigned int *size,
|
||||
Elf_Shdr *sechdr, unsigned int section)
|
||||
{
|
||||
long ret;
|
||||
|
||||
*size += arch_mod_section_prepend(mod, section);
|
||||
ret = ALIGN(*size, sechdr->sh_addralign ?: 1);
|
||||
*size = ret + sechdr->sh_size;
|
||||
return ret;
|
||||
@@ -1622,7 +1642,7 @@ static void layout_sections(struct module *mod,
|
||||
|| strncmp(secstrings + s->sh_name,
|
||||
".init", 5) == 0)
|
||||
continue;
|
||||
s->sh_entsize = get_offset(&mod->core_size, s);
|
||||
s->sh_entsize = get_offset(mod, &mod->core_size, s, i);
|
||||
DEBUGP("\t%s\n", secstrings + s->sh_name);
|
||||
}
|
||||
if (m == 0)
|
||||
@@ -1640,7 +1660,7 @@ static void layout_sections(struct module *mod,
|
||||
|| strncmp(secstrings + s->sh_name,
|
||||
".init", 5) != 0)
|
||||
continue;
|
||||
s->sh_entsize = (get_offset(&mod->init_size, s)
|
||||
s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)
|
||||
| INIT_OFFSET_MASK);
|
||||
DEBUGP("\t%s\n", secstrings + s->sh_name);
|
||||
}
|
||||
@@ -1725,15 +1745,15 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int is_exported(const char *name, const struct module *mod)
|
||||
static int is_exported(const char *name, unsigned long value,
|
||||
const struct module *mod)
|
||||
{
|
||||
if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
|
||||
return 1;
|
||||
const struct kernel_symbol *ks;
|
||||
if (!mod)
|
||||
ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
|
||||
else
|
||||
if (mod && lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
|
||||
return ks != NULL && ks->value == value;
|
||||
}
|
||||
|
||||
/* As per nm */
|
||||
@@ -1865,6 +1885,13 @@ static noinline struct module *load_module(void __user *umod,
|
||||
/* vmalloc barfs on "unusual" numbers. Check here */
|
||||
if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* Create stop_machine threads since the error path relies on
|
||||
* a non-failing stop_machine call. */
|
||||
err = stop_machine_create();
|
||||
if (err)
|
||||
goto free_hdr;
|
||||
|
||||
if (copy_from_user(hdr, umod, len) != 0) {
|
||||
err = -EFAULT;
|
||||
goto free_hdr;
|
||||
@@ -2248,6 +2275,7 @@ static noinline struct module *load_module(void __user *umod,
|
||||
/* Get rid of temporary copy */
|
||||
vfree(hdr);
|
||||
|
||||
stop_machine_destroy();
|
||||
/* Done! */
|
||||
return mod;
|
||||
|
||||
@@ -2270,6 +2298,7 @@ static noinline struct module *load_module(void __user *umod,
|
||||
kfree(args);
|
||||
free_hdr:
|
||||
vfree(hdr);
|
||||
stop_machine_destroy();
|
||||
return ERR_PTR(err);
|
||||
|
||||
truncated:
|
||||
@@ -2504,7 +2533,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
|
||||
strlcpy(name, mod->strtab + mod->symtab[symnum].st_name,
|
||||
KSYM_NAME_LEN);
|
||||
strlcpy(module_name, mod->name, MODULE_NAME_LEN);
|
||||
*exported = is_exported(name, mod);
|
||||
*exported = is_exported(name, *value, mod);
|
||||
preempt_enable();
|
||||
return 0;
|
||||
}
|
||||
|
@@ -38,7 +38,10 @@ struct stop_machine_data {
|
||||
static unsigned int num_threads;
|
||||
static atomic_t thread_ack;
|
||||
static DEFINE_MUTEX(lock);
|
||||
|
||||
/* setup_lock protects refcount, stop_machine_wq and stop_machine_work. */
|
||||
static DEFINE_MUTEX(setup_lock);
|
||||
/* Users of stop_machine. */
|
||||
static int refcount;
|
||||
static struct workqueue_struct *stop_machine_wq;
|
||||
static struct stop_machine_data active, idle;
|
||||
static const cpumask_t *active_cpus;
|
||||
@@ -109,6 +112,43 @@ static int chill(void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stop_machine_create(void)
|
||||
{
|
||||
mutex_lock(&setup_lock);
|
||||
if (refcount)
|
||||
goto done;
|
||||
stop_machine_wq = create_rt_workqueue("kstop");
|
||||
if (!stop_machine_wq)
|
||||
goto err_out;
|
||||
stop_machine_work = alloc_percpu(struct work_struct);
|
||||
if (!stop_machine_work)
|
||||
goto err_out;
|
||||
done:
|
||||
refcount++;
|
||||
mutex_unlock(&setup_lock);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
if (stop_machine_wq)
|
||||
destroy_workqueue(stop_machine_wq);
|
||||
mutex_unlock(&setup_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stop_machine_create);
|
||||
|
||||
void stop_machine_destroy(void)
|
||||
{
|
||||
mutex_lock(&setup_lock);
|
||||
refcount--;
|
||||
if (refcount)
|
||||
goto done;
|
||||
destroy_workqueue(stop_machine_wq);
|
||||
free_percpu(stop_machine_work);
|
||||
done:
|
||||
mutex_unlock(&setup_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stop_machine_destroy);
|
||||
|
||||
int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus)
|
||||
{
|
||||
struct work_struct *sm_work;
|
||||
@@ -146,19 +186,14 @@ int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = stop_machine_create();
|
||||
if (ret)
|
||||
return ret;
|
||||
/* No CPUs can come up or down during this. */
|
||||
get_online_cpus();
|
||||
ret = __stop_machine(fn, data, cpus);
|
||||
put_online_cpus();
|
||||
|
||||
stop_machine_destroy();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stop_machine);
|
||||
|
||||
static int __init stop_machine_init(void)
|
||||
{
|
||||
stop_machine_wq = create_rt_workqueue("kstop");
|
||||
stop_machine_work = alloc_percpu(struct work_struct);
|
||||
return 0;
|
||||
}
|
||||
core_initcall(stop_machine_init);
|
||||
|
Reference in New Issue
Block a user