Commit f71d20e9 authored by Arjan van de Ven's avatar Arjan van de Ven Committed by Linus Torvalds

[PATCH] Add EXPORT_UNUSED_SYMBOL and EXPORT_UNUSED_SYMBOL_GPL

Temporarily add EXPORT_UNUSED_SYMBOL and EXPORT_UNUSED_SYMBOL_GPL.  These
will be used as a transition measure for symbols that aren't used in the
kernel and are on the way out.  When a module uses such a symbol, a warning
is printk'd at modprobe time.

The main reason for removing unused exports is size: eacho export takes
roughly between 100 and 150 bytes of kernel space in the binary.  This
patch gives users the option to immediately get this size gain via a config
option.
Signed-off-by: default avatarArjan van de Ven <arjan@linux.intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f5e54d6e
...@@ -177,6 +177,16 @@ Who: Jean Delvare <khali@linux-fr.org> ...@@ -177,6 +177,16 @@ Who: Jean Delvare <khali@linux-fr.org>
--------------------------- ---------------------------
What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
(temporary transition config option provided until then)
The transition config option will also be removed at the same time.
When: before 2.6.19
Why: Unused symbols are both increasing the size of the kernel binary
and are often a sign of "wrong API"
Who: Arjan van de Ven <arjan@linux.intel.com>
---------------------------
What: remove EXPORT_SYMBOL(tasklist_lock) What: remove EXPORT_SYMBOL(tasklist_lock)
When: August 2006 When: August 2006
Files: kernel/fork.c Files: kernel/fork.c
......
...@@ -58,6 +58,20 @@ ...@@ -58,6 +58,20 @@
VMLINUX_SYMBOL(__stop___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) \
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) \
VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \
} \
\
/* Kernel symbol table: GPL-future-only symbols */ \ /* Kernel symbol table: GPL-future-only symbols */ \
__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \ __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \ VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \
...@@ -79,6 +93,20 @@ ...@@ -79,6 +93,20 @@
VMLINUX_SYMBOL(__stop___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) \
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) \
VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \
} \
\
/* Kernel symbol table: GPL-future-only symbols */ \ /* Kernel symbol table: GPL-future-only symbols */ \
__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \ __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \ VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \
......
...@@ -203,6 +203,15 @@ void *__symbol_get_gpl(const char *symbol); ...@@ -203,6 +203,15 @@ void *__symbol_get_gpl(const char *symbol);
#define EXPORT_SYMBOL_GPL_FUTURE(sym) \ #define EXPORT_SYMBOL_GPL_FUTURE(sym) \
__EXPORT_SYMBOL(sym, "_gpl_future") __EXPORT_SYMBOL(sym, "_gpl_future")
#ifdef CONFIG_UNUSED_SYMBOLS
#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl")
#else
#define EXPORT_UNUSED_SYMBOL(sym)
#define EXPORT_UNUSED_SYMBOL_GPL(sym)
#endif
#endif #endif
struct module_ref struct module_ref
...@@ -261,6 +270,15 @@ struct module ...@@ -261,6 +270,15 @@ struct module
unsigned int num_gpl_syms; unsigned int num_gpl_syms;
const unsigned long *gpl_crcs; const unsigned long *gpl_crcs;
/* unused exported symbols. */
const struct kernel_symbol *unused_syms;
unsigned int num_unused_syms;
const unsigned long *unused_crcs;
/* GPL-only, unused exported symbols. */
const struct kernel_symbol *unused_gpl_syms;
unsigned int num_unused_gpl_syms;
const unsigned long *unused_gpl_crcs;
/* symbols that will be GPL-only in the near future. */ /* symbols that will be GPL-only in the near future. */
const struct kernel_symbol *gpl_future_syms; const struct kernel_symbol *gpl_future_syms;
unsigned int num_gpl_future_syms; unsigned int num_gpl_future_syms;
...@@ -456,6 +474,8 @@ void module_remove_driver(struct device_driver *); ...@@ -456,6 +474,8 @@ void module_remove_driver(struct device_driver *);
#define EXPORT_SYMBOL(sym) #define EXPORT_SYMBOL(sym)
#define EXPORT_SYMBOL_GPL(sym) #define EXPORT_SYMBOL_GPL(sym)
#define EXPORT_SYMBOL_GPL_FUTURE(sym) #define EXPORT_SYMBOL_GPL_FUTURE(sym)
#define EXPORT_UNUSED_SYMBOL(sym)
#define EXPORT_UNUSED_SYMBOL_GPL(sym)
/* Given an address, look for it in the exception tables. */ /* Given an address, look for it in the exception tables. */
static inline const struct exception_table_entry * static inline const struct exception_table_entry *
......
/* Rewritten by Rusty Russell, on the backs of many others... /*
Copyright (C) 2002 Richard Henderson Copyright (C) 2002 Richard Henderson
Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM. Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
...@@ -122,9 +122,17 @@ extern const struct kernel_symbol __start___ksymtab_gpl[]; ...@@ -122,9 +122,17 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
extern const struct kernel_symbol __stop___ksymtab_gpl[]; extern const struct kernel_symbol __stop___ksymtab_gpl[];
extern const struct kernel_symbol __start___ksymtab_gpl_future[]; extern const struct kernel_symbol __start___ksymtab_gpl_future[];
extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
extern const struct kernel_symbol __start___ksymtab_unused[];
extern const struct kernel_symbol __stop___ksymtab_unused[];
extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
extern const struct kernel_symbol __start___ksymtab_gpl_future[];
extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
extern const unsigned long __start___kcrctab[]; extern const unsigned long __start___kcrctab[];
extern const unsigned long __start___kcrctab_gpl[]; extern const unsigned long __start___kcrctab_gpl[];
extern const unsigned long __start___kcrctab_gpl_future[]; extern const unsigned long __start___kcrctab_gpl_future[];
extern const unsigned long __start___kcrctab_unused[];
extern const unsigned long __start___kcrctab_unused_gpl[];
#ifndef CONFIG_MODVERSIONS #ifndef CONFIG_MODVERSIONS
#define symversion(base, idx) NULL #define symversion(base, idx) NULL
...@@ -144,6 +152,17 @@ static const struct kernel_symbol *lookup_symbol(const char *name, ...@@ -144,6 +152,17 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
return NULL; return NULL;
} }
static void printk_unused_warning(const char *name)
{
printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
"however this module is using it.\n", name);
printk(KERN_WARNING "This symbol will go away in the future.\n");
printk(KERN_WARNING "Please evalute if this is the right api to use, "
"and if it really is, submit a report the linux kernel "
"mailinglist together with submitting your code for "
"inclusion.\n");
}
/* Find a symbol, return value, crc and module which owns it */ /* Find a symbol, return value, crc and module which owns it */
static unsigned long __find_symbol(const char *name, static unsigned long __find_symbol(const char *name,
struct module **owner, struct module **owner,
...@@ -186,6 +205,25 @@ static unsigned long __find_symbol(const char *name, ...@@ -186,6 +205,25 @@ static unsigned long __find_symbol(const char *name,
return ks->value; return ks->value;
} }
ks = lookup_symbol(name, __start___ksymtab_unused,
__stop___ksymtab_unused);
if (ks) {
printk_unused_warning(name);
*crc = symversion(__start___kcrctab_unused,
(ks - __start___ksymtab_unused));
return ks->value;
}
if (gplok)
ks = lookup_symbol(name, __start___ksymtab_unused_gpl,
__stop___ksymtab_unused_gpl);
if (ks) {
printk_unused_warning(name);
*crc = symversion(__start___kcrctab_unused_gpl,
(ks - __start___ksymtab_unused_gpl));
return ks->value;
}
/* Now try modules. */ /* Now try modules. */
list_for_each_entry(mod, &modules, list) { list_for_each_entry(mod, &modules, list) {
*owner = mod; *owner = mod;
...@@ -204,6 +242,23 @@ static unsigned long __find_symbol(const char *name, ...@@ -204,6 +242,23 @@ static unsigned long __find_symbol(const char *name,
return ks->value; return ks->value;
} }
} }
ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms);
if (ks) {
printk_unused_warning(name);
*crc = symversion(mod->unused_crcs, (ks - mod->unused_syms));
return ks->value;
}
if (gplok) {
ks = lookup_symbol(name, mod->unused_gpl_syms,
mod->unused_gpl_syms + mod->num_unused_gpl_syms);
if (ks) {
printk_unused_warning(name);
*crc = symversion(mod->unused_gpl_crcs,
(ks - mod->unused_gpl_syms));
return ks->value;
}
}
ks = lookup_symbol(name, mod->gpl_future_syms, ks = lookup_symbol(name, mod->gpl_future_syms,
(mod->gpl_future_syms + (mod->gpl_future_syms +
mod->num_gpl_future_syms)); mod->num_gpl_future_syms));
...@@ -1407,6 +1462,8 @@ static struct module *load_module(void __user *umod, ...@@ -1407,6 +1462,8 @@ static struct module *load_module(void __user *umod,
exportindex, modindex, obsparmindex, infoindex, gplindex, exportindex, modindex, obsparmindex, infoindex, gplindex,
crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex, crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
gplfuturecrcindex, unwindex = 0; gplfuturecrcindex, unwindex = 0;
unsigned int unusedindex, unusedcrcindex, unusedgplindex,
unusedgplcrcindex;
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 */
...@@ -1487,9 +1544,13 @@ static struct module *load_module(void __user *umod, ...@@ -1487,9 +1544,13 @@ static struct module *load_module(void __user *umod,
exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future"); gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused");
unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl");
crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future"); gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused");
unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl");
setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
...@@ -1638,14 +1699,27 @@ static struct module *load_module(void __user *umod, ...@@ -1638,14 +1699,27 @@ static struct module *load_module(void __user *umod,
mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size / mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
sizeof(*mod->gpl_future_syms); sizeof(*mod->gpl_future_syms);
mod->num_unused_syms = sechdrs[unusedindex].sh_size /
sizeof(*mod->unused_syms);
mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size /
sizeof(*mod->unused_gpl_syms);
mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
if (gplfuturecrcindex) if (gplfuturecrcindex)
mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;
if (unusedcrcindex)
mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr;
mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr;
if (unusedgplcrcindex)
mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr;
#ifdef CONFIG_MODVERSIONS #ifdef CONFIG_MODVERSIONS
if ((mod->num_syms && !crcindex) || if ((mod->num_syms && !crcindex) ||
(mod->num_gpl_syms && !gplcrcindex) || (mod->num_gpl_syms && !gplcrcindex) ||
(mod->num_gpl_future_syms && !gplfuturecrcindex)) { (mod->num_gpl_future_syms && !gplfuturecrcindex) ||
(mod->num_unused_syms && !unusedcrcindex) ||
(mod->num_unused_gpl_syms && !unusedgplcrcindex)) {
printk(KERN_WARNING "%s: No versions for exported symbols." printk(KERN_WARNING "%s: No versions for exported symbols."
" Tainting kernel.\n", mod->name); " Tainting kernel.\n", mod->name);
add_taint(TAINT_FORCED_MODULE); add_taint(TAINT_FORCED_MODULE);
......
...@@ -23,6 +23,22 @@ config MAGIC_SYSRQ ...@@ -23,6 +23,22 @@ config MAGIC_SYSRQ
keys are documented in <file:Documentation/sysrq.txt>. Don't say Y keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
unless you really know what this hack does. unless you really know what this hack does.
config UNUSED_SYMBOLS
bool "Enable unused/obsolete exported symbols"
default y if X86
help
Unused but exported symbols make the kernel needlessly bigger. For
that reason most of these unused exports will soon be removed. This
option is provided temporarily to provide a transition period in case
some external kernel module needs one of these symbols anyway. If you
encounter such a case in your module, consider if you are actually
using the right API. (rationale: since nobody in the kernel is using
this in a module, there is a pretty good chance it's actually the
wrong interface to use). If you really need the symbol, please send a
mail to the linux kernel mailing list mentioning the symbol and why
you really need it, and what the merge plan to the mainline kernel for
your module is.
config DEBUG_KERNEL config DEBUG_KERNEL
bool "Kernel debugging" bool "Kernel debugging"
help help
......
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