[RFC] Add EXPORT_INIT_SYMBOL()?

From: Sam Ravnborg
Date: Sat Feb 02 2008 - 08:52:42 EST


While analysing some of the section mismatches reported
by modpost I came to the conclusion that there
was no good way to say that a certain function could
both be annotated say __cpuinit and exported.

One example is register_cpu_notifier() in kernel/cpu.c
The function is annotated __cpuinit which is correct
as this function is used only in the startup phase
of a non HOTPLUG_CPU kernel and always available if
CONFIG_HOTPLUG_CPU is equal 'y'.

There are more examples in the tree - I have used
register_cpu_notifier as an example.

So that left me with the following choices:
a) Drop the annotation of register_cpu_notifier()
thus wasting memory and loosing the checks
performed by modpost.
b) Add a small helper function annotated __ref
that would call the __cpuinit annotated
__register_cpu_notifier()
c) Drop all section mismatch checks for exported
symbols expect those annotated with __init
d) Add a new EXPORT_SYMBOL variant that tell modpost
that this symbol are safe to use any of the
__devinit, __cpuinit, __meminit annotated
functions.

I was quite tempted to just go for c) but decided to
get some opinions on approach d).
Implemented with following patch - and uses
the new EXPOST_INIT_SYMBOL() for register_cpu_notifier.

Btw. I went for EXPORT_INIT_SYMBOL in favour of
EXPORT_SYMBOL_INIT as the latter syntax is used for
symbol classification.

Comments?

Note: This is an RFC - I will split it up in two
patches if we go for this. One that introduce
EXPORT_INIT_SYMBOL and another that use the
new EXPORT for register_cpu_notifier().

Sam

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index f784d2f..c64a675 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -97,6 +97,7 @@
__ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab) = .; \
*(__ksymtab) \
+ *(__ksymtab_init) \
VMLINUX_SYMBOL(__stop___ksymtab) = .; \
} \
\
@@ -132,6 +133,7 @@
__kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab) = .; \
*(__kcrctab) \
+ *(__kcrctab_init) \
VMLINUX_SYMBOL(__stop___kcrctab) = .; \
} \
\
diff --git a/include/linux/module.h b/include/linux/module.h
index ac481e2..f853b06 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -206,6 +206,14 @@ void *__symbol_get_gpl(const char *symbol);
#define EXPORT_SYMBOL_GPL_FUTURE(sym) \
__EXPORT_SYMBOL(sym, "_gpl_future")

+/*
+ * Use EXPORT_INIT_SYMBOL for code that are annotated __*init
+ * to document that this symbol is used only during the
+ * early init phase.
+ */
+#define EXPORT_INIT_SYMBOL(sym) \
+ __EXPORT_SYMBOL(sym, "_init")
+

#ifdef CONFIG_UNUSED_SYMBOLS
#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
diff --git a/kernel/cpu.c b/kernel/cpu.c
index e0d3a4f..91833af 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -147,7 +147,7 @@ int __cpuinit register_cpu_notifier(struct notifier_block *nb)

#ifdef CONFIG_HOTPLUG_CPU

-EXPORT_SYMBOL(register_cpu_notifier);
+EXPORT_INIT_SYMBOL(register_cpu_notifier);

void unregister_cpu_notifier(struct notifier_block *nb)
{
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index f8efc93..f4d660e 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -33,7 +33,8 @@ static int sec_mismatch_verbose = 1;

enum export {
export_plain, export_unused, export_gpl,
- export_unused_gpl, export_gpl_future, export_unknown
+ export_unused_gpl, export_gpl_future, export_init,
+ export_unknown
};

#define PRINTF __attribute__ ((format (printf, 1, 2)))
@@ -220,6 +221,7 @@ static struct {
{ .str = "EXPORT_SYMBOL_GPL", .export = export_gpl },
{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
+ { .str = "EXPORT_INIT_SYMBOL", .export = export_init },
{ .str = "(unknown)", .export = export_unknown },
};

@@ -254,6 +256,8 @@ static enum export export_from_sec(struct elf_info *elf, Elf_Section sec)
return export_unused_gpl;
else if (sec == elf->export_gpl_future_sec)
return export_gpl_future;
+ else if (sec == elf->export_init_sec)
+ return export_init;
else
return export_unknown;
}
@@ -435,6 +439,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
info->export_unused_gpl_sec = i;
else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
info->export_gpl_future_sec = i;
+ else if (strcmp(secname, "__ksymtab_init") == 0)
+ info->export_init_sec = i;

if (sechdrs[i].sh_type != SHT_SYMTAB)
continue;
@@ -867,6 +873,13 @@ const struct sectioncheck sectioncheck[] = {
.tosec = { ALL_INIT_SECTIONS, NULL },
.mismatch = EXIT_TO_INIT,
},
+/* export from __ksymtab_init to *init / *exit functions or data is OK */
+{
+ .fromsec = { "__ksymtab_init*", NULL },
+ .tosec = { DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, MEM_INIT_SECTIONS,
+ DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS, NULL },
+ .mismatch = NO_MISMATCH
+},
/* Do not export init/exit functions or data */
{
.fromsec = { "__ksymtab*", NULL },
@@ -1573,6 +1586,7 @@ static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
case export_plain:
case export_unused:
case export_unknown:
+ case export_init:
/* ignore */
break;
}
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 999f15e..3d3ea05 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -126,6 +126,7 @@ struct elf_info {
Elf_Section export_gpl_sec;
Elf_Section export_unused_gpl_sec;
Elf_Section export_gpl_future_sec;
+ Elf_Section export_init_sec;
const char *strtab;
char *modinfo;
unsigned int modinfo_len;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/