Commit ccec1be4 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Add a MODULE_VERSION macro

From: Rusty Russell <rusty@au1.ibm.com>

The way it works is that the .mod file contains the name of the module (as
before), but succeeding lines are the constituent parts (assumed to be .c
files, which usually works: if they use MODULE_VERSION in a file for which
this isn't true we'll get a warning).

As we postprocess modules, we look in the .modinfo section for a
"version=", which is placed by the MODULE_VERSION() macro.  This will be of
form "version=<macroarg>" "\0" [24 chars] "\0".  The 24 chars are replaced
by the md4 sum of the .c files and any files they #include using '#include
"file"' which are found in the current directory.  Whitespace is collapsed
outside strings, and comments are ignored for purposes of the sum.

The result is a .modinfo entry such as

	version=1.16ac-rustytest B13E9451C4CA3B89577DEFF



At the kernel summit, various people asked for a MODULE_VERSION macro to
store module strings (for later access through sysfs).  A simple md4 is
needed to identify changes in modules which, inevitably, do not update the
version.  It skips whitespace and comments, and includes #includes which
are in the same dir.

The module versions should be set according to this definition, based on
the RPM one, or CVS Revision tags.  Violators will be shot.

 [<epoch>`:']<version>[`-'<extraversion>]
 <epoch>: A (small) unsigned integer which allows you to start versions
          anew. If not mentioned, it's zero.  eg. "2:1.0" is after
     "1:2.0".
 <version>: The <version> may contain only alphanumerics.
 <extraversion>: Like <version>, but inserted for local
          customizations, eg "rh3" or "rusty1".

Comparison of two versions (assuming same epoch):

Split each into all-digit and all-alphabetical parts.  Compare each one one
at a time: digit parts numerically, alphabetical in ASCII order.  So 0.10
comes after 0.9.
parent f6455f35
...@@ -127,6 +127,24 @@ extern const struct gtype##_id __mod_##gtype##_table \ ...@@ -127,6 +127,24 @@ extern const struct gtype##_id __mod_##gtype##_table \
#define MODULE_DEVICE_TABLE(type,name) \ #define MODULE_DEVICE_TABLE(type,name) \
MODULE_GENERIC_TABLE(type##_device,name) MODULE_GENERIC_TABLE(type##_device,name)
/* Version of form [<epoch>:]<version>[-<extra-version>].
Or for CVS/RCS ID version, everything but the number is stripped.
<epoch>: A (small) unsigned integer which allows you to start versions
anew. If not mentioned, it's zero. eg. "2:1.0" is after
"1:2.0".
<version>: The <version> may contain only alphanumerics and the
character `.'. Ordered by numeric sort for numeric parts,
ascii sort for ascii parts (as per RPM or DEB algorithm).
<extraversion>: Like <version>, but inserted for local
customizations, eg "rh3" or "rusty1".
Using this automatically adds a checksum of the .c files and the
local headers to the end. Use MODULE_VERSION("") if you want just
this. Macro includes room for this.
*/
#define MODULE_VERSION(_version) \
MODULE_INFO(version, _version "\0xxxxxxxxxxxxxxxxxxxxxxxx")
/* Given an address, look for it in the exception tables */ /* Given an address, look for it in the exception tables */
const struct exception_table_entry *search_exception_tables(unsigned long add); const struct exception_table_entry *search_exception_tables(unsigned long add);
......
...@@ -12,7 +12,7 @@ host-progs := fixdep split-include conmakehash docproc kallsyms modpost \ ...@@ -12,7 +12,7 @@ host-progs := fixdep split-include conmakehash docproc kallsyms modpost \
mk_elfconfig pnmtologo bin2c mk_elfconfig pnmtologo bin2c
always := $(host-progs) empty.o always := $(host-progs) empty.o
modpost-objs := modpost.o file2alias.o modpost-objs := modpost.o file2alias.o sumversion.o
subdir-$(CONFIG_MODVERSIONS) += genksyms subdir-$(CONFIG_MODVERSIONS) += genksyms
...@@ -24,7 +24,7 @@ $(addprefix $(obj)/,$(filter-out fixdep,$(always)) $(subdir-y)): $(obj)/fixdep ...@@ -24,7 +24,7 @@ $(addprefix $(obj)/,$(filter-out fixdep,$(always)) $(subdir-y)): $(obj)/fixdep
# dependencies on generated files need to be listed explicitly # dependencies on generated files need to be listed explicitly
$(obj)/modpost.o $(obj)/file2alias.o: $(obj)/elfconfig.h $(obj)/modpost.o $(obj)/file2alias.o $(obj)/sumversion.o: $(obj)/elfconfig.h
quiet_cmd_elfconfig = MKELF $@ quiet_cmd_elfconfig = MKELF $@
cmd_elfconfig = $(obj)/mk_elfconfig $(ARCH) < $< > $@ cmd_elfconfig = $(obj)/mk_elfconfig $(ARCH) < $< > $@
......
...@@ -64,8 +64,6 @@ endif ...@@ -64,8 +64,6 @@ endif
# We keep a list of all modules in $(MODVERDIR) # We keep a list of all modules in $(MODVERDIR)
touch-module = @echo $(@:.o=.ko) > $(MODVERDIR)/$(@F:.o=.mod)
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \ __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m)) \ $(if $(KBUILD_MODULES),$(obj-m)) \
$(subdir-ym) $(always) $(subdir-ym) $(always)
...@@ -178,7 +176,7 @@ endef ...@@ -178,7 +176,7 @@ endef
$(single-used-m): %.o: %.c FORCE $(single-used-m): %.o: %.c FORCE
$(call if_changed_rule,cc_o_c) $(call if_changed_rule,cc_o_c)
$(touch-module) @{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
quiet_cmd_cc_lst_c = MKLST $@ quiet_cmd_cc_lst_c = MKLST $@
cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \ cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
...@@ -273,7 +271,7 @@ $(multi-used-y) : %.o: $(multi-objs-y) FORCE ...@@ -273,7 +271,7 @@ $(multi-used-y) : %.o: $(multi-objs-y) FORCE
$(multi-used-m) : %.o: $(multi-objs-m) FORCE $(multi-used-m) : %.o: $(multi-objs-m) FORCE
$(call if_changed,link_multi-m) $(call if_changed,link_multi-m)
$(touch-module) @{ echo $(@:.o=.ko); echo $(link_multi_deps); } > $(MODVERDIR)/$(@F:.o=.mod)
targets += $(multi-used-y) $(multi-used-m) targets += $(multi-used-y) $(multi-used-m)
......
...@@ -9,7 +9,7 @@ include scripts/Makefile.lib ...@@ -9,7 +9,7 @@ include scripts/Makefile.lib
# #
__modules := $(shell cat /dev/null $(wildcard $(MODVERDIR)/*.mod)) __modules := $(shell head -q -n1 /dev/null $(wildcard $(MODVERDIR)/*.mod))
modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o))) modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o)))
ifneq ($(filter-out $(modules),$(__modules)),) ifneq ($(filter-out $(modules),$(__modules)),)
......
...@@ -10,10 +10,11 @@ include scripts/Makefile.lib ...@@ -10,10 +10,11 @@ include scripts/Makefile.lib
# #
__modules := $(shell cat /dev/null $(wildcard $(MODVERDIR)/*.mod)) __modules := $(shell head -q -n1 /dev/null $(wildcard $(MODVERDIR)/*.mod))
modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o))) modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o)))
ifneq ($(filter-out $(modules),$(__modules)),) ifneq ($(filter-out $(modules),$(__modules)),)
$(warning Trouble: $(__modules) )
$(warning *** Uh-oh, you have stale module entries. You messed with SUBDIRS,) $(warning *** Uh-oh, you have stale module entries. You messed with SUBDIRS,)
$(warning do not complain if something goes wrong.) $(warning do not complain if something goes wrong.)
endif endif
......
...@@ -65,15 +65,15 @@ new_module(char *modname) ...@@ -65,15 +65,15 @@ new_module(char *modname)
struct module *mod; struct module *mod;
char *p; char *p;
mod = NOFAIL(malloc(sizeof(*mod)));
memset(mod, 0, sizeof(*mod));
mod->name = NOFAIL(strdup(modname));
/* strip trailing .o */ /* strip trailing .o */
p = strstr(modname, ".o"); p = strstr(mod->name, ".o");
if (p) if (p)
*p = 0; *p = 0;
mod = NOFAIL(malloc(sizeof(*mod)));
memset(mod, 0, sizeof(*mod));
mod->name = modname;
/* add to list */ /* add to list */
mod->next = modules; mod->next = modules;
modules = mod; modules = mod;
...@@ -194,25 +194,24 @@ grab_file(const char *filename, unsigned long *size) ...@@ -194,25 +194,24 @@ grab_file(const char *filename, unsigned long *size)
int fd; int fd;
fd = open(filename, O_RDONLY); fd = open(filename, O_RDONLY);
if (fd < 0) { if (fstat(fd, &st) != 0)
perror(filename); return NULL;
abort();
}
if (fstat(fd, &st) != 0) {
perror(filename);
abort();
}
*size = st.st_size; *size = st.st_size;
map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED) {
perror(filename);
abort();
}
close(fd); close(fd);
if (map == MAP_FAILED)
return NULL;
return map; return map;
} }
void
release_file(void *file, unsigned long size)
{
munmap(file, size);
}
void void
parse_elf(struct elf_info *info, const char *filename) parse_elf(struct elf_info *info, const char *filename)
{ {
...@@ -222,6 +221,10 @@ parse_elf(struct elf_info *info, const char *filename) ...@@ -222,6 +221,10 @@ parse_elf(struct elf_info *info, const char *filename)
Elf_Sym *sym; Elf_Sym *sym;
hdr = grab_file(filename, &info->size); hdr = grab_file(filename, &info->size);
if (!hdr) {
perror(filename);
abort();
}
info->hdr = hdr; info->hdr = hdr;
if (info->size < sizeof(*hdr)) if (info->size < sizeof(*hdr))
goto truncated; goto truncated;
...@@ -239,11 +242,19 @@ parse_elf(struct elf_info *info, const char *filename) ...@@ -239,11 +242,19 @@ parse_elf(struct elf_info *info, const char *filename)
sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset); sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size); sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link); sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name);
} }
/* Find symbol table. */ /* Find symbol table. */
for (i = 1; i < hdr->e_shnum; i++) { for (i = 1; i < hdr->e_shnum; i++) {
const char *secstrings
= (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
if (sechdrs[i].sh_offset > info->size) if (sechdrs[i].sh_offset > info->size)
goto truncated; goto truncated;
if (strcmp(secstrings+sechdrs[i].sh_name, ".modinfo") == 0) {
info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
info->modinfo_len = sechdrs[i].sh_size;
}
if (sechdrs[i].sh_type != SHT_SYMTAB) if (sechdrs[i].sh_type != SHT_SYMTAB)
continue; continue;
...@@ -274,7 +285,7 @@ parse_elf(struct elf_info *info, const char *filename) ...@@ -274,7 +285,7 @@ parse_elf(struct elf_info *info, const char *filename)
void void
parse_elf_finish(struct elf_info *info) parse_elf_finish(struct elf_info *info)
{ {
munmap(info->hdr, info->size); release_file(info->hdr, info->size);
} }
#define CRC_PFX MODULE_SYMBOL_PREFIX "__crc_" #define CRC_PFX MODULE_SYMBOL_PREFIX "__crc_"
...@@ -372,6 +383,8 @@ read_symbols(char *modname) ...@@ -372,6 +383,8 @@ read_symbols(char *modname)
handle_modversions(mod, &info, sym, symname); handle_modversions(mod, &info, sym, symname);
handle_moddevtable(mod, &info, sym, symname); handle_moddevtable(mod, &info, sym, symname);
} }
maybe_frob_version(modname, info.modinfo, info.modinfo_len,
(void *)info.modinfo - (void *)info.hdr);
parse_elf_finish(&info); parse_elf_finish(&info);
/* Our trick to get versioning for struct_module - it's /* Our trick to get versioning for struct_module - it's
......
...@@ -80,9 +80,19 @@ struct elf_info { ...@@ -80,9 +80,19 @@ struct elf_info {
Elf_Sym *symtab_start; Elf_Sym *symtab_start;
Elf_Sym *symtab_stop; Elf_Sym *symtab_stop;
const char *strtab; const char *strtab;
char *modinfo;
unsigned int modinfo_len;
}; };
void handle_moddevtable(struct module *mod, struct elf_info *info, void handle_moddevtable(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname); Elf_Sym *sym, const char *symname);
void add_moddevtable(struct buffer *buf, struct module *mod); void add_moddevtable(struct buffer *buf, struct module *mod);
void maybe_frob_version(const char *modfilename,
void *modinfo,
unsigned long modinfo_len,
unsigned long modinfo_offset);
void *grab_file(const char *filename, unsigned long *size);
void release_file(void *file, unsigned long size);
This diff is collapsed.
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