Commit cab4e4c4 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-module-and-param

* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-module-and-param:
  module: use strstarts()
  strstarts: helper function for !strncmp(str, prefix, strlen(prefix))
  arm: allow usage of string functions in linux/string.h
  module: don't use stop_machine on module load
  module: create a request_module_nowait()
  module: include other structures in module version check
  module: remove the SHF_ALLOC flag on the __versions section.
  module: clarify the force-loading taint message.
  module: Export symbols needed for Ksplice
  Ksplice: Add functions for walking kallsyms symbols
  module: remove module_text_address()
  module: __module_address
  module: Make find_symbol return a struct kernel_symbol
  kernel/module.c: fix an unused goto label
  param: fix charp parameters set via sysfs

Fix trivial conflicts in kernel/extable.c manually.
parents 5412b539 49502677
...@@ -18,7 +18,10 @@ ...@@ -18,7 +18,10 @@
unsigned int __machine_arch_type; unsigned int __machine_arch_type;
#include <linux/string.h> #include <linux/compiler.h> /* for inline */
#include <linux/types.h> /* for size_t */
#include <linux/stddef.h> /* for NULL */
#include <asm/string.h>
#ifdef STANDALONE_DEBUG #ifdef STANDALONE_DEBUG
#define putstr printf #define putstr printf
......
...@@ -2720,14 +2720,14 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -2720,14 +2720,14 @@ int nand_scan_tail(struct mtd_info *mtd)
return chip->scan_bbt(mtd); return chip->scan_bbt(mtd);
} }
/* module_text_address() isn't exported, and it's mostly a pointless /* is_module_text_address() isn't exported, and it's mostly a pointless
test if this is a module _anyway_ -- they'd have to try _really_ hard test if this is a module _anyway_ -- they'd have to try _really_ hard
to call us from in-kernel code if the core NAND support is modular. */ to call us from in-kernel code if the core NAND support is modular. */
#ifdef MODULE #ifdef MODULE
#define caller_is_module() (1) #define caller_is_module() (1)
#else #else
#define caller_is_module() \ #define caller_is_module() \
module_text_address((unsigned long)__builtin_return_address(0)) is_module_text_address((unsigned long)__builtin_return_address(0))
#endif #endif
/** /**
......
...@@ -13,10 +13,17 @@ ...@@ -13,10 +13,17 @@
#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \ #define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \
2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + 1) 2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + 1)
struct module;
#ifdef CONFIG_KALLSYMS #ifdef CONFIG_KALLSYMS
/* Lookup the address for a symbol. Returns 0 if not found. */ /* Lookup the address for a symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name); unsigned long kallsyms_lookup_name(const char *name);
/* Call a function on each kallsyms symbol in the core kernel */
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
unsigned long),
void *data);
extern int kallsyms_lookup_size_offset(unsigned long addr, extern int kallsyms_lookup_size_offset(unsigned long addr,
unsigned long *symbolsize, unsigned long *symbolsize,
unsigned long *offset); unsigned long *offset);
...@@ -43,6 +50,14 @@ static inline unsigned long kallsyms_lookup_name(const char *name) ...@@ -43,6 +50,14 @@ static inline unsigned long kallsyms_lookup_name(const char *name)
return 0; return 0;
} }
static inline int kallsyms_on_each_symbol(int (*fn)(void *, const char *,
struct module *,
unsigned long),
void *data)
{
return 0;
}
static inline int kallsyms_lookup_size_offset(unsigned long addr, static inline int kallsyms_lookup_size_offset(unsigned long addr,
unsigned long *symbolsize, unsigned long *symbolsize,
unsigned long *offset) unsigned long *offset)
......
...@@ -29,10 +29,15 @@ ...@@ -29,10 +29,15 @@
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
/* modprobe exit status on success, -ve on error. Return value /* modprobe exit status on success, -ve on error. Return value
* usually useless though. */ * usually useless though. */
extern int request_module(const char * name, ...) __attribute__ ((format (printf, 1, 2))); extern int __request_module(bool wait, const char *name, ...) \
#define try_then_request_module(x, mod...) ((x) ?: (request_module(mod), (x))) __attribute__((format(printf, 2, 3)));
#define request_module(mod...) __request_module(true, mod)
#define request_module_nowait(mod...) __request_module(false, mod)
#define try_then_request_module(x, mod...) \
((x) ?: (__request_module(false, mod), (x)))
#else #else
static inline int request_module(const char * name, ...) { return -ENOSYS; } static inline int request_module(const char *name, ...) { return -ENOSYS; }
static inline int request_module_nowait(const char *name, ...) { return -ENOSYS; }
#define try_then_request_module(x, mod...) (x) #define try_then_request_module(x, mod...) (x)
#endif #endif
......
...@@ -248,6 +248,10 @@ struct module ...@@ -248,6 +248,10 @@ struct module
const unsigned long *crcs; const unsigned long *crcs;
unsigned int num_syms; unsigned int num_syms;
/* Kernel parameters. */
struct kernel_param *kp;
unsigned int num_kp;
/* GPL-only exported symbols. */ /* GPL-only exported symbols. */
unsigned int num_gpl_syms; unsigned int num_gpl_syms;
const struct kernel_symbol *gpl_syms; const struct kernel_symbol *gpl_syms;
...@@ -350,6 +354,8 @@ struct module ...@@ -350,6 +354,8 @@ struct module
#define MODULE_ARCH_INIT {} #define MODULE_ARCH_INIT {}
#endif #endif
extern struct mutex module_mutex;
/* FIXME: It'd be nice to isolate modules during init, too, so they /* FIXME: It'd be nice to isolate modules during init, too, so they
aren't used before they (may) fail. But presently too much code aren't used before they (may) fail. But presently too much code
(IDE & SCSI) require entry into the module during init.*/ (IDE & SCSI) require entry into the module during init.*/
...@@ -358,10 +364,10 @@ static inline int module_is_live(struct module *mod) ...@@ -358,10 +364,10 @@ static inline int module_is_live(struct module *mod)
return mod->state != MODULE_STATE_GOING; return mod->state != MODULE_STATE_GOING;
} }
/* Is this address in a module? (second is with no locks, for oops) */
struct module *module_text_address(unsigned long addr);
struct module *__module_text_address(unsigned long addr); struct module *__module_text_address(unsigned long addr);
int is_module_address(unsigned long addr); struct module *__module_address(unsigned long addr);
bool is_module_address(unsigned long addr);
bool is_module_text_address(unsigned long addr);
static inline int within_module_core(unsigned long addr, struct module *mod) static inline int within_module_core(unsigned long addr, struct module *mod)
{ {
...@@ -375,6 +381,31 @@ static inline int within_module_init(unsigned long addr, struct module *mod) ...@@ -375,6 +381,31 @@ static inline int within_module_init(unsigned long addr, struct module *mod)
addr < (unsigned long)mod->module_init + mod->init_size; addr < (unsigned long)mod->module_init + mod->init_size;
} }
/* Search for module by name: must hold module_mutex. */
struct module *find_module(const char *name);
struct symsearch {
const struct kernel_symbol *start, *stop;
const unsigned long *crcs;
enum {
NOT_GPL_ONLY,
GPL_ONLY,
WILL_BE_GPL_ONLY,
} licence;
bool unused;
};
/* Search for an exported symbol by name. */
const struct kernel_symbol *find_symbol(const char *name,
struct module **owner,
const unsigned long **crc,
bool gplok,
bool warn);
/* Walk the exported symbol table */
bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
unsigned int symnum, void *data), void *data);
/* Returns 0 and fills in value, defined and namebuf, or -ERANGE if /* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
symnum out of range. */ symnum out of range. */
int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
...@@ -383,6 +414,10 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, ...@@ -383,6 +414,10 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
/* Look for this name: can be of form module:name. */ /* Look for this name: can be of form module:name. */
unsigned long module_kallsyms_lookup_name(const char *name); unsigned long module_kallsyms_lookup_name(const char *name);
int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
struct module *, unsigned long),
void *data);
extern void __module_put_and_exit(struct module *mod, long code) extern void __module_put_and_exit(struct module *mod, long code)
__attribute__((noreturn)); __attribute__((noreturn));
#define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code); #define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code);
...@@ -444,6 +479,7 @@ static inline void __module_get(struct module *module) ...@@ -444,6 +479,7 @@ static inline void __module_get(struct module *module)
#define symbol_put_addr(p) do { } while(0) #define symbol_put_addr(p) do { } while(0)
#endif /* CONFIG_MODULE_UNLOAD */ #endif /* CONFIG_MODULE_UNLOAD */
int use_module(struct module *a, struct module *b);
/* This is a #define so the string doesn't get put in every .o file */ /* This is a #define so the string doesn't get put in every .o file */
#define module_name(mod) \ #define module_name(mod) \
...@@ -490,21 +526,24 @@ search_module_extables(unsigned long addr) ...@@ -490,21 +526,24 @@ search_module_extables(unsigned long addr)
return NULL; return NULL;
} }
/* Is this address in a module? */ static inline struct module *__module_address(unsigned long addr)
static inline struct module *module_text_address(unsigned long addr)
{ {
return NULL; return NULL;
} }
/* Is this address in a module? (don't take a lock, we're oopsing) */
static inline struct module *__module_text_address(unsigned long addr) static inline struct module *__module_text_address(unsigned long addr)
{ {
return NULL; return NULL;
} }
static inline int is_module_address(unsigned long addr) static inline bool is_module_address(unsigned long addr)
{ {
return 0; return false;
}
static inline bool is_module_text_address(unsigned long addr)
{
return false;
} }
/* Get/put a kernel symbol (calls should be symmetric) */ /* Get/put a kernel symbol (calls should be symmetric) */
...@@ -559,6 +598,14 @@ static inline unsigned long module_kallsyms_lookup_name(const char *name) ...@@ -559,6 +598,14 @@ static inline unsigned long module_kallsyms_lookup_name(const char *name)
return 0; return 0;
} }
static inline int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
struct module *,
unsigned long),
void *data)
{
return 0;
}
static inline int register_module_notifier(struct notifier_block * nb) static inline int register_module_notifier(struct notifier_block * nb)
{ {
/* no events will happen anyway, so this can always succeed */ /* no events will happen anyway, so this can always succeed */
......
...@@ -138,6 +138,16 @@ extern int parse_args(const char *name, ...@@ -138,6 +138,16 @@ extern int parse_args(const char *name,
unsigned num, unsigned num,
int (*unknown)(char *param, char *val)); int (*unknown)(char *param, char *val));
/* Called by module remove. */
#ifdef CONFIG_SYSFS
extern void destroy_params(const struct kernel_param *params, unsigned num);
#else
static inline void destroy_params(const struct kernel_param *params,
unsigned num)
{
}
#endif /* !CONFIG_SYSFS */
/* All the helper functions */ /* All the helper functions */
/* The macros to do compile-time type checking stolen from Jakub /* The macros to do compile-time type checking stolen from Jakub
Jelinek, who IIRC came up with this idea for the 2.4 module init code. */ Jelinek, who IIRC came up with this idea for the 2.4 module init code. */
......
...@@ -122,5 +122,14 @@ int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) __printf(3, 4); ...@@ -122,5 +122,14 @@ int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) __printf(3, 4);
extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos,
const void *from, size_t available); const void *from, size_t available);
/**
* strstarts - does @str start with @prefix?
* @str: string to examine
* @prefix: prefix to look for.
*/
static inline bool strstarts(const char *str, const char *prefix)
{
return strncmp(str, prefix, strlen(prefix)) == 0;
}
#endif #endif
#endif /* _LINUX_STRING_H_ */ #endif /* _LINUX_STRING_H_ */
...@@ -65,7 +65,7 @@ __notrace_funcgraph int __kernel_text_address(unsigned long addr) ...@@ -65,7 +65,7 @@ __notrace_funcgraph int __kernel_text_address(unsigned long addr)
{ {
if (core_kernel_text(addr)) if (core_kernel_text(addr))
return 1; return 1;
if (__module_text_address(addr)) if (is_module_text_address(addr))
return 1; return 1;
/* /*
* There might be init symbols in saved stacktraces. * There might be init symbols in saved stacktraces.
...@@ -84,7 +84,7 @@ int kernel_text_address(unsigned long addr) ...@@ -84,7 +84,7 @@ int kernel_text_address(unsigned long addr)
{ {
if (core_kernel_text(addr)) if (core_kernel_text(addr))
return 1; return 1;
return module_text_address(addr) != NULL; return is_module_text_address(addr);
} }
/* /*
...@@ -100,5 +100,5 @@ int func_ptr_is_kernel_text(void *ptr) ...@@ -100,5 +100,5 @@ int func_ptr_is_kernel_text(void *ptr)
addr = (unsigned long) dereference_function_descriptor(ptr); addr = (unsigned long) dereference_function_descriptor(ptr);
if (core_kernel_text(addr)) if (core_kernel_text(addr))
return 1; return 1;
return module_text_address(addr) != NULL; return is_module_text_address(addr);
} }
...@@ -161,6 +161,25 @@ unsigned long kallsyms_lookup_name(const char *name) ...@@ -161,6 +161,25 @@ unsigned long kallsyms_lookup_name(const char *name)
return module_kallsyms_lookup_name(name); return module_kallsyms_lookup_name(name);
} }
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
unsigned long),
void *data)
{
char namebuf[KSYM_NAME_LEN];
unsigned long i;
unsigned int off;
int ret;
for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
off = kallsyms_expand_symbol(off, namebuf);
ret = fn(data, namebuf, NULL, kallsyms_addresses[i]);
if (ret != 0)
return ret;
}
return module_kallsyms_on_each_symbol(fn, data);
}
EXPORT_SYMBOL_GPL(kallsyms_on_each_symbol);
static unsigned long get_symbol_pos(unsigned long addr, static unsigned long get_symbol_pos(unsigned long addr,
unsigned long *symbolsize, unsigned long *symbolsize,
unsigned long *offset) unsigned long *offset)
......
...@@ -50,7 +50,8 @@ static struct workqueue_struct *khelper_wq; ...@@ -50,7 +50,8 @@ static struct workqueue_struct *khelper_wq;
char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
/** /**
* request_module - try to load a kernel module * __request_module - try to load a kernel module
* @wait: wait (or not) for the operation to complete
* @fmt: printf style format string for the name of the module * @fmt: printf style format string for the name of the module
* @...: arguments as specified in the format string * @...: arguments as specified in the format string
* *
...@@ -63,7 +64,7 @@ char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; ...@@ -63,7 +64,7 @@ char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
* If module auto-loading support is disabled then this function * If module auto-loading support is disabled then this function
* becomes a no-operation. * becomes a no-operation.
*/ */
int request_module(const char *fmt, ...) int __request_module(bool wait, const char *fmt, ...)
{ {
va_list args; va_list args;
char module_name[MODULE_NAME_LEN]; char module_name[MODULE_NAME_LEN];
...@@ -108,11 +109,12 @@ int request_module(const char *fmt, ...) ...@@ -108,11 +109,12 @@ int request_module(const char *fmt, ...)
return -ENOMEM; return -ENOMEM;
} }
ret = call_usermodehelper(modprobe_path, argv, envp, 1); ret = call_usermodehelper(modprobe_path, argv, envp,
wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
atomic_dec(&kmod_concurrent); atomic_dec(&kmod_concurrent);
return ret; return ret;
} }
EXPORT_SYMBOL(request_module); EXPORT_SYMBOL(__request_module);
#endif /* CONFIG_MODULES */ #endif /* CONFIG_MODULES */
struct subprocess_info { struct subprocess_info {
......
...@@ -68,7 +68,8 @@ ...@@ -68,7 +68,8 @@
/* List of modules, protected by module_mutex or preempt_disable /* List of modules, protected by module_mutex or preempt_disable
* (delete uses stop_machine/add uses RCU list operations). */ * (delete uses stop_machine/add uses RCU list operations). */
static DEFINE_MUTEX(module_mutex); DEFINE_MUTEX(module_mutex);
EXPORT_SYMBOL_GPL(module_mutex);
static LIST_HEAD(modules); static LIST_HEAD(modules);
/* Waiting for a module to finish initializing? */ /* Waiting for a module to finish initializing? */
...@@ -76,7 +77,7 @@ static DECLARE_WAIT_QUEUE_HEAD(module_wq); ...@@ -76,7 +77,7 @@ static DECLARE_WAIT_QUEUE_HEAD(module_wq);
static BLOCKING_NOTIFIER_HEAD(module_notify_list); static BLOCKING_NOTIFIER_HEAD(module_notify_list);
/* Bounds of module allocation, for speeding __module_text_address */ /* Bounds of module allocation, for speeding __module_address */
static unsigned long module_addr_min = -1UL, module_addr_max = 0; static unsigned long module_addr_min = -1UL, module_addr_max = 0;
int register_module_notifier(struct notifier_block * nb) int register_module_notifier(struct notifier_block * nb)
...@@ -186,17 +187,6 @@ extern const unsigned long __start___kcrctab_unused_gpl[]; ...@@ -186,17 +187,6 @@ extern const unsigned long __start___kcrctab_unused_gpl[];
#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL) #define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
#endif #endif
struct symsearch {
const struct kernel_symbol *start, *stop;
const unsigned long *crcs;
enum {
NOT_GPL_ONLY,
GPL_ONLY,
WILL_BE_GPL_ONLY,
} licence;
bool unused;
};
static bool each_symbol_in_section(const struct symsearch *arr, static bool each_symbol_in_section(const struct symsearch *arr,
unsigned int arrsize, unsigned int arrsize,
struct module *owner, struct module *owner,
...@@ -217,10 +207,8 @@ static bool each_symbol_in_section(const struct symsearch *arr, ...@@ -217,10 +207,8 @@ static bool each_symbol_in_section(const struct symsearch *arr,
} }
/* Returns true as soon as fn returns true, otherwise false. */ /* Returns true as soon as fn returns true, otherwise false. */
static bool each_symbol(bool (*fn)(const struct symsearch *arr, bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
struct module *owner, unsigned int symnum, void *data), void *data)
unsigned int symnum, void *data),
void *data)
{ {
struct module *mod; struct module *mod;
const struct symsearch arr[] = { const struct symsearch arr[] = {
...@@ -273,6 +261,7 @@ static bool each_symbol(bool (*fn)(const struct symsearch *arr, ...@@ -273,6 +261,7 @@ static bool each_symbol(bool (*fn)(const struct symsearch *arr,
} }
return false; return false;
} }
EXPORT_SYMBOL_GPL(each_symbol);
struct find_symbol_arg { struct find_symbol_arg {
/* Input */ /* Input */
...@@ -283,7 +272,7 @@ struct find_symbol_arg { ...@@ -283,7 +272,7 @@ struct find_symbol_arg {
/* Output */ /* Output */
struct module *owner; struct module *owner;
const unsigned long *crc; const unsigned long *crc;
unsigned long value; const struct kernel_symbol *sym;
}; };
static bool find_symbol_in_section(const struct symsearch *syms, static bool find_symbol_in_section(const struct symsearch *syms,
...@@ -324,13 +313,13 @@ static bool find_symbol_in_section(const struct symsearch *syms, ...@@ -324,13 +313,13 @@ static bool find_symbol_in_section(const struct symsearch *syms,
fsa->owner = owner; fsa->owner = owner;
fsa->crc = symversion(syms->crcs, symnum); fsa->crc = symversion(syms->crcs, symnum);
fsa->value = syms->start[symnum].value; fsa->sym = &syms->start[symnum];
return true; return true;
} }
/* Find a symbol, return value, (optional) crc and (optional) module /* Find a symbol and return it, along with, (optional) crc and
* which owns it */ * (optional) module which owns it */
static unsigned long find_symbol(const char *name, const struct kernel_symbol *find_symbol(const char *name,
struct module **owner, struct module **owner,
const unsigned long **crc, const unsigned long **crc,
bool gplok, bool gplok,
...@@ -347,15 +336,16 @@ static unsigned long find_symbol(const char *name, ...@@ -347,15 +336,16 @@ static unsigned long find_symbol(const char *name,
*owner = fsa.owner; *owner = fsa.owner;
if (crc) if (crc)
*crc = fsa.crc; *crc = fsa.crc;
return fsa.value; return fsa.sym;
} }
DEBUGP("Failed to find symbol %s\n", name); DEBUGP("Failed to find symbol %s\n", name);
return -ENOENT; return NULL;
} }
EXPORT_SYMBOL_GPL(find_symbol);
/* Search for module by name: must hold module_mutex. */ /* Search for module by name: must hold module_mutex. */
static struct module *find_module(const char *name) struct module *find_module(const char *name)
{ {
struct module *mod; struct module *mod;
...@@ -365,6 +355,7 @@ static struct module *find_module(const char *name) ...@@ -365,6 +355,7 @@ static struct module *find_module(const char *name)
} }
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(find_module);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
...@@ -641,7 +632,7 @@ static int already_uses(struct module *a, struct module *b) ...@@ -641,7 +632,7 @@ static int already_uses(struct module *a, struct module *b)
} }
/* Module a uses b */ /* Module a uses b */
static int use_module(struct module *a, struct module *b) int use_module(struct module *a, struct module *b)
{ {
struct module_use *use; struct module_use *use;
int no_warn, err; int no_warn, err;
...@@ -674,6 +665,7 @@ static int use_module(struct module *a, struct module *b) ...@@ -674,6 +665,7 @@ static int use_module(struct module *a, struct module *b)
no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name); no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name);
return 1; return 1;
} }
EXPORT_SYMBOL_GPL(use_module);
/* Clear the unload stuff of the module. */ /* Clear the unload stuff of the module. */
static void module_unload_free(struct module *mod) static void module_unload_free(struct module *mod)
...@@ -894,7 +886,7 @@ void __symbol_put(const char *symbol) ...@@ -894,7 +886,7 @@ void __symbol_put(const char *symbol)
struct module *owner; struct module *owner;
preempt_disable(); preempt_disable();
if (IS_ERR_VALUE(find_symbol(symbol, &owner, NULL, true, false))) if (!find_symbol(symbol, &owner, NULL, true, false))
BUG(); BUG();
module_put(owner); module_put(owner);
preempt_enable(); preempt_enable();
...@@ -908,8 +900,10 @@ void symbol_put_addr(void *addr) ...@@ -908,8 +900,10 @@ void symbol_put_addr(void *addr)
if (core_kernel_text((unsigned long)addr)) if (core_kernel_text((unsigned long)addr))
return; return;
if (!(modaddr = module_text_address((unsigned long)addr))) /* module_text_address is safe here: we're supposed to have reference
BUG(); * to module from symbol_get, so it can't go away. */
modaddr = __module_text_address((unsigned long)addr);
BUG_ON(!modaddr);
module_put(modaddr); module_put(modaddr);
} }
EXPORT_SYMBOL_GPL(symbol_put_addr); EXPORT_SYMBOL_GPL(symbol_put_addr);
...@@ -949,10 +943,11 @@ static inline void module_unload_free(struct module *mod) ...@@ -949,10 +943,11 @@ static inline void module_unload_free(struct module *mod)
{ {
} }
static inline int use_module(struct module *a, struct module *b) int use_module(struct module *a, struct module *b)
{ {
return strong_try_module_get(b) == 0; return strong_try_module_get(b) == 0;
} }
EXPORT_SYMBOL_GPL(use_module);
static inline void module_unload_init(struct module *mod) static inline void module_unload_init(struct module *mod)
{ {
...@@ -995,12 +990,12 @@ static struct module_attribute *modinfo_attrs[] = { ...@@ -995,12 +990,12 @@ static struct module_attribute *modinfo_attrs[] = {
static const char vermagic[] = VERMAGIC_STRING; static const char vermagic[] = VERMAGIC_STRING;
static int try_to_force_load(struct module *mod, const char *symname) static int try_to_force_load(struct module *mod, const char *reason)
{ {
#ifdef CONFIG_MODULE_FORCE_LOAD #ifdef CONFIG_MODULE_FORCE_LOAD
if (!test_taint(TAINT_FORCED_MODULE)) if (!test_taint(TAINT_FORCED_MODULE))
printk("%s: no version for \"%s\" found: kernel tainted.\n", printk(KERN_WARNING "%s: %s: kernel tainted.\n",
mod->name, symname); mod->name, reason);
add_taint_module(mod, TAINT_FORCED_MODULE); add_taint_module(mod, TAINT_FORCED_MODULE);
return 0; return 0;
#else #else
...@@ -1057,9 +1052,9 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, ...@@ -1057,9 +1052,9 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
{ {
const unsigned long *crc; const unsigned long *crc;
if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc, true, false))) if (!find_symbol("module_layout", NULL, &crc, true, false))
BUG(); BUG();
return check_version(sechdrs, versindex, "struct_module", mod, crc); return check_version(sechdrs, versindex, "module_layout", mod, crc);
} }
/* First part is kernel version, which we ignore if module has crcs. */ /* First part is kernel version, which we ignore if module has crcs. */
...@@ -1098,25 +1093,25 @@ static inline int same_magic(const char *amagic, const char *bmagic, ...@@ -1098,25 +1093,25 @@ static inline int same_magic(const char *amagic, const char *bmagic,
/* Resolve a symbol for this module. I.e. if we find one, record usage. /* Resolve a symbol for this module. I.e. if we find one, record usage.
Must be holding module_mutex. */ Must be holding module_mutex. */
static unsigned long resolve_symbol(Elf_Shdr *sechdrs, static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs,
unsigned int versindex, unsigned int versindex,
const char *name, const char *name,
struct module *mod) struct module *mod)
{ {
struct module *owner; struct module *owner;
unsigned long ret; const struct kernel_symbol *sym;
const unsigned long *crc; const unsigned long *crc;
ret = find_symbol(name, &owner, &crc, sym = find_symbol(name, &owner, &crc,
!(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true); !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true);
if (!IS_ERR_VALUE(ret)) {
/* use_module can fail due to OOM, /* use_module can fail due to OOM,
or module initialization or unloading */ or module initialization or unloading */
if (sym) {
if (!check_version(sechdrs, versindex, name, mod, crc) || if (!check_version(sechdrs, versindex, name, mod, crc) ||
!use_module(mod, owner)) !use_module(mod, owner))
ret = -EINVAL; sym = NULL;
} }
return ret; return sym;
} }
/* /*
...@@ -1491,6 +1486,9 @@ static void free_module(struct module *mod) ...@@ -1491,6 +1486,9 @@ static void free_module(struct module *mod)
/* Module unload stuff */ /* Module unload stuff */
module_unload_free(mod); module_unload_free(mod);
/* Free any allocated parameters. */
destroy_params(mod->kp, mod->num_kp);
/* release any pointers to mcount in this module */ /* release any pointers to mcount in this module */
ftrace_release(mod->module_core, mod->core_size); ftrace_release(mod->module_core, mod->core_size);
...@@ -1513,17 +1511,15 @@ static void free_module(struct module *mod) ...@@ -1513,17 +1511,15 @@ static void free_module(struct module *mod)
void *__symbol_get(const char *symbol) void *__symbol_get(const char *symbol)
{ {
struct module *owner; struct module *owner;
unsigned long value; const struct kernel_symbol *sym;
preempt_disable(); preempt_disable();
value = find_symbol(symbol, &owner, NULL, true, true); sym = find_symbol(symbol, &owner, NULL, true, true);
if (IS_ERR_VALUE(value)) if (sym && strong_try_module_get(owner))
value = 0; sym = NULL;
else if (strong_try_module_get(owner))
value = 0;
preempt_enable(); preempt_enable();
return (void *)value; return sym ? (void *)sym->value : NULL;
} }
EXPORT_SYMBOL_GPL(__symbol_get); EXPORT_SYMBOL_GPL(__symbol_get);
...@@ -1551,8 +1547,7 @@ static int verify_export_symbols(struct module *mod) ...@@ -1551,8 +1547,7 @@ static int verify_export_symbols(struct module *mod)
for (i = 0; i < ARRAY_SIZE(arr); i++) { for (i = 0; i < ARRAY_SIZE(arr); i++) {
for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
if (!IS_ERR_VALUE(find_symbol(s->name, &owner, if (find_symbol(s->name, &owner, NULL, true, false)) {
NULL, true, false))) {
printk(KERN_ERR printk(KERN_ERR
"%s: exports duplicate symbol %s" "%s: exports duplicate symbol %s"
" (owned by %s)\n", " (owned by %s)\n",
...@@ -1576,6 +1571,7 @@ static int simplify_symbols(Elf_Shdr *sechdrs, ...@@ -1576,6 +1571,7 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
unsigned long secbase; unsigned long secbase;
unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
int ret = 0; int ret = 0;
const struct kernel_symbol *ksym;
for (i = 1; i < n; i++) { for (i = 1; i < n; i++) {
switch (sym[i].st_shndx) { switch (sym[i].st_shndx) {
...@@ -1595,13 +1591,14 @@ static int simplify_symbols(Elf_Shdr *sechdrs, ...@@ -1595,13 +1591,14 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
break; break;
case SHN_UNDEF: case SHN_UNDEF:
sym[i].st_value ksym = resolve_symbol(sechdrs, versindex,
= resolve_symbol(sechdrs, versindex,
strtab + sym[i].st_name, mod); strtab + sym[i].st_name, mod);
/* Ok if resolved. */ /* Ok if resolved. */
if (!IS_ERR_VALUE(sym[i].st_value)) if (ksym) {
sym[i].st_value = ksym->value;
break; break;
}
/* Ok if weak. */ /* Ok if weak. */
if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK) if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
break; break;
...@@ -1676,8 +1673,7 @@ static void layout_sections(struct module *mod, ...@@ -1676,8 +1673,7 @@ static void layout_sections(struct module *mod,
if ((s->sh_flags & masks[m][0]) != masks[m][0] if ((s->sh_flags & masks[m][0]) != masks[m][0]
|| (s->sh_flags & masks[m][1]) || (s->sh_flags & masks[m][1])
|| s->sh_entsize != ~0UL || s->sh_entsize != ~0UL
|| strncmp(secstrings + s->sh_name, || strstarts(secstrings + s->sh_name, ".init"))
".init", 5) == 0)
continue; continue;
s->sh_entsize = get_offset(mod, &mod->core_size, s, i); s->sh_entsize = get_offset(mod, &mod->core_size, s, i);
DEBUGP("\t%s\n", secstrings + s->sh_name); DEBUGP("\t%s\n", secstrings + s->sh_name);
...@@ -1694,8 +1690,7 @@ static void layout_sections(struct module *mod, ...@@ -1694,8 +1690,7 @@ static void layout_sections(struct module *mod,
if ((s->sh_flags & masks[m][0]) != masks[m][0] if ((s->sh_flags & masks[m][0]) != masks[m][0]
|| (s->sh_flags & masks[m][1]) || (s->sh_flags & masks[m][1])
|| s->sh_entsize != ~0UL || s->sh_entsize != ~0UL
|| strncmp(secstrings + s->sh_name, || !strstarts(secstrings + s->sh_name, ".init"))
".init", 5) != 0)
continue; continue;
s->sh_entsize = (get_offset(mod, &mod->init_size, s, i) s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)
| INIT_OFFSET_MASK); | INIT_OFFSET_MASK);
...@@ -1828,8 +1823,7 @@ static char elf_type(const Elf_Sym *sym, ...@@ -1828,8 +1823,7 @@ static char elf_type(const Elf_Sym *sym,
else else
return 'b'; return 'b';
} }
if (strncmp(secstrings + sechdrs[sym->st_shndx].sh_name, if (strstarts(secstrings + sechdrs[sym->st_shndx].sh_name, ".debug"))
".debug", strlen(".debug")) == 0)
return 'n'; return 'n';
return '?'; return '?';
} }
...@@ -1898,8 +1892,7 @@ static noinline struct module *load_module(void __user *umod, ...@@ -1898,8 +1892,7 @@ static noinline struct module *load_module(void __user *umod,
unsigned int symindex = 0; unsigned int symindex = 0;
unsigned int strindex = 0; unsigned int strindex = 0;
unsigned int modindex, versindex, infoindex, pcpuindex; unsigned int modindex, versindex, infoindex, pcpuindex;
unsigned int num_kp, num_mcount; unsigned int num_mcount;
struct kernel_param *kp;
struct module *mod; struct module *mod;
long err = 0; long err = 0;
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
...@@ -1916,12 +1909,6 @@ static noinline struct module *load_module(void __user *umod, ...@@ -1916,12 +1909,6 @@ static noinline struct module *load_module(void __user *umod,
if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL) if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
return ERR_PTR(-ENOMEM); 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) { if (copy_from_user(hdr, umod, len) != 0) {
err = -EFAULT; err = -EFAULT;
goto free_hdr; goto free_hdr;
...@@ -1962,9 +1949,12 @@ static noinline struct module *load_module(void __user *umod, ...@@ -1962,9 +1949,12 @@ static noinline struct module *load_module(void __user *umod,
} }
#ifndef CONFIG_MODULE_UNLOAD #ifndef CONFIG_MODULE_UNLOAD
/* Don't load .exit sections */ /* Don't load .exit sections */
if (strncmp(secstrings+sechdrs[i].sh_name, ".exit", 5) == 0) if (strstarts(secstrings+sechdrs[i].sh_name, ".exit"))
sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC; sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
#endif #endif
/* Don't keep __versions around; it's just for loading. */
if (strcmp(secstrings + sechdrs[i].sh_name, "__versions") == 0)
sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
} }
modindex = find_sec(hdr, sechdrs, secstrings, modindex = find_sec(hdr, sechdrs, secstrings,
...@@ -2006,7 +1996,7 @@ static noinline struct module *load_module(void __user *umod, ...@@ -2006,7 +1996,7 @@ static noinline struct module *load_module(void __user *umod,
modmagic = get_modinfo(sechdrs, infoindex, "vermagic"); modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
/* This is allowed: modprobe --force will invalidate it. */ /* This is allowed: modprobe --force will invalidate it. */
if (!modmagic) { if (!modmagic) {
err = try_to_force_load(mod, "magic"); err = try_to_force_load(mod, "bad vermagic");
if (err) if (err)
goto free_hdr; goto free_hdr;
} else if (!same_magic(modmagic, vermagic, versindex)) { } else if (!same_magic(modmagic, vermagic, versindex)) {
...@@ -2144,8 +2134,8 @@ static noinline struct module *load_module(void __user *umod, ...@@ -2144,8 +2134,8 @@ static noinline struct module *load_module(void __user *umod,
/* Now we've got everything in the final locations, we can /* Now we've got everything in the final locations, we can
* find optional sections. */ * find optional sections. */
kp = section_objs(hdr, sechdrs, secstrings, "__param", sizeof(*kp), mod->kp = section_objs(hdr, sechdrs, secstrings, "__param",
&num_kp); sizeof(*mod->kp), &mod->num_kp);
mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab", mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab",
sizeof(*mod->syms), &mod->num_syms); sizeof(*mod->syms), &mod->num_syms);
mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab"); mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab");
...@@ -2195,8 +2185,8 @@ static noinline struct module *load_module(void __user *umod, ...@@ -2195,8 +2185,8 @@ static noinline struct module *load_module(void __user *umod,
|| (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs) || (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs)
#endif #endif
) { ) {
printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name); err = try_to_force_load(mod,
err = try_to_force_load(mod, "nocrc"); "no versions for exported symbols");
if (err) if (err)
goto cleanup; goto cleanup;
} }
...@@ -2291,11 +2281,11 @@ static noinline struct module *load_module(void __user *umod, ...@@ -2291,11 +2281,11 @@ static noinline struct module *load_module(void __user *umod,
*/ */
list_add_rcu(&mod->list, &modules); list_add_rcu(&mod->list, &modules);
err = parse_args(mod->name, mod->args, kp, num_kp, NULL); err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL);
if (err < 0) if (err < 0)
goto unlink; goto unlink;
err = mod_sysfs_setup(mod, kp, num_kp); err = mod_sysfs_setup(mod, mod->kp, mod->num_kp);
if (err < 0) if (err < 0)
goto unlink; goto unlink;
add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
...@@ -2304,12 +2294,13 @@ static noinline struct module *load_module(void __user *umod, ...@@ -2304,12 +2294,13 @@ static noinline struct module *load_module(void __user *umod,
/* Get rid of temporary copy */ /* Get rid of temporary copy */
vfree(hdr); vfree(hdr);
stop_machine_destroy();
/* Done! */ /* Done! */
return mod; return mod;
unlink: unlink:
stop_machine(__unlink_module, mod, NULL); /* Unlink carefully: kallsyms could be walking list. */
list_del_rcu(&mod->list);
synchronize_sched();
module_arch_cleanup(mod); module_arch_cleanup(mod);
cleanup: cleanup:
kobject_del(&mod->mkobj.kobj); kobject_del(&mod->mkobj.kobj);
...@@ -2317,8 +2308,8 @@ static noinline struct module *load_module(void __user *umod, ...@@ -2317,8 +2308,8 @@ static noinline struct module *load_module(void __user *umod,
ftrace_release(mod->module_core, mod->core_size); ftrace_release(mod->module_core, mod->core_size);
free_unload: free_unload:
module_unload_free(mod); module_unload_free(mod);
free_init:
#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
free_init:
percpu_modfree(mod->refptr); percpu_modfree(mod->refptr);
#endif #endif
module_free(mod, mod->module_init); module_free(mod, mod->module_init);
...@@ -2332,7 +2323,6 @@ static noinline struct module *load_module(void __user *umod, ...@@ -2332,7 +2323,6 @@ static noinline struct module *load_module(void __user *umod,
kfree(args); kfree(args);
free_hdr: free_hdr:
vfree(hdr); vfree(hdr);
stop_machine_destroy();
return ERR_PTR(err); return ERR_PTR(err);
truncated: truncated:
...@@ -2609,6 +2599,25 @@ unsigned long module_kallsyms_lookup_name(const char *name) ...@@ -2609,6 +2599,25 @@ unsigned long module_kallsyms_lookup_name(const char *name)
preempt_enable(); preempt_enable();
return ret; return ret;
} }
int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
struct module *, unsigned long),
void *data)
{
struct module *mod;
unsigned int i;
int ret;
list_for_each_entry(mod, &modules, list) {
for (i = 0; i < mod->num_symtab; i++) {
ret = fn(data, mod->strtab + mod->symtab[i].st_name,
mod, mod->symtab[i].st_value);
if (ret != 0)
return ret;
}
}
return 0;
}
#endif /* CONFIG_KALLSYMS */ #endif /* CONFIG_KALLSYMS */
static char *module_flags(struct module *mod, char *buf) static char *module_flags(struct module *mod, char *buf)
...@@ -2744,29 +2753,31 @@ const struct exception_table_entry *search_module_extables(unsigned long addr) ...@@ -2744,29 +2753,31 @@ const struct exception_table_entry *search_module_extables(unsigned long addr)
} }
/* /*
* Is this a valid module address? * is_module_address - is this address inside a module?
* @addr: the address to check.
*
* See is_module_text_address() if you simply want to see if the address
* is code (not data).
*/ */
int is_module_address(unsigned long addr) bool is_module_address(unsigned long addr)
{ {
struct module *mod; bool ret;
preempt_disable(); preempt_disable();
ret = __module_address(addr) != NULL;
list_for_each_entry_rcu(mod, &modules, list) {
if (within_module_core(addr, mod)) {
preempt_enable();
return 1;
}
}
preempt_enable(); preempt_enable();
return 0; return ret;
} }
/*
/* Is this a valid kernel address? */ * __module_address - get the module which contains an address.
__notrace_funcgraph struct module *__module_text_address(unsigned long addr) * @addr: the address.
*
* Must be called with preempt disabled or module mutex held so that
* module doesn't get freed during this.
*/
__notrace_funcgraph struct module *__module_address(unsigned long addr)
{ {
struct module *mod; struct module *mod;
...@@ -2774,22 +2785,51 @@ __notrace_funcgraph struct module *__module_text_address(unsigned long addr) ...@@ -2774,22 +2785,51 @@ __notrace_funcgraph struct module *__module_text_address(unsigned long addr)
return NULL; return NULL;
list_for_each_entry_rcu(mod, &modules, list) list_for_each_entry_rcu(mod, &modules, list)
if (within(addr, mod->module_init, mod->init_text_size) if (within_module_core(addr, mod)
|| within(addr, mod->module_core, mod->core_text_size)) || within_module_init(addr, mod))
return mod; return mod;
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(__module_address);
struct module *module_text_address(unsigned long addr) /*
* is_module_text_address - is this address inside module code?
* @addr: the address to check.
*
* See is_module_address() if you simply want to see if the address is
* anywhere in a module. See kernel_text_address() for testing if an
* address corresponds to kernel or module code.
*/
bool is_module_text_address(unsigned long addr)
{ {
struct module *mod; bool ret;
preempt_disable(); preempt_disable();
mod = __module_text_address(addr); ret = __module_text_address(addr) != NULL;
preempt_enable(); preempt_enable();
return ret;
}
/*
* __module_text_address - get the module whose code contains an address.
* @addr: the address.
*
* Must be called with preempt disabled or module mutex held so that
* module doesn't get freed during this.
*/
struct module *__module_text_address(unsigned long addr)
{
struct module *mod = __module_address(addr);
if (mod) {
/* Make sure it's within the text section. */
if (!within(addr, mod->module_init, mod->init_text_size)
&& !within(addr, mod->module_core, mod->core_text_size))
mod = NULL;
}
return mod; return mod;
} }
EXPORT_SYMBOL_GPL(__module_text_address);
/* Don't grab lock, we're oopsing. */ /* Don't grab lock, we're oopsing. */
void print_modules(void) void print_modules(void)
...@@ -2809,9 +2849,17 @@ void print_modules(void) ...@@ -2809,9 +2849,17 @@ void print_modules(void)
} }
#ifdef CONFIG_MODVERSIONS #ifdef CONFIG_MODVERSIONS
/* Generate the signature for struct module here, too, for modversions. */ /* Generate the signature for all relevant module structures here.
void struct_module(struct module *mod) { return; } * If these change, we don't want to try to parse the module. */
EXPORT_SYMBOL(struct_module); void module_layout(struct module *mod,
struct modversion_info *ver,
struct kernel_param *kp,
struct kernel_symbol *ks,
struct marker *marker,
struct tracepoint *tp)
{
}
EXPORT_SYMBOL(module_layout);
#endif #endif
#ifdef CONFIG_MARKERS #ifdef CONFIG_MARKERS
......
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/slab.h> #include <linux/slab.h>
/* We abuse the high bits of "perm" to record whether we kmalloc'ed. */
#define KPARAM_KMALLOCED 0x80000000
#if 0 #if 0
#define DEBUGP printk #define DEBUGP printk
#else #else
...@@ -217,7 +220,19 @@ int param_set_charp(const char *val, struct kernel_param *kp) ...@@ -217,7 +220,19 @@ int param_set_charp(const char *val, struct kernel_param *kp)
return -ENOSPC; return -ENOSPC;
} }
*(char **)kp->arg = (char *)val; if (kp->perm & KPARAM_KMALLOCED)
kfree(*(char **)kp->arg);
/* This is a hack. We can't need to strdup in early boot, and we
* don't need to; this mangled commandline is preserved. */
if (slab_is_available()) {
kp->perm |= KPARAM_KMALLOCED;
*(char **)kp->arg = kstrdup(val, GFP_KERNEL);
if (!kp->arg)
return -ENOMEM;
} else
*(const char **)kp->arg = val;
return 0; return 0;
} }
...@@ -571,6 +586,15 @@ void module_param_sysfs_remove(struct module *mod) ...@@ -571,6 +586,15 @@ void module_param_sysfs_remove(struct module *mod)
} }
#endif #endif
void destroy_params(const struct kernel_param *params, unsigned num)
{
unsigned int i;
for (i = 0; i < num; i++)
if (params[i].perm & KPARAM_KMALLOCED)
kfree(*(char **)params[i].arg);
}
static void __init kernel_add_sysfs_param(const char *name, static void __init kernel_add_sysfs_param(const char *name,
struct kernel_param *kparam, struct kernel_param *kparam,
unsigned int name_skip) unsigned int name_skip)
......
...@@ -1607,12 +1607,12 @@ static void read_symbols(char *modname) ...@@ -1607,12 +1607,12 @@ static void read_symbols(char *modname)
parse_elf_finish(&info); parse_elf_finish(&info);
/* Our trick to get versioning for struct_module - it's /* Our trick to get versioning for module struct etc. - it's
* never passed as an argument to an exported function, so * never passed as an argument to an exported function, so
* the automatic versioning doesn't pick it up, but it's really * the automatic versioning doesn't pick it up, but it's really
* important anyhow */ * important anyhow */
if (modversions) if (modversions)
mod->unres = alloc_symbol("struct_module", 0, mod->unres); mod->unres = alloc_symbol("module_layout", 0, mod->unres);
} }
#define SZ 500 #define SZ 500
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment