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: params.c: Use new strtobool function to process boolean inputs debugfs: move to new strtobool Add a strtobool function matching semantics of existing in kernel equivalents modpost: Update 64k section support for binutils 2.18.50 module: Use binary search in lookup_symbol() module: Use the binary search for symbols resolution lib: Add generic binary search function to the kernel. module: Sort exported symbols module: each_symbol_section instead of each_symbol module: split unset_section_ro_nx function. module: undo module RONX protection correctly. module: zero mod->init_ro_size after init is freed. minor ANSI prototype sparse fix module: reorder kparam_array to remove alignment padding on 64 bit builds module: remove 64 bit alignment padding from struct module with CONFIG_TRACE* module: do not hide __modver_version_show declaration behind ifdef module: deal with alignment issues in built-in module versions
This commit is contained in:
commit
98a38a5d60
16 changed files with 237 additions and 127 deletions
|
@ -11,5 +11,6 @@ void kernel_map_pages(struct page *page, int numpages, int enable);
|
|||
int set_memory_ro(unsigned long addr, int numpages);
|
||||
int set_memory_rw(unsigned long addr, int numpages);
|
||||
int set_memory_nx(unsigned long addr, int numpages);
|
||||
int set_memory_x(unsigned long addr, int numpages);
|
||||
|
||||
#endif /* _S390_CACHEFLUSH_H */
|
||||
|
|
|
@ -54,3 +54,8 @@ int set_memory_nx(unsigned long addr, int numpages)
|
|||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(set_memory_nx);
|
||||
|
||||
int set_memory_x(unsigned long addr, int numpages)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -429,24 +429,15 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf,
|
|||
{
|
||||
char buf[32];
|
||||
int buf_size;
|
||||
bool bv;
|
||||
u32 *val = file->private_data;
|
||||
|
||||
buf_size = min(count, (sizeof(buf)-1));
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
|
||||
switch (buf[0]) {
|
||||
case 'y':
|
||||
case 'Y':
|
||||
case '1':
|
||||
*val = 1;
|
||||
break;
|
||||
case 'n':
|
||||
case 'N':
|
||||
case '0':
|
||||
*val = 0;
|
||||
break;
|
||||
}
|
||||
if (strtobool(buf, &bv) == 0)
|
||||
*val = bv;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -274,70 +274,70 @@
|
|||
/* Kernel symbol table: Normal symbols */ \
|
||||
__ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start___ksymtab) = .; \
|
||||
*(__ksymtab) \
|
||||
*(SORT(___ksymtab+*)) \
|
||||
VMLINUX_SYMBOL(__stop___ksymtab) = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-only symbols */ \
|
||||
__ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \
|
||||
*(__ksymtab_gpl) \
|
||||
*(SORT(___ksymtab_gpl+*)) \
|
||||
VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: Normal unused symbols */ \
|
||||
__ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \
|
||||
*(__ksymtab_unused) \
|
||||
*(SORT(___ksymtab_unused+*)) \
|
||||
VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-only unused symbols */ \
|
||||
__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \
|
||||
*(__ksymtab_unused_gpl) \
|
||||
*(SORT(___ksymtab_unused_gpl+*)) \
|
||||
VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-future-only symbols */ \
|
||||
__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \
|
||||
*(__ksymtab_gpl_future) \
|
||||
*(SORT(___ksymtab_gpl_future+*)) \
|
||||
VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: Normal symbols */ \
|
||||
__kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start___kcrctab) = .; \
|
||||
*(__kcrctab) \
|
||||
*(SORT(___kcrctab+*)) \
|
||||
VMLINUX_SYMBOL(__stop___kcrctab) = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-only symbols */ \
|
||||
__kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \
|
||||
*(__kcrctab_gpl) \
|
||||
*(SORT(___kcrctab_gpl+*)) \
|
||||
VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: Normal unused symbols */ \
|
||||
__kcrctab_unused : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start___kcrctab_unused) = .; \
|
||||
*(__kcrctab_unused) \
|
||||
*(SORT(___kcrctab_unused+*)) \
|
||||
VMLINUX_SYMBOL(__stop___kcrctab_unused) = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-only unused symbols */ \
|
||||
__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \
|
||||
*(__kcrctab_unused_gpl) \
|
||||
*(SORT(___kcrctab_unused_gpl+*)) \
|
||||
VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-future-only symbols */ \
|
||||
__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \
|
||||
*(__kcrctab_gpl_future) \
|
||||
*(SORT(___kcrctab_gpl_future+*)) \
|
||||
VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \
|
||||
} \
|
||||
\
|
||||
|
|
9
include/linux/bsearch.h
Normal file
9
include/linux/bsearch.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef _LINUX_BSEARCH_H
|
||||
#define _LINUX_BSEARCH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
void *bsearch(const void *key, const void *base, size_t num, size_t size,
|
||||
int (*cmp)(const void *key, const void *elt));
|
||||
|
||||
#endif /* _LINUX_BSEARCH_H */
|
|
@ -64,6 +64,9 @@ struct module_version_attribute {
|
|||
const char *version;
|
||||
} __attribute__ ((__aligned__(sizeof(void *))));
|
||||
|
||||
extern ssize_t __modver_version_show(struct module_attribute *,
|
||||
struct module *, char *);
|
||||
|
||||
struct module_kobject
|
||||
{
|
||||
struct kobject kobj;
|
||||
|
@ -172,12 +175,7 @@ extern struct module __this_module;
|
|||
#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
|
||||
#else
|
||||
#define MODULE_VERSION(_version) \
|
||||
extern ssize_t __modver_version_show(struct module_attribute *, \
|
||||
struct module *, char *); \
|
||||
static struct module_version_attribute __modver_version_attr \
|
||||
__used \
|
||||
__attribute__ ((__section__ ("__modver"),aligned(sizeof(void *)))) \
|
||||
= { \
|
||||
static struct module_version_attribute ___modver_attr = { \
|
||||
.mattr = { \
|
||||
.attr = { \
|
||||
.name = "version", \
|
||||
|
@ -187,7 +185,10 @@ extern struct module __this_module;
|
|||
}, \
|
||||
.module_name = KBUILD_MODNAME, \
|
||||
.version = _version, \
|
||||
}
|
||||
}; \
|
||||
static const struct module_version_attribute \
|
||||
__used __attribute__ ((__section__ ("__modver"))) \
|
||||
* __moduleparam_const __modver_attr = &___modver_attr
|
||||
#endif
|
||||
|
||||
/* Optional firmware file (or files) needed by the module
|
||||
|
@ -223,7 +224,7 @@ struct module_use {
|
|||
extern void *__crc_##sym __attribute__((weak)); \
|
||||
static const unsigned long __kcrctab_##sym \
|
||||
__used \
|
||||
__attribute__((section("__kcrctab" sec), unused)) \
|
||||
__attribute__((section("___kcrctab" sec "+" #sym), unused)) \
|
||||
= (unsigned long) &__crc_##sym;
|
||||
#else
|
||||
#define __CRC_SYMBOL(sym, sec)
|
||||
|
@ -238,7 +239,7 @@ struct module_use {
|
|||
= MODULE_SYMBOL_PREFIX #sym; \
|
||||
static const struct kernel_symbol __ksymtab_##sym \
|
||||
__used \
|
||||
__attribute__((section("__ksymtab" sec), unused)) \
|
||||
__attribute__((section("___ksymtab" sec "+" #sym), unused)) \
|
||||
= { (unsigned long)&sym, __kstrtab_##sym }
|
||||
|
||||
#define EXPORT_SYMBOL(sym) \
|
||||
|
@ -367,34 +368,35 @@ struct module
|
|||
struct module_notes_attrs *notes_attrs;
|
||||
#endif
|
||||
|
||||
/* The command line arguments (may be mangled). People like
|
||||
keeping pointers to this stuff */
|
||||
char *args;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* Per-cpu data. */
|
||||
void __percpu *percpu;
|
||||
unsigned int percpu_size;
|
||||
#endif
|
||||
|
||||
/* The command line arguments (may be mangled). People like
|
||||
keeping pointers to this stuff */
|
||||
char *args;
|
||||
#ifdef CONFIG_TRACEPOINTS
|
||||
struct tracepoint * const *tracepoints_ptrs;
|
||||
unsigned int num_tracepoints;
|
||||
struct tracepoint * const *tracepoints_ptrs;
|
||||
#endif
|
||||
#ifdef HAVE_JUMP_LABEL
|
||||
struct jump_entry *jump_entries;
|
||||
unsigned int num_jump_entries;
|
||||
#endif
|
||||
#ifdef CONFIG_TRACING
|
||||
const char **trace_bprintk_fmt_start;
|
||||
unsigned int num_trace_bprintk_fmt;
|
||||
const char **trace_bprintk_fmt_start;
|
||||
#endif
|
||||
#ifdef CONFIG_EVENT_TRACING
|
||||
struct ftrace_event_call **trace_events;
|
||||
unsigned int num_trace_events;
|
||||
#endif
|
||||
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
|
||||
unsigned long *ftrace_callsites;
|
||||
unsigned int num_ftrace_callsites;
|
||||
unsigned long *ftrace_callsites;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MODULE_UNLOAD
|
||||
|
@ -475,8 +477,9 @@ const struct kernel_symbol *find_symbol(const char *name,
|
|||
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);
|
||||
bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
|
||||
struct module *owner,
|
||||
void *data), void *data);
|
||||
|
||||
/* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
|
||||
symnum out of range. */
|
||||
|
|
|
@ -67,9 +67,9 @@ struct kparam_string {
|
|||
struct kparam_array
|
||||
{
|
||||
unsigned int max;
|
||||
unsigned int elemsize;
|
||||
unsigned int *num;
|
||||
const struct kernel_param_ops *ops;
|
||||
unsigned int elemsize;
|
||||
void *elem;
|
||||
};
|
||||
|
||||
|
@ -371,8 +371,9 @@ extern int param_get_invbool(char *buffer, const struct kernel_param *kp);
|
|||
*/
|
||||
#define module_param_array_named(name, array, type, nump, perm) \
|
||||
static const struct kparam_array __param_arr_##name \
|
||||
= { ARRAY_SIZE(array), nump, ¶m_ops_##type, \
|
||||
sizeof(array[0]), array }; \
|
||||
= { .max = ARRAY_SIZE(array), .num = nump, \
|
||||
.ops = ¶m_ops_##type, \
|
||||
.elemsize = sizeof(array[0]), .elem = array }; \
|
||||
__module_param_call(MODULE_PARAM_PREFIX, name, \
|
||||
¶m_array_ops, \
|
||||
.arr = &__param_arr_##name, \
|
||||
|
|
|
@ -123,6 +123,7 @@ extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
|
|||
extern void argv_free(char **argv);
|
||||
|
||||
extern bool sysfs_streq(const char *s1, const char *s2);
|
||||
extern int strtobool(const char *s, bool *res);
|
||||
|
||||
#ifdef CONFIG_BINARY_PRINTF
|
||||
int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args);
|
||||
|
|
105
kernel/module.c
105
kernel/module.c
|
@ -57,6 +57,7 @@
|
|||
#include <linux/kmemleak.h>
|
||||
#include <linux/jump_label.h>
|
||||
#include <linux/pfn.h>
|
||||
#include <linux/bsearch.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/module.h>
|
||||
|
@ -240,23 +241,24 @@ static bool each_symbol_in_section(const struct symsearch *arr,
|
|||
struct module *owner,
|
||||
bool (*fn)(const struct symsearch *syms,
|
||||
struct module *owner,
|
||||
unsigned int symnum, void *data),
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned int j;
|
||||
|
||||
for (j = 0; j < arrsize; j++) {
|
||||
for (i = 0; i < arr[j].stop - arr[j].start; i++)
|
||||
if (fn(&arr[j], owner, i, data))
|
||||
return true;
|
||||
if (fn(&arr[j], owner, data))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Returns true as soon as fn returns true, otherwise false. */
|
||||
bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
|
||||
unsigned int symnum, void *data), void *data)
|
||||
bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
|
||||
struct module *owner,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
struct module *mod;
|
||||
static const struct symsearch arr[] = {
|
||||
|
@ -309,7 +311,7 @@ bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
|
|||
}
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(each_symbol);
|
||||
EXPORT_SYMBOL_GPL(each_symbol_section);
|
||||
|
||||
struct find_symbol_arg {
|
||||
/* Input */
|
||||
|
@ -323,15 +325,12 @@ struct find_symbol_arg {
|
|||
const struct kernel_symbol *sym;
|
||||
};
|
||||
|
||||
static bool find_symbol_in_section(const struct symsearch *syms,
|
||||
struct module *owner,
|
||||
unsigned int symnum, void *data)
|
||||
static bool check_symbol(const struct symsearch *syms,
|
||||
struct module *owner,
|
||||
unsigned int symnum, void *data)
|
||||
{
|
||||
struct find_symbol_arg *fsa = data;
|
||||
|
||||
if (strcmp(syms->start[symnum].name, fsa->name) != 0)
|
||||
return false;
|
||||
|
||||
if (!fsa->gplok) {
|
||||
if (syms->licence == GPL_ONLY)
|
||||
return false;
|
||||
|
@ -365,6 +364,30 @@ static bool find_symbol_in_section(const struct symsearch *syms,
|
|||
return true;
|
||||
}
|
||||
|
||||
static int cmp_name(const void *va, const void *vb)
|
||||
{
|
||||
const char *a;
|
||||
const struct kernel_symbol *b;
|
||||
a = va; b = vb;
|
||||
return strcmp(a, b->name);
|
||||
}
|
||||
|
||||
static bool find_symbol_in_section(const struct symsearch *syms,
|
||||
struct module *owner,
|
||||
void *data)
|
||||
{
|
||||
struct find_symbol_arg *fsa = data;
|
||||
struct kernel_symbol *sym;
|
||||
|
||||
sym = bsearch(fsa->name, syms->start, syms->stop - syms->start,
|
||||
sizeof(struct kernel_symbol), cmp_name);
|
||||
|
||||
if (sym != NULL && check_symbol(syms, owner, sym - syms->start, data))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Find a symbol and return it, along with, (optional) crc and
|
||||
* (optional) module which owns it. Needs preempt disabled or module_mutex. */
|
||||
const struct kernel_symbol *find_symbol(const char *name,
|
||||
|
@ -379,7 +402,7 @@ const struct kernel_symbol *find_symbol(const char *name,
|
|||
fsa.gplok = gplok;
|
||||
fsa.warn = warn;
|
||||
|
||||
if (each_symbol(find_symbol_in_section, &fsa)) {
|
||||
if (each_symbol_section(find_symbol_in_section, &fsa)) {
|
||||
if (owner)
|
||||
*owner = fsa.owner;
|
||||
if (crc)
|
||||
|
@ -1607,27 +1630,28 @@ static void set_section_ro_nx(void *base,
|
|||
}
|
||||
}
|
||||
|
||||
/* Setting memory back to RW+NX before releasing it */
|
||||
void unset_section_ro_nx(struct module *mod, void *module_region)
|
||||
static void unset_module_core_ro_nx(struct module *mod)
|
||||
{
|
||||
unsigned long total_pages;
|
||||
set_page_attributes(mod->module_core + mod->core_text_size,
|
||||
mod->module_core + mod->core_size,
|
||||
set_memory_x);
|
||||
set_page_attributes(mod->module_core,
|
||||
mod->module_core + mod->core_ro_size,
|
||||
set_memory_rw);
|
||||
}
|
||||
|
||||
if (mod->module_core == module_region) {
|
||||
/* Set core as NX+RW */
|
||||
total_pages = MOD_NUMBER_OF_PAGES(mod->module_core, mod->core_size);
|
||||
set_memory_nx((unsigned long)mod->module_core, total_pages);
|
||||
set_memory_rw((unsigned long)mod->module_core, total_pages);
|
||||
|
||||
} else if (mod->module_init == module_region) {
|
||||
/* Set init as NX+RW */
|
||||
total_pages = MOD_NUMBER_OF_PAGES(mod->module_init, mod->init_size);
|
||||
set_memory_nx((unsigned long)mod->module_init, total_pages);
|
||||
set_memory_rw((unsigned long)mod->module_init, total_pages);
|
||||
}
|
||||
static void unset_module_init_ro_nx(struct module *mod)
|
||||
{
|
||||
set_page_attributes(mod->module_init + mod->init_text_size,
|
||||
mod->module_init + mod->init_size,
|
||||
set_memory_x);
|
||||
set_page_attributes(mod->module_init,
|
||||
mod->module_init + mod->init_ro_size,
|
||||
set_memory_rw);
|
||||
}
|
||||
|
||||
/* Iterate through all modules and set each module's text as RW */
|
||||
void set_all_modules_text_rw()
|
||||
void set_all_modules_text_rw(void)
|
||||
{
|
||||
struct module *mod;
|
||||
|
||||
|
@ -1648,7 +1672,7 @@ void set_all_modules_text_rw()
|
|||
}
|
||||
|
||||
/* Iterate through all modules and set each module's text as RO */
|
||||
void set_all_modules_text_ro()
|
||||
void set_all_modules_text_ro(void)
|
||||
{
|
||||
struct module *mod;
|
||||
|
||||
|
@ -1669,7 +1693,8 @@ void set_all_modules_text_ro()
|
|||
}
|
||||
#else
|
||||
static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { }
|
||||
static inline void unset_section_ro_nx(struct module *mod, void *module_region) { }
|
||||
static void unset_module_core_ro_nx(struct module *mod) { }
|
||||
static void unset_module_init_ro_nx(struct module *mod) { }
|
||||
#endif
|
||||
|
||||
/* Free a module, remove from lists, etc. */
|
||||
|
@ -1696,7 +1721,7 @@ static void free_module(struct module *mod)
|
|||
destroy_params(mod->kp, mod->num_kp);
|
||||
|
||||
/* This may be NULL, but that's OK */
|
||||
unset_section_ro_nx(mod, mod->module_init);
|
||||
unset_module_init_ro_nx(mod);
|
||||
module_free(mod, mod->module_init);
|
||||
kfree(mod->args);
|
||||
percpu_modfree(mod);
|
||||
|
@ -1705,7 +1730,7 @@ static void free_module(struct module *mod)
|
|||
lockdep_free_key_range(mod->module_core, mod->core_size);
|
||||
|
||||
/* Finally, free the core (containing the module structure) */
|
||||
unset_section_ro_nx(mod, mod->module_core);
|
||||
unset_module_core_ro_nx(mod);
|
||||
module_free(mod, mod->module_core);
|
||||
|
||||
#ifdef CONFIG_MPU
|
||||
|
@ -2030,11 +2055,8 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
|
|||
const struct kernel_symbol *start,
|
||||
const struct kernel_symbol *stop)
|
||||
{
|
||||
const struct kernel_symbol *ks = start;
|
||||
for (; ks < stop; ks++)
|
||||
if (strcmp(ks->name, name) == 0)
|
||||
return ks;
|
||||
return NULL;
|
||||
return bsearch(name, start, stop - start,
|
||||
sizeof(struct kernel_symbol), cmp_name);
|
||||
}
|
||||
|
||||
static int is_exported(const char *name, unsigned long value,
|
||||
|
@ -2931,10 +2953,11 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
|
|||
mod->symtab = mod->core_symtab;
|
||||
mod->strtab = mod->core_strtab;
|
||||
#endif
|
||||
unset_section_ro_nx(mod, mod->module_init);
|
||||
unset_module_init_ro_nx(mod);
|
||||
module_free(mod, mod->module_init);
|
||||
mod->module_init = NULL;
|
||||
mod->init_size = 0;
|
||||
mod->init_ro_size = 0;
|
||||
mod->init_text_size = 0;
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
|
|
|
@ -297,21 +297,15 @@ EXPORT_SYMBOL(param_ops_charp);
|
|||
int param_set_bool(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
bool v;
|
||||
int ret;
|
||||
|
||||
/* No equals means "set"... */
|
||||
if (!val) val = "1";
|
||||
|
||||
/* One of =[yYnN01] */
|
||||
switch (val[0]) {
|
||||
case 'y': case 'Y': case '1':
|
||||
v = true;
|
||||
break;
|
||||
case 'n': case 'N': case '0':
|
||||
v = false;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = strtobool(val, &v);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (kp->flags & KPARAM_ISBOOL)
|
||||
*(bool *)kp->arg = v;
|
||||
|
@ -821,15 +815,18 @@ ssize_t __modver_version_show(struct module_attribute *mattr,
|
|||
return sprintf(buf, "%s\n", vattr->version);
|
||||
}
|
||||
|
||||
extern struct module_version_attribute __start___modver[], __stop___modver[];
|
||||
extern const struct module_version_attribute *__start___modver[];
|
||||
extern const struct module_version_attribute *__stop___modver[];
|
||||
|
||||
static void __init version_sysfs_builtin(void)
|
||||
{
|
||||
const struct module_version_attribute *vattr;
|
||||
const struct module_version_attribute **p;
|
||||
struct module_kobject *mk;
|
||||
int err;
|
||||
|
||||
for (vattr = __start___modver; vattr < __stop___modver; vattr++) {
|
||||
for (p = __start___modver; p < __stop___modver; p++) {
|
||||
const struct module_version_attribute *vattr = *p;
|
||||
|
||||
mk = locate_module_kobject(vattr->module_name);
|
||||
if (mk) {
|
||||
err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
|
||||
|
|
|
@ -21,7 +21,8 @@ lib-y += kobject.o kref.o klist.o
|
|||
|
||||
obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
|
||||
bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
|
||||
string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o
|
||||
string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o \
|
||||
bsearch.o
|
||||
obj-y += kstrtox.o
|
||||
obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
|
||||
|
||||
|
|
53
lib/bsearch.c
Normal file
53
lib/bsearch.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* A generic implementation of binary search for the Linux kernel
|
||||
*
|
||||
* Copyright (C) 2008-2009 Ksplice, Inc.
|
||||
* Author: Tim Abbott <tabbott@ksplice.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; version 2.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/bsearch.h>
|
||||
|
||||
/*
|
||||
* bsearch - binary search an array of elements
|
||||
* @key: pointer to item being searched for
|
||||
* @base: pointer to first element to search
|
||||
* @num: number of elements
|
||||
* @size: size of each element
|
||||
* @cmp: pointer to comparison function
|
||||
*
|
||||
* This function does a binary search on the given array. The
|
||||
* contents of the array should already be in ascending sorted order
|
||||
* under the provided comparison function.
|
||||
*
|
||||
* Note that the key need not have the same type as the elements in
|
||||
* the array, e.g. key could be a string and the comparison function
|
||||
* could compare the string with the struct's name field. However, if
|
||||
* the key and elements in the array are of the same type, you can use
|
||||
* the same comparison function for both sort() and bsearch().
|
||||
*/
|
||||
void *bsearch(const void *key, const void *base, size_t num, size_t size,
|
||||
int (*cmp)(const void *key, const void *elt))
|
||||
{
|
||||
size_t start = 0, end = num;
|
||||
int result;
|
||||
|
||||
while (start < end) {
|
||||
size_t mid = start + (end - start) / 2;
|
||||
|
||||
result = cmp(key, base + mid * size);
|
||||
if (result < 0)
|
||||
end = mid;
|
||||
else if (result > 0)
|
||||
start = mid + 1;
|
||||
else
|
||||
return (void *)base + mid * size;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(bsearch);
|
29
lib/string.c
29
lib/string.c
|
@ -535,6 +535,35 @@ bool sysfs_streq(const char *s1, const char *s2)
|
|||
}
|
||||
EXPORT_SYMBOL(sysfs_streq);
|
||||
|
||||
/**
|
||||
* strtobool - convert common user inputs into boolean values
|
||||
* @s: input string
|
||||
* @res: result
|
||||
*
|
||||
* This routine returns 0 iff the first character is one of 'Yy1Nn0'.
|
||||
* Otherwise it will return -EINVAL. Value pointed to by res is
|
||||
* updated upon finding a match.
|
||||
*/
|
||||
int strtobool(const char *s, bool *res)
|
||||
{
|
||||
switch (s[0]) {
|
||||
case 'y':
|
||||
case 'Y':
|
||||
case '1':
|
||||
*res = true;
|
||||
break;
|
||||
case 'n':
|
||||
case 'N':
|
||||
case '0':
|
||||
*res = false;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(strtobool);
|
||||
|
||||
#ifndef __HAVE_ARCH_MEMSET
|
||||
/**
|
||||
* memset - Fill a region of memory with the given value
|
||||
|
|
|
@ -420,11 +420,10 @@ static int parse_elf(struct elf_info *info, const char *filename)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (hdr->e_shnum == 0) {
|
||||
if (hdr->e_shnum == SHN_UNDEF) {
|
||||
/*
|
||||
* There are more than 64k sections,
|
||||
* read count from .sh_size.
|
||||
* note: it doesn't need shndx2secindex()
|
||||
*/
|
||||
info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
|
||||
}
|
||||
|
@ -432,8 +431,7 @@ static int parse_elf(struct elf_info *info, const char *filename)
|
|||
info->num_sections = hdr->e_shnum;
|
||||
}
|
||||
if (hdr->e_shstrndx == SHN_XINDEX) {
|
||||
info->secindex_strings =
|
||||
shndx2secindex(TO_NATIVE(sechdrs[0].sh_link));
|
||||
info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
|
||||
}
|
||||
else {
|
||||
info->secindex_strings = hdr->e_shstrndx;
|
||||
|
@ -489,7 +487,7 @@ static int parse_elf(struct elf_info *info, const char *filename)
|
|||
sechdrs[i].sh_offset;
|
||||
info->symtab_stop = (void *)hdr +
|
||||
sechdrs[i].sh_offset + sechdrs[i].sh_size;
|
||||
sh_link_idx = shndx2secindex(sechdrs[i].sh_link);
|
||||
sh_link_idx = sechdrs[i].sh_link;
|
||||
info->strtab = (void *)hdr +
|
||||
sechdrs[sh_link_idx].sh_offset;
|
||||
}
|
||||
|
@ -516,11 +514,9 @@ static int parse_elf(struct elf_info *info, const char *filename)
|
|||
|
||||
if (symtab_shndx_idx != ~0U) {
|
||||
Elf32_Word *p;
|
||||
if (symtab_idx !=
|
||||
shndx2secindex(sechdrs[symtab_shndx_idx].sh_link))
|
||||
if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
|
||||
fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
|
||||
filename,
|
||||
shndx2secindex(sechdrs[symtab_shndx_idx].sh_link),
|
||||
filename, sechdrs[symtab_shndx_idx].sh_link,
|
||||
symtab_idx);
|
||||
/* Fix endianness */
|
||||
for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
|
||||
|
@ -1446,7 +1442,7 @@ static unsigned int *reloc_location(struct elf_info *elf,
|
|||
Elf_Shdr *sechdr, Elf_Rela *r)
|
||||
{
|
||||
Elf_Shdr *sechdrs = elf->sechdrs;
|
||||
int section = shndx2secindex(sechdr->sh_info);
|
||||
int section = sechdr->sh_info;
|
||||
|
||||
return (void *)elf->hdr + sechdrs[section].sh_offset +
|
||||
r->r_offset;
|
||||
|
|
|
@ -145,33 +145,22 @@ static inline int is_shndx_special(unsigned int i)
|
|||
return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
|
||||
}
|
||||
|
||||
/* shndx is in [0..SHN_LORESERVE) U (SHN_HIRESERVE, 0xfffffff], thus:
|
||||
* shndx == 0 <=> sechdrs[0]
|
||||
* ......
|
||||
* shndx == SHN_LORESERVE-1 <=> sechdrs[SHN_LORESERVE-1]
|
||||
* shndx == SHN_HIRESERVE+1 <=> sechdrs[SHN_LORESERVE]
|
||||
* shndx == SHN_HIRESERVE+2 <=> sechdrs[SHN_LORESERVE+1]
|
||||
* ......
|
||||
* fyi: sym->st_shndx is uint16, SHN_LORESERVE = ff00, SHN_HIRESERVE = ffff,
|
||||
* so basically we map 0000..feff -> 0000..feff
|
||||
* ff00..ffff -> (you are a bad boy, dont do it)
|
||||
* 10000..xxxx -> ff00..(xxxx-0x100)
|
||||
/*
|
||||
* Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
|
||||
* the way to -256..-1, to avoid conflicting with real section
|
||||
* indices.
|
||||
*/
|
||||
static inline unsigned int shndx2secindex(unsigned int i)
|
||||
{
|
||||
if (i <= SHN_HIRESERVE)
|
||||
return i;
|
||||
return i - (SHN_HIRESERVE + 1 - SHN_LORESERVE);
|
||||
}
|
||||
#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1))
|
||||
|
||||
/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
|
||||
static inline unsigned int get_secindex(const struct elf_info *info,
|
||||
const Elf_Sym *sym)
|
||||
{
|
||||
if (is_shndx_special(sym->st_shndx))
|
||||
return SPECIAL(sym->st_shndx);
|
||||
if (sym->st_shndx != SHN_XINDEX)
|
||||
return sym->st_shndx;
|
||||
return shndx2secindex(info->symtab_shndx_start[sym -
|
||||
info->symtab_start]);
|
||||
return info->symtab_shndx_start[sym - info->symtab_start];
|
||||
}
|
||||
|
||||
/* file2alias.c */
|
||||
|
|
|
@ -5,4 +5,15 @@
|
|||
*/
|
||||
SECTIONS {
|
||||
/DISCARD/ : { *(.discard) }
|
||||
|
||||
__ksymtab : { *(SORT(___ksymtab+*)) }
|
||||
__ksymtab_gpl : { *(SORT(___ksymtab_gpl+*)) }
|
||||
__ksymtab_unused : { *(SORT(___ksymtab_unused+*)) }
|
||||
__ksymtab_unused_gpl : { *(SORT(___ksymtab_unused_gpl+*)) }
|
||||
__ksymtab_gpl_future : { *(SORT(___ksymtab_gpl_future+*)) }
|
||||
__kcrctab : { *(SORT(___kcrctab+*)) }
|
||||
__kcrctab_gpl : { *(SORT(___kcrctab_gpl+*)) }
|
||||
__kcrctab_unused : { *(SORT(___kcrctab_unused+*)) }
|
||||
__kcrctab_unused_gpl : { *(SORT(___kcrctab_unused_gpl+*)) }
|
||||
__kcrctab_gpl_future : { *(SORT(___kcrctab_gpl_future+*)) }
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue