linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: Question on MODULE_VERSION macro
       [not found] <20040119214233.GF967@beaverton.ibm.com>
@ 2004-01-20  0:57 ` Rusty Russell
  2004-01-20  1:17   ` Greg KH
  0 siblings, 1 reply; 14+ messages in thread
From: Rusty Russell @ 2004-01-20  0:57 UTC (permalink / raw)
  To: Mike Anderson
  Cc: linux-kernel, Brian King, Christoph Hellwig, greg, kai, sam, akpm

In message <20040119214233.GF967@beaverton.ibm.com> you write:
> Rusty,
> 	Christoph mentioned that a MODULE_VERSION macro may be pending.

Hey, thanks Christoph for the reminder.  I stopped when we were
frozen.

This still seems to apply.  Do people think this is huge overkill, or
a work of obvious beauty and genius?

Doesn't put things in sysfs, but Greg was working on that for module
parameters... Greg?

Cheers,
Rusty.

Name: Add a MODULE_VERSION macro
Author: Rusty Russell
Status: Tested on 2.6.0-test5

D: At the kernel summit, various people asked for a MODULE_VERSION
D: macro to store module strings (for later access through sysfs).
D: A simple md4 is needed to identify changes in modules which,
D: inevitably, do not update the version.  It skips whitespace and
D: comments, and includes #includes which are in the same dir.
D: 
D: The module versions should be set according to this definition,
D: based on the RPM one, or CVS Revision tags.  Violators will be shot.
D: 
D:  [<epoch>`:']<version>[`-'<extraversion>]
D:  <epoch>: A (small) unsigned integer which allows you to start versions
D:           anew. If not mentioned, it's zero.  eg. "2:1.0" is after
D:	     "1:2.0".
D:  <version>: The <version> may contain only alphanumerics.
D:  <extraversion>: Like <version>, but inserted for local
D:           customizations, eg "rh3" or "rusty1".
D: 
D: Comparison of two versions (assuming same epoch):
D: 
D: Split each into all-digit and all-alphabetical parts.  Compare each
D: one one at a time: digit parts numerically, alphabetical in ASCII
D: order.  So 0.10 comes after 0.9.

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/include/linux/module.h .25664-linux-2.6.0-test6-bk6.updated/include/linux/module.h
--- .25664-linux-2.6.0-test6-bk6/include/linux/module.h	2003-09-22 10:26:13.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/include/linux/module.h	2003-10-05 16:45:10.000000000 +1000
@@ -123,6 +123,24 @@ extern const struct gtype##_id __mod_##g
 #define MODULE_DEVICE_TABLE(type,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 */
 const struct exception_table_entry *search_exception_tables(unsigned long add);
 
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/scripts/Makefile .25664-linux-2.6.0-test6-bk6.updated/scripts/Makefile
--- .25664-linux-2.6.0-test6-bk6/scripts/Makefile	2003-09-29 10:26:16.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/scripts/Makefile	2003-10-05 16:45:10.000000000 +1000
@@ -12,7 +12,7 @@ host-progs	:= fixdep split-include conma
 		   mk_elfconfig pnmtologo bin2c
 always		:= $(host-progs) empty.o
 
-modpost-objs	:= modpost.o file2alias.o
+modpost-objs	:= modpost.o file2alias.o sumversion.o
 
 subdir-$(CONFIG_MODVERSIONS)	+= genksyms
 
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/scripts/Makefile.build .25664-linux-2.6.0-test6-bk6.updated/scripts/Makefile.build
--- .25664-linux-2.6.0-test6-bk6/scripts/Makefile.build	2003-09-29 10:26:16.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/scripts/Makefile.build	2003-10-05 16:45:10.000000000 +1000
@@ -64,8 +64,6 @@ endif
 
 # 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)) \
 	 $(if $(KBUILD_MODULES),$(obj-m)) \
 	 $(subdir-ym) $(always)
@@ -178,7 +176,7 @@ endef
 
 $(single-used-m): %.o: %.c FORCE
 	$(call if_changed_rule,cc_o_c)
-	$(touch-module)
+	@{ echo $(@:.o=.ko); echo $<; } > $(MODVERDIR)/$(@F:.o=.mod)
 
 quiet_cmd_cc_lst_c = MKLST   $@
       cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
@@ -273,7 +271,7 @@ $(multi-used-y) : %.o: $(multi-objs-y) F
 
 $(multi-used-m) : %.o: $(multi-objs-m) FORCE
 	$(call if_changed,link_multi-m)
-	$(touch-module)
+	@{ echo $(@:.o=.ko); echo $(link_multi_deps:.o=.c); } > $(MODVERDIR)/$(@F:.o=.mod)
 
 targets += $(multi-used-y) $(multi-used-m)
 
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/scripts/Makefile.modpost .25664-linux-2.6.0-test6-bk6.updated/scripts/Makefile.modpost
--- .25664-linux-2.6.0-test6-bk6/scripts/Makefile.modpost	2003-09-29 10:26:16.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/scripts/Makefile.modpost	2003-10-05 16:45:10.000000000 +1000
@@ -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)))
 
 ifneq ($(filter-out $(modules),$(__modules)),)
+  $(warning Trouble: $(__modules) )
   $(warning *** Uh-oh, you have stale module entries. You messed with SUBDIRS,)
   $(warning     do not complain if something goes wrong.)
 endif
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/scripts/modpost.c .25664-linux-2.6.0-test6-bk6.updated/scripts/modpost.c
--- .25664-linux-2.6.0-test6-bk6/scripts/modpost.c	2003-09-29 10:26:16.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/scripts/modpost.c	2003-10-05 16:46:49.000000000 +1000
@@ -65,15 +65,15 @@ new_module(char *modname)
 	struct module *mod;
 	char *p;
 	
+	mod = NOFAIL(malloc(sizeof(*mod)));
+	memset(mod, 0, sizeof(*mod));
+	mod->name = NOFAIL(strdup(modname));
+
 	/* strip trailing .o */
-	p = strstr(modname, ".o");
+	p = strstr(mod->name, ".o");
 	if (p)
 		*p = 0;
 
-	mod = NOFAIL(malloc(sizeof(*mod)));
-	memset(mod, 0, sizeof(*mod));
-	mod->name = modname;
-
 	/* add to list */
 	mod->next = modules;
 	modules = mod;
@@ -182,26 +182,25 @@ grab_file(const char *filename, unsigned
 	int fd;
 
 	fd = open(filename, O_RDONLY);
-	if (fd < 0) {
-		perror(filename);
-		abort();
-	}
-	if (fstat(fd, &st) != 0) {
-		perror(filename);
-		abort();
-	}
+	if (fstat(fd, &st) != 0)
+		return NULL;
 
 	*size = st.st_size;
 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-	if (map == MAP_FAILED) {
-		perror(filename);
-		abort();
-	}
 	close(fd);
+
+	if (map == MAP_FAILED)
+		return NULL;
 	return map;
 }
 
 void
+release_file(void *file, unsigned long size)
+{
+	munmap(file, size);
+}
+
+void
 parse_elf(struct elf_info *info, const char *filename)
 {
 	unsigned int i;
@@ -210,6 +209,10 @@ parse_elf(struct elf_info *info, const c
 	Elf_Sym  *sym;
 
 	hdr = grab_file(filename, &info->size);
+	if (!hdr) {
+		perror(filename);
+		abort();
+	}
 	info->hdr = hdr;
 	if (info->size < sizeof(*hdr))
 		goto truncated;
@@ -227,11 +230,19 @@ parse_elf(struct elf_info *info, const c
 		sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
 		sechdrs[i].sh_size   = TO_NATIVE(sechdrs[i].sh_size);
 		sechdrs[i].sh_link   = TO_NATIVE(sechdrs[i].sh_link);
+		sechdrs[i].sh_name   = TO_NATIVE(sechdrs[i].sh_name);
 	}
 	/* Find symbol table. */
 	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)
 			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)
 			continue;
 
@@ -262,7 +273,7 @@ parse_elf(struct elf_info *info, const c
 void
 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_"
@@ -348,6 +359,8 @@ read_symbols(char *modname)
 		handle_modversions(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);
 
 	/* Our trick to get versioning for struct_module - it's
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/scripts/modpost.h .25664-linux-2.6.0-test6-bk6.updated/scripts/modpost.h
--- .25664-linux-2.6.0-test6-bk6/scripts/modpost.h	2003-09-22 10:06:44.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/scripts/modpost.h	2003-10-05 16:45:10.000000000 +1000
@@ -80,9 +80,19 @@ struct elf_info {
 	Elf_Sym      *symtab_start;
 	Elf_Sym      *symtab_stop;
 	const char   *strtab;
+	char	     *modinfo;
+	unsigned int modinfo_len;
 };
 
 void handle_moddevtable(struct module *mod, struct elf_info *info,
 			Elf_Sym *sym, const char *symname);
 
 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);
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/scripts/sumversion.c .25664-linux-2.6.0-test6-bk6.updated/scripts/sumversion.c
--- .25664-linux-2.6.0-test6-bk6/scripts/sumversion.c	1970-01-01 10:00:00.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/scripts/sumversion.c	2003-10-05 16:45:10.000000000 +1000
@@ -0,0 +1,540 @@
+#include <netinet/in.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include "modpost.h"
+
+/* Parse tag=value strings from .modinfo section */
+static char *next_string(char *string, unsigned long *secsize)
+{
+	/* Skip non-zero chars */
+	while (string[0]) {
+		string++;
+		if ((*secsize)-- <= 1)
+			return NULL;
+	}
+
+	/* Skip any zero padding. */
+	while (!string[0]) {
+		string++;
+		if ((*secsize)-- <= 1)
+			return NULL;
+	}
+	return string;
+}
+
+static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
+			 const char *tag)
+{
+	char *p;
+	unsigned int taglen = strlen(tag);
+	unsigned long size = modinfo_len;
+
+	for (p = modinfo; p; p = next_string(p, &size)) {
+		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
+			return p + taglen + 1;
+	}
+	return NULL;
+}
+
+/* 
+ * Stolen form Cryptographic API.
+ *
+ * MD4 Message Digest Algorithm (RFC1320).
+ *
+ * Implementation derived from Andrew Tridgell and Steve French's
+ * CIFS MD4 implementation, and the cryptoapi implementation
+ * originally based on the public domain implementation written
+ * by Colin Plumb in 1993.
+ *
+ * Copyright (c) Andrew Tridgell 1997-1998.
+ * Modified by Steve French (sfrench@us.ibm.com) 2002
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#define MD4_DIGEST_SIZE		16
+#define MD4_HMAC_BLOCK_SIZE	64
+#define MD4_BLOCK_WORDS		16
+#define MD4_HASH_WORDS		4
+
+struct md4_ctx {
+	uint32_t hash[MD4_HASH_WORDS];
+	uint32_t block[MD4_BLOCK_WORDS];
+	uint64_t byte_count;
+};
+
+static inline uint32_t lshift(uint32_t x, unsigned int s)
+{
+	x &= 0xFFFFFFFF;
+	return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
+{
+	return (x & y) | ((~x) & z);
+}
+
+static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
+{
+	return (x & y) | (x & z) | (y & z);
+}
+
+static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
+{
+	return x ^ y ^ z;
+}
+                        
+#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
+#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
+#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
+
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
+{
+	while (words--) {
+		*buf = ntohl(*buf);
+		buf++;
+	}
+}
+
+static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
+{
+	while (words--) {
+		*buf = htonl(*buf);
+		buf++;
+	}
+}
+
+static void md4_transform(uint32_t *hash, uint32_t const *in)
+{
+	uint32_t a, b, c, d;
+
+	a = hash[0];
+	b = hash[1];
+	c = hash[2];
+	d = hash[3];
+
+	ROUND1(a, b, c, d, in[0], 3);
+	ROUND1(d, a, b, c, in[1], 7);
+	ROUND1(c, d, a, b, in[2], 11);
+	ROUND1(b, c, d, a, in[3], 19);
+	ROUND1(a, b, c, d, in[4], 3);
+	ROUND1(d, a, b, c, in[5], 7);
+	ROUND1(c, d, a, b, in[6], 11);
+	ROUND1(b, c, d, a, in[7], 19);
+	ROUND1(a, b, c, d, in[8], 3);
+	ROUND1(d, a, b, c, in[9], 7);
+	ROUND1(c, d, a, b, in[10], 11);
+	ROUND1(b, c, d, a, in[11], 19);
+	ROUND1(a, b, c, d, in[12], 3);
+	ROUND1(d, a, b, c, in[13], 7);
+	ROUND1(c, d, a, b, in[14], 11);
+	ROUND1(b, c, d, a, in[15], 19);
+
+	ROUND2(a, b, c, d,in[ 0], 3);
+	ROUND2(d, a, b, c, in[4], 5);
+	ROUND2(c, d, a, b, in[8], 9);
+	ROUND2(b, c, d, a, in[12], 13);
+	ROUND2(a, b, c, d, in[1], 3);
+	ROUND2(d, a, b, c, in[5], 5);
+	ROUND2(c, d, a, b, in[9], 9);
+	ROUND2(b, c, d, a, in[13], 13);
+	ROUND2(a, b, c, d, in[2], 3);
+	ROUND2(d, a, b, c, in[6], 5);
+	ROUND2(c, d, a, b, in[10], 9);
+	ROUND2(b, c, d, a, in[14], 13);
+	ROUND2(a, b, c, d, in[3], 3);
+	ROUND2(d, a, b, c, in[7], 5);
+	ROUND2(c, d, a, b, in[11], 9);
+	ROUND2(b, c, d, a, in[15], 13);
+
+	ROUND3(a, b, c, d,in[ 0], 3);
+	ROUND3(d, a, b, c, in[8], 9);
+	ROUND3(c, d, a, b, in[4], 11);
+	ROUND3(b, c, d, a, in[12], 15);
+	ROUND3(a, b, c, d, in[2], 3);
+	ROUND3(d, a, b, c, in[10], 9);
+	ROUND3(c, d, a, b, in[6], 11);
+	ROUND3(b, c, d, a, in[14], 15);
+	ROUND3(a, b, c, d, in[1], 3);
+	ROUND3(d, a, b, c, in[9], 9);
+	ROUND3(c, d, a, b, in[5], 11);
+	ROUND3(b, c, d, a, in[13], 15);
+	ROUND3(a, b, c, d, in[3], 3);
+	ROUND3(d, a, b, c, in[11], 9);
+	ROUND3(c, d, a, b, in[7], 11);
+	ROUND3(b, c, d, a, in[15], 15);
+
+	hash[0] += a;
+	hash[1] += b;
+	hash[2] += c;
+	hash[3] += d;
+}
+
+static inline void md4_transform_helper(struct md4_ctx *ctx)
+{
+	le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
+	md4_transform(ctx->hash, ctx->block);
+}
+
+static void md4_init(struct md4_ctx *mctx)
+{
+	mctx->hash[0] = 0x67452301;
+	mctx->hash[1] = 0xefcdab89;
+	mctx->hash[2] = 0x98badcfe;
+	mctx->hash[3] = 0x10325476;
+	mctx->byte_count = 0;
+}
+
+static void md4_update(struct md4_ctx *mctx,
+		       const unsigned char *data, unsigned int len)
+{
+	const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+	mctx->byte_count += len;
+
+	if (avail > len) {
+		memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+		       data, len);
+		return;
+	}
+
+	memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+	       data, avail);
+
+	md4_transform_helper(mctx);
+	data += avail;
+	len -= avail;
+
+	while (len >= sizeof(mctx->block)) {
+		memcpy(mctx->block, data, sizeof(mctx->block));
+		md4_transform_helper(mctx);
+		data += sizeof(mctx->block);
+		len -= sizeof(mctx->block);
+	}
+
+	memcpy(mctx->block, data, len);
+}
+
+static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
+{
+	const unsigned int offset = mctx->byte_count & 0x3f;
+	char *p = (char *)mctx->block + offset;
+	int padding = 56 - (offset + 1);
+
+	*p++ = 0x80;
+	if (padding < 0) {
+		memset(p, 0x00, padding + sizeof (uint64_t));
+		md4_transform_helper(mctx);
+		p = (char *)mctx->block;
+		padding = 56;
+	}
+
+	memset(p, 0, padding);
+	mctx->block[14] = mctx->byte_count << 3;
+	mctx->block[15] = mctx->byte_count >> 29;
+	le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
+	                  sizeof(uint64_t)) / sizeof(uint32_t));
+	md4_transform(mctx->hash, mctx->block);
+	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
+	
+	snprintf(out, len, "%08X%08X%08X%08X",
+		 mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
+}
+
+static int parse_file(const char *fname, struct md4_ctx *md);
+
+/* Local include files, if in current dir. */
+static void include_file(const char *line, int maxlen, const char *base,
+			 struct md4_ctx *md)
+{
+	unsigned int i;
+
+	for (i = 0; line[i] != '"'; i++) {
+		if (i == maxlen) {
+			fprintf(stderr,
+				"sumversion: badly formed #include in %s\n",
+				base);
+			return;
+		}
+	}
+
+	{
+		const char *dirend;
+		char fname[i + strlen(base)];
+
+		dirend = strrchr(base, '/');
+		if (!dirend)
+			dirend = base;
+		else
+			dirend++;
+		memcpy(fname, base, dirend - base);
+		memcpy(fname + (dirend - base), line, i);
+		fname[(dirend - base) + i] = '\0';
+
+		parse_file(fname, md);
+	}
+}
+
+static inline void add_char(unsigned char c, struct md4_ctx *md)
+{
+	md4_update(md, &c, 1);
+}
+
+static int parse_string(const char *file, unsigned long len,
+			struct md4_ctx *md)
+{
+	unsigned long i;
+
+	add_char(file[0], md);
+	for (i = 1; i < len; i++) {
+		add_char(file[i], md);
+		if (file[i] == '"' && file[i-1] != '\\')
+			break;
+	}
+	return i;
+}
+
+static int parse_comment(const char *file, unsigned long len)
+{
+	unsigned long i;
+
+	for (i = 2; i < len; i++) {
+		if (file[i-1] == '*' && file[i] == '/')
+			break;
+	}
+	return i;
+}
+
+static int skip_whitespace(const char *file, unsigned long len)
+{
+	unsigned long i;
+
+	for (i = 0; i < len; i++) {
+		if (file[i] != ' ' && file[i] != '\t')
+			break;
+	}
+	return i;
+}
+
+#define strneq(str, literal) (strncmp((str), (literal), strlen(literal)) == 0)
+
+/* Just in case it does a (local) include. */
+static int parse_cpp_line(const char *file, unsigned long len,
+			  const char *base, struct md4_ctx *md)
+{
+	unsigned long i = 0;
+
+	add_char(file[i++], md);
+	i += skip_whitespace(file+i, len - i);
+	if (i + strlen("include") >= len)
+		return i;
+	if (!strneq(file + i, "include"))
+		return i;
+	md4_update(md, (unsigned char *)"include", strlen("include"));	
+	i += strlen("include");
+	i += skip_whitespace(file+i, len - i);
+	if (i >= len)
+		return i;
+	if (file[i] != '"')
+		return i-1;
+	include_file(file+i+1, len - i - 1, base, md);
+	return i-1;
+}
+
+static int parse_file(const char *fname, struct md4_ctx *md)
+{
+	char *file;
+	unsigned long i, len;
+	int start_of_line = 1;
+
+	file = grab_file(fname, &len);
+	if (!file)
+		return 0;
+
+	for (i = 0; i < len; i++) {
+		/* Collapse and ignore \ and CR. */
+		if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') {
+			i += 2;
+			continue;
+		}
+
+		if (file[i] == '\n')
+			start_of_line = 1;
+
+		/* Ignore whitespace */
+		if (isspace(file[i]))
+			continue;
+
+		/* Handle strings as whole units */
+		if (file[i] == '"') {
+			i += parse_string(file+i, len - i, md);
+			start_of_line = 0;
+			continue;
+		}
+
+		/* Comments: ignore */
+		if (file[i] == '/' && file[i+1] == '*') {
+			i += parse_comment(file+i, len - i);
+			start_of_line = 0;
+			continue;
+		}
+
+		/* Potential #include files */
+		if (file[i] == '#' && start_of_line) {
+			i += parse_cpp_line(file+i, len - i, fname, md);
+			start_of_line = 0;
+			continue;
+		}
+
+		start_of_line = 0;
+		add_char(file[i], md);
+	}
+	return 1;
+}
+
+static void get_version(const char *modname, char sum[])
+{
+	void *file;
+	unsigned long len;
+	struct md4_ctx md;
+	char *sources, *end, *fname;
+	const char *basename;
+	char filelist[sizeof(".tmp_versions/%s.mod") + strlen(modname)];
+
+	/* Source files for module are in .tmp_versions/modname.mod,
+	   after the first line. */
+	if (strrchr(modname, '/'))
+		basename = strrchr(modname, '/') + 1;
+	else
+		basename = modname;
+	sprintf(filelist, ".tmp_versions/%s", basename);
+	/* Truncate .o, add .mod */
+	strcpy(filelist + strlen(filelist)-2, ".mod");
+
+	file = grab_file(filelist, &len);
+	if (!file) {
+		fprintf(stderr, "Warning: could not find versions for %s\n",
+			filelist);
+		return;
+	}
+
+	sources = strchr(file, '\n');
+	if (!sources) {
+		fprintf(stderr, "Warning: malformed versions file for %s\n",
+			modname);
+		goto release;
+	}
+
+	sources++;
+	end = strchr(sources, '\n');
+	if (!end) {
+		fprintf(stderr, "Warning: bad ending versions file for %s\n",
+			modname);
+		goto release;
+	}
+	*end = '\0';
+
+	md4_init(&md);
+	for (fname = strtok(sources, " "); fname; fname = strtok(NULL, " "))
+		if (!parse_file(fname, &md)) {
+			fprintf(stderr, "Warning: could not open %s: %s\n",
+				fname, strerror(errno));
+			goto release;
+		}
+
+	/* sum is of form \0<padding>. */ 
+	md4_final_ascii(&md, sum, 1 + strlen(sum+1));
+release:
+	release_file(file, len);
+}
+
+static void write_version(const char *filename, const char *sum,
+			  unsigned long offset)
+{
+	int fd;
+
+	fd = open(filename, O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "Warning: changing sum in %s failed: %s\n",
+			filename, strerror(errno));
+		return;
+	}
+
+	if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+		fprintf(stderr, "Warning: changing sum in %s:%lu failed: %s\n",
+			filename, offset, strerror(errno));
+		goto out;
+	}
+
+	if (write(fd, sum, strlen(sum)+1) != strlen(sum)+1) {
+		fprintf(stderr, "Warning: writing sum in %s failed: %s\n",
+			filename, strerror(errno));
+		goto out;
+	}
+out:
+	close(fd);
+}
+
+void strip_rcs_crap(char *version)
+{
+	unsigned int len, full_len;
+
+	if (strncmp(version, "$Revision", strlen("$Revision")) != 0)
+		return;
+
+	/* Space for version string follows. */
+	full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2;
+
+	/* Move string to start with version number: prefix will be
+	 * $Revision$ or $Revision: */
+	len = strlen("$Revision");
+	if (version[len] == ':' || version[len] == '$')
+		len++;
+	while (isspace(version[len])) 
+		len++;
+	memmove(version, version+len, full_len-len);
+	full_len -= len;
+
+	/* Preserve up to next whitespace. */
+	len = 0;
+	while (version[len] && !isspace(version[len]))
+		len++;
+	memmove(version + len, version + strlen(version),
+		full_len - strlen(version));
+}
+
+/* If the modinfo contains a "version" value, then set this. */
+void maybe_frob_version(const char *modfilename,
+			void *modinfo,
+			unsigned long modinfo_len,
+			unsigned long modinfo_offset)
+{
+	char *version, *csum;
+
+	version = get_modinfo(modinfo, modinfo_len, "version");
+	if (!version)
+		return;
+
+	/* RCS $Revision gets stripped out. */
+	strip_rcs_crap(version);
+
+	/* Check against double sumversion */
+	if (strchr(version, ' '))
+		return;
+
+	/* Version contains embedded NUL: second half has space for checksum */
+	csum = version + strlen(version);
+	*(csum++) = ' ';
+	get_version(modfilename, csum);
+	write_version(modfilename, version,
+		      modinfo_offset + (version - (char *)modinfo));
+}
--
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-01-20  0:57 ` Question on MODULE_VERSION macro Rusty Russell
@ 2004-01-20  1:17   ` Greg KH
  2004-01-20  7:47     ` Rusty Russell
  2004-03-10 20:49     ` Brian King
  0 siblings, 2 replies; 14+ messages in thread
From: Greg KH @ 2004-01-20  1:17 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Mike Anderson, linux-kernel, Brian King, Christoph Hellwig, kai,
	sam, akpm

On Tue, Jan 20, 2004 at 11:57:38AM +1100, Rusty Russell wrote:
> In message <20040119214233.GF967@beaverton.ibm.com> you write:
> > Rusty,
> > 	Christoph mentioned that a MODULE_VERSION macro may be pending.
> 
> Hey, thanks Christoph for the reminder.  I stopped when we were
> frozen.
> 
> This still seems to apply.  Do people think this is huge overkill, or
> a work of obvious beauty and genius?

Looks sane.  I'm guessing that modinfo can show this?

> Doesn't put things in sysfs, but Greg was working on that for module
> parameters... Greg?

Oh yeah, I'll dig out that patch later this week.  An older version has
been sitting in my bk tree forever, need to update it with the last
changes you sent me.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-01-20  1:17   ` Greg KH
@ 2004-01-20  7:47     ` Rusty Russell
  2004-02-20 21:44       ` Brian King
  2004-03-10 20:49     ` Brian King
  1 sibling, 1 reply; 14+ messages in thread
From: Rusty Russell @ 2004-01-20  7:47 UTC (permalink / raw)
  To: Greg KH
  Cc: Mike Anderson, linux-kernel, Brian King, Christoph Hellwig, kai,
	sam, akpm

In message <20040120011734.GB6309@kroah.com> you write:
> On Tue, Jan 20, 2004 at 11:57:38AM +1100, Rusty Russell wrote:
> > In message <20040119214233.GF967@beaverton.ibm.com> you write:
> > > Rusty,
> > > 	Christoph mentioned that a MODULE_VERSION macro may be pending.
> > 
> > Hey, thanks Christoph for the reminder.  I stopped when we were
> > frozen.
> > 
> > This still seems to apply.  Do people think this is huge overkill, or
> > a work of obvious beauty and genius?
> 
> Looks sane.  I'm guessing that modinfo can show this?

Yes.  Looks like so:

--- working-2.6.1-bk5-module_version/arch/i386/kernel/apm.c.~1~	2003-09-29 10:25:15.000000000 +1000
+++ working-2.6.1-bk5-module_version/arch/i386/kernel/apm.c	2004-01-20 18:22:46.000000000 +1100
@@ -2081,3 +2081,4 @@
 MODULE_PARM_DESC(smp,
 	"Set this to enable APM use on an SMP platform. Use with caution on older systems");
 MODULE_ALIAS_MISCDEV(APM_MINOR_DEV);
+MODULE_VERSION("1.16ac-rustytest");

$ modinfo arch/i386/kernel/apm.ko
author:         Stephen Rothwell
description:    Advanced Power Management
license:        GPL
....
version:        1.16ac-rustytest B13E9451C4CA3B89577DEFF
vermagic:       2.6.1-bk5 SMP PENTIUMII gcc-3.2
depends:        

Thanks,
Rusty.
--
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-01-20  7:47     ` Rusty Russell
@ 2004-02-20 21:44       ` Brian King
  2004-02-21  1:07         ` Rusty Russell
  0 siblings, 1 reply; 14+ messages in thread
From: Brian King @ 2004-02-20 21:44 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Greg KH, Mike Anderson, linux-kernel, Christoph Hellwig, kai, sam, akpm

Any update on the MODULE_VERSION macro getting into mainline?

-Brian


Rusty Russell wrote:
> In message <20040120011734.GB6309@kroah.com> you write:
> 
>>On Tue, Jan 20, 2004 at 11:57:38AM +1100, Rusty Russell wrote:
>>
>>>In message <20040119214233.GF967@beaverton.ibm.com> you write:
>>>
>>>>Rusty,
>>>>	Christoph mentioned that a MODULE_VERSION macro may be pending.
>>>
>>>Hey, thanks Christoph for the reminder.  I stopped when we were
>>>frozen.
>>>
>>>This still seems to apply.  Do people think this is huge overkill, or
>>>a work of obvious beauty and genius?
>>
>>Looks sane.  I'm guessing that modinfo can show this?
> 
> 
> Yes.  Looks like so:
> 
> --- working-2.6.1-bk5-module_version/arch/i386/kernel/apm.c.~1~	2003-09-29 10:25:15.000000000 +1000
> +++ working-2.6.1-bk5-module_version/arch/i386/kernel/apm.c	2004-01-20 18:22:46.000000000 +1100
> @@ -2081,3 +2081,4 @@
>  MODULE_PARM_DESC(smp,
>  	"Set this to enable APM use on an SMP platform. Use with caution on older systems");
>  MODULE_ALIAS_MISCDEV(APM_MINOR_DEV);
> +MODULE_VERSION("1.16ac-rustytest");
> 
> $ modinfo arch/i386/kernel/apm.ko
> author:         Stephen Rothwell
> description:    Advanced Power Management
> license:        GPL
> ....
> version:        1.16ac-rustytest B13E9451C4CA3B89577DEFF
> vermagic:       2.6.1-bk5 SMP PENTIUMII gcc-3.2
> depends:        
> 
> Thanks,
> Rusty.
> --
>   Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
> 


-- 
Brian King
eServer Storage I/O
IBM Linux Technology Center


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-02-20 21:44       ` Brian King
@ 2004-02-21  1:07         ` Rusty Russell
  2004-02-22 23:23           ` Sam Ravnborg
  0 siblings, 1 reply; 14+ messages in thread
From: Rusty Russell @ 2004-02-21  1:07 UTC (permalink / raw)
  To: Brian King; +Cc: sam, akpm, linux-kernel

In message <40367FC8.2020802@us.ibm.com> you write:
> Any update on the MODULE_VERSION macro getting into mainline?

Sam need to ack the build system changes.

Sam?

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

Cheers!
Rusty.
--
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

Name: Add a MODULE_VERSION macro
Author: Rusty Russell
Status: Tested on 2.6.0-test5

D: At the kernel summit, various people asked for a MODULE_VERSION
D: macro to store module strings (for later access through sysfs).
D: A simple md4 is needed to identify changes in modules which,
D: inevitably, do not update the version.  It skips whitespace and
D: comments, and includes #includes which are in the same dir.
D: 
D: The module versions should be set according to this definition,
D: based on the RPM one, or CVS Revision tags.  Violators will be shot.
D: 
D:  [<epoch>`:']<version>[`-'<extraversion>]
D:  <epoch>: A (small) unsigned integer which allows you to start versions
D:           anew. If not mentioned, it's zero.  eg. "2:1.0" is after
D:	     "1:2.0".
D:  <version>: The <version> may contain only alphanumerics.
D:  <extraversion>: Like <version>, but inserted for local
D:           customizations, eg "rh3" or "rusty1".
D: 
D: Comparison of two versions (assuming same epoch):
D: 
D: Split each into all-digit and all-alphabetical parts.  Compare each
D: one one at a time: digit parts numerically, alphabetical in ASCII
D: order.  So 0.10 comes after 0.9.

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/include/linux/module.h .25664-linux-2.6.0-test6-bk6.updated/include/linux/module.h
--- .25664-linux-2.6.0-test6-bk6/include/linux/module.h	2003-09-22 10:26:13.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/include/linux/module.h	2003-10-05 16:45:10.000000000 +1000
@@ -123,6 +123,24 @@ extern const struct gtype##_id __mod_##g
 #define MODULE_DEVICE_TABLE(type,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 */
 const struct exception_table_entry *search_exception_tables(unsigned long add);
 
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/scripts/Makefile .25664-linux-2.6.0-test6-bk6.updated/scripts/Makefile
--- .25664-linux-2.6.0-test6-bk6/scripts/Makefile	2003-09-29 10:26:16.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/scripts/Makefile	2003-10-05 16:45:10.000000000 +1000
@@ -12,7 +12,7 @@ host-progs	:= fixdep split-include conma
 		   mk_elfconfig pnmtologo bin2c
 always		:= $(host-progs) empty.o
 
-modpost-objs	:= modpost.o file2alias.o
+modpost-objs	:= modpost.o file2alias.o sumversion.o
 
 subdir-$(CONFIG_MODVERSIONS)	+= genksyms
 
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/scripts/Makefile.build .25664-linux-2.6.0-test6-bk6.updated/scripts/Makefile.build
--- .25664-linux-2.6.0-test6-bk6/scripts/Makefile.build	2003-09-29 10:26:16.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/scripts/Makefile.build	2003-10-05 16:45:10.000000000 +1000
@@ -64,8 +64,6 @@ endif
 
 # 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)) \
 	 $(if $(KBUILD_MODULES),$(obj-m)) \
 	 $(subdir-ym) $(always)
@@ -178,7 +176,7 @@ endef
 
 $(single-used-m): %.o: %.c FORCE
 	$(call if_changed_rule,cc_o_c)
-	$(touch-module)
+	@{ echo $(@:.o=.ko); echo $<; } > $(MODVERDIR)/$(@F:.o=.mod)
 
 quiet_cmd_cc_lst_c = MKLST   $@
       cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
@@ -273,7 +271,7 @@ $(multi-used-y) : %.o: $(multi-objs-y) F
 
 $(multi-used-m) : %.o: $(multi-objs-m) FORCE
 	$(call if_changed,link_multi-m)
-	$(touch-module)
+	@{ echo $(@:.o=.ko); echo $(link_multi_deps:.o=.c); } > $(MODVERDIR)/$(@F:.o=.mod)
 
 targets += $(multi-used-y) $(multi-used-m)
 
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/scripts/Makefile.modpost .25664-linux-2.6.0-test6-bk6.updated/scripts/Makefile.modpost
--- .25664-linux-2.6.0-test6-bk6/scripts/Makefile.modpost	2003-09-29 10:26:16.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/scripts/Makefile.modpost	2003-10-05 16:45:10.000000000 +1000
@@ -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)))
 
 ifneq ($(filter-out $(modules),$(__modules)),)
+  $(warning Trouble: $(__modules) )
   $(warning *** Uh-oh, you have stale module entries. You messed with SUBDIRS,)
   $(warning     do not complain if something goes wrong.)
 endif
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/scripts/modpost.c .25664-linux-2.6.0-test6-bk6.updated/scripts/modpost.c
--- .25664-linux-2.6.0-test6-bk6/scripts/modpost.c	2003-09-29 10:26:16.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/scripts/modpost.c	2003-10-05 16:46:49.000000000 +1000
@@ -65,15 +65,15 @@ new_module(char *modname)
 	struct module *mod;
 	char *p;
 	
+	mod = NOFAIL(malloc(sizeof(*mod)));
+	memset(mod, 0, sizeof(*mod));
+	mod->name = NOFAIL(strdup(modname));
+
 	/* strip trailing .o */
-	p = strstr(modname, ".o");
+	p = strstr(mod->name, ".o");
 	if (p)
 		*p = 0;
 
-	mod = NOFAIL(malloc(sizeof(*mod)));
-	memset(mod, 0, sizeof(*mod));
-	mod->name = modname;
-
 	/* add to list */
 	mod->next = modules;
 	modules = mod;
@@ -182,26 +182,25 @@ grab_file(const char *filename, unsigned
 	int fd;
 
 	fd = open(filename, O_RDONLY);
-	if (fd < 0) {
-		perror(filename);
-		abort();
-	}
-	if (fstat(fd, &st) != 0) {
-		perror(filename);
-		abort();
-	}
+	if (fstat(fd, &st) != 0)
+		return NULL;
 
 	*size = st.st_size;
 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-	if (map == MAP_FAILED) {
-		perror(filename);
-		abort();
-	}
 	close(fd);
+
+	if (map == MAP_FAILED)
+		return NULL;
 	return map;
 }
 
 void
+release_file(void *file, unsigned long size)
+{
+	munmap(file, size);
+}
+
+void
 parse_elf(struct elf_info *info, const char *filename)
 {
 	unsigned int i;
@@ -210,6 +209,10 @@ parse_elf(struct elf_info *info, const c
 	Elf_Sym  *sym;
 
 	hdr = grab_file(filename, &info->size);
+	if (!hdr) {
+		perror(filename);
+		abort();
+	}
 	info->hdr = hdr;
 	if (info->size < sizeof(*hdr))
 		goto truncated;
@@ -227,11 +230,19 @@ parse_elf(struct elf_info *info, const c
 		sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
 		sechdrs[i].sh_size   = TO_NATIVE(sechdrs[i].sh_size);
 		sechdrs[i].sh_link   = TO_NATIVE(sechdrs[i].sh_link);
+		sechdrs[i].sh_name   = TO_NATIVE(sechdrs[i].sh_name);
 	}
 	/* Find symbol table. */
 	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)
 			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)
 			continue;
 
@@ -262,7 +273,7 @@ parse_elf(struct elf_info *info, const c
 void
 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_"
@@ -348,6 +359,8 @@ read_symbols(char *modname)
 		handle_modversions(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);
 
 	/* Our trick to get versioning for struct_module - it's
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/scripts/modpost.h .25664-linux-2.6.0-test6-bk6.updated/scripts/modpost.h
--- .25664-linux-2.6.0-test6-bk6/scripts/modpost.h	2003-09-22 10:06:44.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/scripts/modpost.h	2003-10-05 16:45:10.000000000 +1000
@@ -80,9 +80,19 @@ struct elf_info {
 	Elf_Sym      *symtab_start;
 	Elf_Sym      *symtab_stop;
 	const char   *strtab;
+	char	     *modinfo;
+	unsigned int modinfo_len;
 };
 
 void handle_moddevtable(struct module *mod, struct elf_info *info,
 			Elf_Sym *sym, const char *symname);
 
 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);
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .25664-linux-2.6.0-test6-bk6/scripts/sumversion.c .25664-linux-2.6.0-test6-bk6.updated/scripts/sumversion.c
--- .25664-linux-2.6.0-test6-bk6/scripts/sumversion.c	1970-01-01 10:00:00.000000000 +1000
+++ .25664-linux-2.6.0-test6-bk6.updated/scripts/sumversion.c	2003-10-05 16:45:10.000000000 +1000
@@ -0,0 +1,540 @@
+#include <netinet/in.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include "modpost.h"
+
+/* Parse tag=value strings from .modinfo section */
+static char *next_string(char *string, unsigned long *secsize)
+{
+	/* Skip non-zero chars */
+	while (string[0]) {
+		string++;
+		if ((*secsize)-- <= 1)
+			return NULL;
+	}
+
+	/* Skip any zero padding. */
+	while (!string[0]) {
+		string++;
+		if ((*secsize)-- <= 1)
+			return NULL;
+	}
+	return string;
+}
+
+static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
+			 const char *tag)
+{
+	char *p;
+	unsigned int taglen = strlen(tag);
+	unsigned long size = modinfo_len;
+
+	for (p = modinfo; p; p = next_string(p, &size)) {
+		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
+			return p + taglen + 1;
+	}
+	return NULL;
+}
+
+/* 
+ * Stolen form Cryptographic API.
+ *
+ * MD4 Message Digest Algorithm (RFC1320).
+ *
+ * Implementation derived from Andrew Tridgell and Steve French's
+ * CIFS MD4 implementation, and the cryptoapi implementation
+ * originally based on the public domain implementation written
+ * by Colin Plumb in 1993.
+ *
+ * Copyright (c) Andrew Tridgell 1997-1998.
+ * Modified by Steve French (sfrench@us.ibm.com) 2002
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#define MD4_DIGEST_SIZE		16
+#define MD4_HMAC_BLOCK_SIZE	64
+#define MD4_BLOCK_WORDS		16
+#define MD4_HASH_WORDS		4
+
+struct md4_ctx {
+	uint32_t hash[MD4_HASH_WORDS];
+	uint32_t block[MD4_BLOCK_WORDS];
+	uint64_t byte_count;
+};
+
+static inline uint32_t lshift(uint32_t x, unsigned int s)
+{
+	x &= 0xFFFFFFFF;
+	return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
+{
+	return (x & y) | ((~x) & z);
+}
+
+static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
+{
+	return (x & y) | (x & z) | (y & z);
+}
+
+static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
+{
+	return x ^ y ^ z;
+}
+                        
+#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
+#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
+#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
+
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
+{
+	while (words--) {
+		*buf = ntohl(*buf);
+		buf++;
+	}
+}
+
+static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
+{
+	while (words--) {
+		*buf = htonl(*buf);
+		buf++;
+	}
+}
+
+static void md4_transform(uint32_t *hash, uint32_t const *in)
+{
+	uint32_t a, b, c, d;
+
+	a = hash[0];
+	b = hash[1];
+	c = hash[2];
+	d = hash[3];
+
+	ROUND1(a, b, c, d, in[0], 3);
+	ROUND1(d, a, b, c, in[1], 7);
+	ROUND1(c, d, a, b, in[2], 11);
+	ROUND1(b, c, d, a, in[3], 19);
+	ROUND1(a, b, c, d, in[4], 3);
+	ROUND1(d, a, b, c, in[5], 7);
+	ROUND1(c, d, a, b, in[6], 11);
+	ROUND1(b, c, d, a, in[7], 19);
+	ROUND1(a, b, c, d, in[8], 3);
+	ROUND1(d, a, b, c, in[9], 7);
+	ROUND1(c, d, a, b, in[10], 11);
+	ROUND1(b, c, d, a, in[11], 19);
+	ROUND1(a, b, c, d, in[12], 3);
+	ROUND1(d, a, b, c, in[13], 7);
+	ROUND1(c, d, a, b, in[14], 11);
+	ROUND1(b, c, d, a, in[15], 19);
+
+	ROUND2(a, b, c, d,in[ 0], 3);
+	ROUND2(d, a, b, c, in[4], 5);
+	ROUND2(c, d, a, b, in[8], 9);
+	ROUND2(b, c, d, a, in[12], 13);
+	ROUND2(a, b, c, d, in[1], 3);
+	ROUND2(d, a, b, c, in[5], 5);
+	ROUND2(c, d, a, b, in[9], 9);
+	ROUND2(b, c, d, a, in[13], 13);
+	ROUND2(a, b, c, d, in[2], 3);
+	ROUND2(d, a, b, c, in[6], 5);
+	ROUND2(c, d, a, b, in[10], 9);
+	ROUND2(b, c, d, a, in[14], 13);
+	ROUND2(a, b, c, d, in[3], 3);
+	ROUND2(d, a, b, c, in[7], 5);
+	ROUND2(c, d, a, b, in[11], 9);
+	ROUND2(b, c, d, a, in[15], 13);
+
+	ROUND3(a, b, c, d,in[ 0], 3);
+	ROUND3(d, a, b, c, in[8], 9);
+	ROUND3(c, d, a, b, in[4], 11);
+	ROUND3(b, c, d, a, in[12], 15);
+	ROUND3(a, b, c, d, in[2], 3);
+	ROUND3(d, a, b, c, in[10], 9);
+	ROUND3(c, d, a, b, in[6], 11);
+	ROUND3(b, c, d, a, in[14], 15);
+	ROUND3(a, b, c, d, in[1], 3);
+	ROUND3(d, a, b, c, in[9], 9);
+	ROUND3(c, d, a, b, in[5], 11);
+	ROUND3(b, c, d, a, in[13], 15);
+	ROUND3(a, b, c, d, in[3], 3);
+	ROUND3(d, a, b, c, in[11], 9);
+	ROUND3(c, d, a, b, in[7], 11);
+	ROUND3(b, c, d, a, in[15], 15);
+
+	hash[0] += a;
+	hash[1] += b;
+	hash[2] += c;
+	hash[3] += d;
+}
+
+static inline void md4_transform_helper(struct md4_ctx *ctx)
+{
+	le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
+	md4_transform(ctx->hash, ctx->block);
+}
+
+static void md4_init(struct md4_ctx *mctx)
+{
+	mctx->hash[0] = 0x67452301;
+	mctx->hash[1] = 0xefcdab89;
+	mctx->hash[2] = 0x98badcfe;
+	mctx->hash[3] = 0x10325476;
+	mctx->byte_count = 0;
+}
+
+static void md4_update(struct md4_ctx *mctx,
+		       const unsigned char *data, unsigned int len)
+{
+	const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+	mctx->byte_count += len;
+
+	if (avail > len) {
+		memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+		       data, len);
+		return;
+	}
+
+	memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+	       data, avail);
+
+	md4_transform_helper(mctx);
+	data += avail;
+	len -= avail;
+
+	while (len >= sizeof(mctx->block)) {
+		memcpy(mctx->block, data, sizeof(mctx->block));
+		md4_transform_helper(mctx);
+		data += sizeof(mctx->block);
+		len -= sizeof(mctx->block);
+	}
+
+	memcpy(mctx->block, data, len);
+}
+
+static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
+{
+	const unsigned int offset = mctx->byte_count & 0x3f;
+	char *p = (char *)mctx->block + offset;
+	int padding = 56 - (offset + 1);
+
+	*p++ = 0x80;
+	if (padding < 0) {
+		memset(p, 0x00, padding + sizeof (uint64_t));
+		md4_transform_helper(mctx);
+		p = (char *)mctx->block;
+		padding = 56;
+	}
+
+	memset(p, 0, padding);
+	mctx->block[14] = mctx->byte_count << 3;
+	mctx->block[15] = mctx->byte_count >> 29;
+	le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
+	                  sizeof(uint64_t)) / sizeof(uint32_t));
+	md4_transform(mctx->hash, mctx->block);
+	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
+	
+	snprintf(out, len, "%08X%08X%08X%08X",
+		 mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
+}
+
+static int parse_file(const char *fname, struct md4_ctx *md);
+
+/* Local include files, if in current dir. */
+static void include_file(const char *line, int maxlen, const char *base,
+			 struct md4_ctx *md)
+{
+	unsigned int i;
+
+	for (i = 0; line[i] != '"'; i++) {
+		if (i == maxlen) {
+			fprintf(stderr,
+				"sumversion: badly formed #include in %s\n",
+				base);
+			return;
+		}
+	}
+
+	{
+		const char *dirend;
+		char fname[i + strlen(base)];
+
+		dirend = strrchr(base, '/');
+		if (!dirend)
+			dirend = base;
+		else
+			dirend++;
+		memcpy(fname, base, dirend - base);
+		memcpy(fname + (dirend - base), line, i);
+		fname[(dirend - base) + i] = '\0';
+
+		parse_file(fname, md);
+	}
+}
+
+static inline void add_char(unsigned char c, struct md4_ctx *md)
+{
+	md4_update(md, &c, 1);
+}
+
+static int parse_string(const char *file, unsigned long len,
+			struct md4_ctx *md)
+{
+	unsigned long i;
+
+	add_char(file[0], md);
+	for (i = 1; i < len; i++) {
+		add_char(file[i], md);
+		if (file[i] == '"' && file[i-1] != '\\')
+			break;
+	}
+	return i;
+}
+
+static int parse_comment(const char *file, unsigned long len)
+{
+	unsigned long i;
+
+	for (i = 2; i < len; i++) {
+		if (file[i-1] == '*' && file[i] == '/')
+			break;
+	}
+	return i;
+}
+
+static int skip_whitespace(const char *file, unsigned long len)
+{
+	unsigned long i;
+
+	for (i = 0; i < len; i++) {
+		if (file[i] != ' ' && file[i] != '\t')
+			break;
+	}
+	return i;
+}
+
+#define strneq(str, literal) (strncmp((str), (literal), strlen(literal)) == 0)
+
+/* Just in case it does a (local) include. */
+static int parse_cpp_line(const char *file, unsigned long len,
+			  const char *base, struct md4_ctx *md)
+{
+	unsigned long i = 0;
+
+	add_char(file[i++], md);
+	i += skip_whitespace(file+i, len - i);
+	if (i + strlen("include") >= len)
+		return i;
+	if (!strneq(file + i, "include"))
+		return i;
+	md4_update(md, (unsigned char *)"include", strlen("include"));	
+	i += strlen("include");
+	i += skip_whitespace(file+i, len - i);
+	if (i >= len)
+		return i;
+	if (file[i] != '"')
+		return i-1;
+	include_file(file+i+1, len - i - 1, base, md);
+	return i-1;
+}
+
+static int parse_file(const char *fname, struct md4_ctx *md)
+{
+	char *file;
+	unsigned long i, len;
+	int start_of_line = 1;
+
+	file = grab_file(fname, &len);
+	if (!file)
+		return 0;
+
+	for (i = 0; i < len; i++) {
+		/* Collapse and ignore \ and CR. */
+		if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') {
+			i += 2;
+			continue;
+		}
+
+		if (file[i] == '\n')
+			start_of_line = 1;
+
+		/* Ignore whitespace */
+		if (isspace(file[i]))
+			continue;
+
+		/* Handle strings as whole units */
+		if (file[i] == '"') {
+			i += parse_string(file+i, len - i, md);
+			start_of_line = 0;
+			continue;
+		}
+
+		/* Comments: ignore */
+		if (file[i] == '/' && file[i+1] == '*') {
+			i += parse_comment(file+i, len - i);
+			start_of_line = 0;
+			continue;
+		}
+
+		/* Potential #include files */
+		if (file[i] == '#' && start_of_line) {
+			i += parse_cpp_line(file+i, len - i, fname, md);
+			start_of_line = 0;
+			continue;
+		}
+
+		start_of_line = 0;
+		add_char(file[i], md);
+	}
+	return 1;
+}
+
+static void get_version(const char *modname, char sum[])
+{
+	void *file;
+	unsigned long len;
+	struct md4_ctx md;
+	char *sources, *end, *fname;
+	const char *basename;
+	char filelist[sizeof(".tmp_versions/%s.mod") + strlen(modname)];
+
+	/* Source files for module are in .tmp_versions/modname.mod,
+	   after the first line. */
+	if (strrchr(modname, '/'))
+		basename = strrchr(modname, '/') + 1;
+	else
+		basename = modname;
+	sprintf(filelist, ".tmp_versions/%s", basename);
+	/* Truncate .o, add .mod */
+	strcpy(filelist + strlen(filelist)-2, ".mod");
+
+	file = grab_file(filelist, &len);
+	if (!file) {
+		fprintf(stderr, "Warning: could not find versions for %s\n",
+			filelist);
+		return;
+	}
+
+	sources = strchr(file, '\n');
+	if (!sources) {
+		fprintf(stderr, "Warning: malformed versions file for %s\n",
+			modname);
+		goto release;
+	}
+
+	sources++;
+	end = strchr(sources, '\n');
+	if (!end) {
+		fprintf(stderr, "Warning: bad ending versions file for %s\n",
+			modname);
+		goto release;
+	}
+	*end = '\0';
+
+	md4_init(&md);
+	for (fname = strtok(sources, " "); fname; fname = strtok(NULL, " "))
+		if (!parse_file(fname, &md)) {
+			fprintf(stderr, "Warning: could not open %s: %s\n",
+				fname, strerror(errno));
+			goto release;
+		}
+
+	/* sum is of form \0<padding>. */ 
+	md4_final_ascii(&md, sum, 1 + strlen(sum+1));
+release:
+	release_file(file, len);
+}
+
+static void write_version(const char *filename, const char *sum,
+			  unsigned long offset)
+{
+	int fd;
+
+	fd = open(filename, O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "Warning: changing sum in %s failed: %s\n",
+			filename, strerror(errno));
+		return;
+	}
+
+	if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+		fprintf(stderr, "Warning: changing sum in %s:%lu failed: %s\n",
+			filename, offset, strerror(errno));
+		goto out;
+	}
+
+	if (write(fd, sum, strlen(sum)+1) != strlen(sum)+1) {
+		fprintf(stderr, "Warning: writing sum in %s failed: %s\n",
+			filename, strerror(errno));
+		goto out;
+	}
+out:
+	close(fd);
+}
+
+void strip_rcs_crap(char *version)
+{
+	unsigned int len, full_len;
+
+	if (strncmp(version, "$Revision", strlen("$Revision")) != 0)
+		return;
+
+	/* Space for version string follows. */
+	full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2;
+
+	/* Move string to start with version number: prefix will be
+	 * $Revision$ or $Revision: */
+	len = strlen("$Revision");
+	if (version[len] == ':' || version[len] == '$')
+		len++;
+	while (isspace(version[len])) 
+		len++;
+	memmove(version, version+len, full_len-len);
+	full_len -= len;
+
+	/* Preserve up to next whitespace. */
+	len = 0;
+	while (version[len] && !isspace(version[len]))
+		len++;
+	memmove(version + len, version + strlen(version),
+		full_len - strlen(version));
+}
+
+/* If the modinfo contains a "version" value, then set this. */
+void maybe_frob_version(const char *modfilename,
+			void *modinfo,
+			unsigned long modinfo_len,
+			unsigned long modinfo_offset)
+{
+	char *version, *csum;
+
+	version = get_modinfo(modinfo, modinfo_len, "version");
+	if (!version)
+		return;
+
+	/* RCS $Revision gets stripped out. */
+	strip_rcs_crap(version);
+
+	/* Check against double sumversion */
+	if (strchr(version, ' '))
+		return;
+
+	/* Version contains embedded NUL: second half has space for checksum */
+	csum = version + strlen(version);
+	*(csum++) = ' ';
+	get_version(modfilename, csum);
+	write_version(modfilename, version,
+		      modinfo_offset + (version - (char *)modinfo));
+}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-02-21  1:07         ` Rusty Russell
@ 2004-02-22 23:23           ` Sam Ravnborg
  2004-02-23  3:51             ` Rusty Russell
  0 siblings, 1 reply; 14+ messages in thread
From: Sam Ravnborg @ 2004-02-22 23:23 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Brian King, sam, akpm, linux-kernel

> > Any update on the MODULE_VERSION macro getting into mainline?
> 
> Sam need to ack the build system changes.

I have taken a look at it now.

As you mention yourself this assume all input files for a module
is .c files. Which is almost always the case.
But I do not like the fact that we warn in cases where .s files is
actually used.

Current implementation will also fail when using O= syntax.

The more correct approach is to list the .o files in the
.mod file. Then in sumversion find the corresponding .file.o.cmd, and parse
up the name of the corresponding source file (listed as the first filename
in the deps_ assignment, and pass this filename to grab_file.

Example .file.o.cmd file:
sam@mars:~/bk/v2.6> head -10 ~/b/drivers/scsi/aic7xxx/.aic7xxx_osm.o.cmd
cmd_drivers/scsi/aic7xxx/aic7xxx_osm.o := gcc -Wp,-MD,drivers/scsi/aic7xxx/.aic7xxx_osm.o.d -nostdinc -iwithprefix include -D__KERNEL__ -Iinclude -Iinclude2 -I/home/sam/bk/v2.6/include -I/home/sam/bk/v2.6/drivers/scsi/aic7xxx -Idrivers/scsi/aic7xxx -D__KERNEL__ -I/home/sam/bk/v2.6/include -Iinclude -I/home/sam/bk/v2.6/include2 -Iinclude2  -I/home/sam/bk/v2.6/include -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -pipe -mpreferred-stack-boundary=2 -march=i686 -I/home/sam/bk/v2.6/include/asm-i386/mach-default -Iinclude/asm-i386/mach-default -O2 -fomit-frame-pointer -I/home/sam/bk/v2.6/drivers/scsi -Idrivers/scsi -DMODULE -DKBUILD_BASENAME=aic7xxx_osm -DKBUILD_MODNAME=aic7xxx -c -o drivers/scsi/aic7xxx/aic7xxx_osm.o /home/sam/bk/v2.6/drivers/scsi/aic7xxx/aic7xxx_osm.c

deps_drivers/scsi/aic7xxx/aic7xxx_osm.o := \
  /home/sam/bk/v2.6/drivers/scsi/aic7xxx/aic7xxx_osm.c \
    $(wildcard include/config/aic7xxx/reset/delay/ms.h) \
    $(wildcard include/config/aic7xxx/proc/stats.h) \


Here the source file is listed with absolute path.
It must be as simple as searching through the file for a line starting with deps_,
and then read the following line.

The .mod file will specify the path to the .file.o.cmd file, since this
is an output file, there is no need to use $(srctree).

I hope I made the approach clear enough?

	Sam


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-02-22 23:23           ` Sam Ravnborg
@ 2004-02-23  3:51             ` Rusty Russell
  2004-02-23 21:17               ` Sam Ravnborg
  0 siblings, 1 reply; 14+ messages in thread
From: Rusty Russell @ 2004-02-23  3:51 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: Brian King, akpm, linux-kernel

In message <20040222232317.GA20083@mars.ravnborg.org> you write:
> The more correct approach is to list the .o files in the
> .mod file. Then in sumversion find the corresponding .file.o.cmd, and parse
> up the name of the corresponding source file (listed as the first filename
> in the deps_ assignment, and pass this filename to grab_file.

OK, I've implemented that.  It doesn't complain about non-C files,
although the parsing might be sub-optimal.

See get_source_name() for new code.  I also put the explicit depend on
elfconfig.h in the Makefile.

Thanks!
Rusty.
--
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

Name: Add a MODULE_VERSION macro
Author: Rusty Russell
Status: Tested on 2.6.3-bk3

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.

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12325-linux-2.6.3-bk3/include/linux/module.h .12325-linux-2.6.3-bk3.updated/include/linux/module.h
--- .12325-linux-2.6.3-bk3/include/linux/module.h	2004-02-04 15:39:14.000000000 +1100
+++ .12325-linux-2.6.3-bk3.updated/include/linux/module.h	2004-02-23 14:39:38.000000000 +1100
@@ -127,6 +127,24 @@ extern const struct gtype##_id __mod_##g
 #define MODULE_DEVICE_TABLE(type,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 */
 const struct exception_table_entry *search_exception_tables(unsigned long add);
 
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12325-linux-2.6.3-bk3/scripts/Makefile .12325-linux-2.6.3-bk3.updated/scripts/Makefile
--- .12325-linux-2.6.3-bk3/scripts/Makefile	2003-09-29 10:26:16.000000000 +1000
+++ .12325-linux-2.6.3-bk3.updated/scripts/Makefile	2004-02-23 14:19:30.000000000 +1100
@@ -12,7 +12,7 @@ host-progs	:= fixdep split-include conma
 		   mk_elfconfig pnmtologo bin2c
 always		:= $(host-progs) empty.o
 
-modpost-objs	:= modpost.o file2alias.o
+modpost-objs	:= modpost.o file2alias.o sumversion.o
 
 subdir-$(CONFIG_MODVERSIONS)	+= genksyms
 
@@ -24,7 +24,7 @@ $(addprefix $(obj)/,$(filter-out fixdep,
 
 # 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   $@
       cmd_elfconfig = $(obj)/mk_elfconfig $(ARCH) < $< > $@
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12325-linux-2.6.3-bk3/scripts/Makefile.build .12325-linux-2.6.3-bk3.updated/scripts/Makefile.build
--- .12325-linux-2.6.3-bk3/scripts/Makefile.build	2003-10-09 18:03:05.000000000 +1000
+++ .12325-linux-2.6.3-bk3.updated/scripts/Makefile.build	2004-02-23 11:30:45.000000000 +1100
@@ -64,8 +64,6 @@ endif
 
 # 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)) \
 	 $(if $(KBUILD_MODULES),$(obj-m)) \
 	 $(subdir-ym) $(always)
@@ -178,7 +176,7 @@ endef
 
 $(single-used-m): %.o: %.c FORCE
 	$(call if_changed_rule,cc_o_c)
-	$(touch-module)
+	@{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
 
 quiet_cmd_cc_lst_c = MKLST   $@
       cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
@@ -273,7 +271,7 @@ $(multi-used-y) : %.o: $(multi-objs-y) F
 
 $(multi-used-m) : %.o: $(multi-objs-m) FORCE
 	$(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)
 
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12325-linux-2.6.3-bk3/scripts/Makefile.modpost .12325-linux-2.6.3-bk3.updated/scripts/Makefile.modpost
--- .12325-linux-2.6.3-bk3/scripts/Makefile.modpost	2003-09-29 10:26:16.000000000 +1000
+++ .12325-linux-2.6.3-bk3.updated/scripts/Makefile.modpost	2004-02-23 11:27:40.000000000 +1100
@@ -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)))
 
 ifneq ($(filter-out $(modules),$(__modules)),)
+  $(warning Trouble: $(__modules) )
   $(warning *** Uh-oh, you have stale module entries. You messed with SUBDIRS,)
   $(warning     do not complain if something goes wrong.)
 endif
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12325-linux-2.6.3-bk3/scripts/modpost.c .12325-linux-2.6.3-bk3.updated/scripts/modpost.c
--- .12325-linux-2.6.3-bk3/scripts/modpost.c	2004-02-18 23:54:38.000000000 +1100
+++ .12325-linux-2.6.3-bk3.updated/scripts/modpost.c	2004-02-23 11:27:40.000000000 +1100
@@ -65,15 +65,15 @@ new_module(char *modname)
 	struct module *mod;
 	char *p;
 	
+	mod = NOFAIL(malloc(sizeof(*mod)));
+	memset(mod, 0, sizeof(*mod));
+	mod->name = NOFAIL(strdup(modname));
+
 	/* strip trailing .o */
-	p = strstr(modname, ".o");
+	p = strstr(mod->name, ".o");
 	if (p)
 		*p = 0;
 
-	mod = NOFAIL(malloc(sizeof(*mod)));
-	memset(mod, 0, sizeof(*mod));
-	mod->name = modname;
-
 	/* add to list */
 	mod->next = modules;
 	modules = mod;
@@ -194,26 +194,25 @@ grab_file(const char *filename, unsigned
 	int fd;
 
 	fd = open(filename, O_RDONLY);
-	if (fd < 0) {
-		perror(filename);
-		abort();
-	}
-	if (fstat(fd, &st) != 0) {
-		perror(filename);
-		abort();
-	}
+	if (fstat(fd, &st) != 0)
+		return NULL;
 
 	*size = st.st_size;
 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-	if (map == MAP_FAILED) {
-		perror(filename);
-		abort();
-	}
 	close(fd);
+
+	if (map == MAP_FAILED)
+		return NULL;
 	return map;
 }
 
 void
+release_file(void *file, unsigned long size)
+{
+	munmap(file, size);
+}
+
+void
 parse_elf(struct elf_info *info, const char *filename)
 {
 	unsigned int i;
@@ -222,6 +221,10 @@ parse_elf(struct elf_info *info, const c
 	Elf_Sym  *sym;
 
 	hdr = grab_file(filename, &info->size);
+	if (!hdr) {
+		perror(filename);
+		abort();
+	}
 	info->hdr = hdr;
 	if (info->size < sizeof(*hdr))
 		goto truncated;
@@ -239,11 +242,19 @@ parse_elf(struct elf_info *info, const c
 		sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
 		sechdrs[i].sh_size   = TO_NATIVE(sechdrs[i].sh_size);
 		sechdrs[i].sh_link   = TO_NATIVE(sechdrs[i].sh_link);
+		sechdrs[i].sh_name   = TO_NATIVE(sechdrs[i].sh_name);
 	}
 	/* Find symbol table. */
 	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)
 			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)
 			continue;
 
@@ -274,7 +285,7 @@ parse_elf(struct elf_info *info, const c
 void
 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_"
@@ -372,6 +383,8 @@ read_symbols(char *modname)
 		handle_modversions(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);
 
 	/* Our trick to get versioning for struct_module - it's
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12325-linux-2.6.3-bk3/scripts/modpost.h .12325-linux-2.6.3-bk3.updated/scripts/modpost.h
--- .12325-linux-2.6.3-bk3/scripts/modpost.h	2003-09-22 10:06:44.000000000 +1000
+++ .12325-linux-2.6.3-bk3.updated/scripts/modpost.h	2004-02-23 11:27:40.000000000 +1100
@@ -80,9 +80,19 @@ struct elf_info {
 	Elf_Sym      *symtab_start;
 	Elf_Sym      *symtab_stop;
 	const char   *strtab;
+	char	     *modinfo;
+	unsigned int modinfo_len;
 };
 
 void handle_moddevtable(struct module *mod, struct elf_info *info,
 			Elf_Sym *sym, const char *symname);
 
 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);
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .12325-linux-2.6.3-bk3/scripts/sumversion.c .12325-linux-2.6.3-bk3.updated/scripts/sumversion.c
--- .12325-linux-2.6.3-bk3/scripts/sumversion.c	1970-01-01 10:00:00.000000000 +1000
+++ .12325-linux-2.6.3-bk3.updated/scripts/sumversion.c	2004-02-23 14:41:53.000000000 +1100
@@ -0,0 +1,599 @@
+#include <netinet/in.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include "modpost.h"
+
+/* Parse tag=value strings from .modinfo section */
+static char *next_string(char *string, unsigned long *secsize)
+{
+	/* Skip non-zero chars */
+	while (string[0]) {
+		string++;
+		if ((*secsize)-- <= 1)
+			return NULL;
+	}
+
+	/* Skip any zero padding. */
+	while (!string[0]) {
+		string++;
+		if ((*secsize)-- <= 1)
+			return NULL;
+	}
+	return string;
+}
+
+static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
+			 const char *tag)
+{
+	char *p;
+	unsigned int taglen = strlen(tag);
+	unsigned long size = modinfo_len;
+
+	for (p = modinfo; p; p = next_string(p, &size)) {
+		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
+			return p + taglen + 1;
+	}
+	return NULL;
+}
+
+/* 
+ * Stolen form Cryptographic API.
+ *
+ * MD4 Message Digest Algorithm (RFC1320).
+ *
+ * Implementation derived from Andrew Tridgell and Steve French's
+ * CIFS MD4 implementation, and the cryptoapi implementation
+ * originally based on the public domain implementation written
+ * by Colin Plumb in 1993.
+ *
+ * Copyright (c) Andrew Tridgell 1997-1998.
+ * Modified by Steve French (sfrench@us.ibm.com) 2002
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#define MD4_DIGEST_SIZE		16
+#define MD4_HMAC_BLOCK_SIZE	64
+#define MD4_BLOCK_WORDS		16
+#define MD4_HASH_WORDS		4
+
+struct md4_ctx {
+	uint32_t hash[MD4_HASH_WORDS];
+	uint32_t block[MD4_BLOCK_WORDS];
+	uint64_t byte_count;
+};
+
+static inline uint32_t lshift(uint32_t x, unsigned int s)
+{
+	x &= 0xFFFFFFFF;
+	return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
+{
+	return (x & y) | ((~x) & z);
+}
+
+static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
+{
+	return (x & y) | (x & z) | (y & z);
+}
+
+static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
+{
+	return x ^ y ^ z;
+}
+                        
+#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
+#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
+#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
+
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
+{
+	while (words--) {
+		*buf = ntohl(*buf);
+		buf++;
+	}
+}
+
+static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
+{
+	while (words--) {
+		*buf = htonl(*buf);
+		buf++;
+	}
+}
+
+static void md4_transform(uint32_t *hash, uint32_t const *in)
+{
+	uint32_t a, b, c, d;
+
+	a = hash[0];
+	b = hash[1];
+	c = hash[2];
+	d = hash[3];
+
+	ROUND1(a, b, c, d, in[0], 3);
+	ROUND1(d, a, b, c, in[1], 7);
+	ROUND1(c, d, a, b, in[2], 11);
+	ROUND1(b, c, d, a, in[3], 19);
+	ROUND1(a, b, c, d, in[4], 3);
+	ROUND1(d, a, b, c, in[5], 7);
+	ROUND1(c, d, a, b, in[6], 11);
+	ROUND1(b, c, d, a, in[7], 19);
+	ROUND1(a, b, c, d, in[8], 3);
+	ROUND1(d, a, b, c, in[9], 7);
+	ROUND1(c, d, a, b, in[10], 11);
+	ROUND1(b, c, d, a, in[11], 19);
+	ROUND1(a, b, c, d, in[12], 3);
+	ROUND1(d, a, b, c, in[13], 7);
+	ROUND1(c, d, a, b, in[14], 11);
+	ROUND1(b, c, d, a, in[15], 19);
+
+	ROUND2(a, b, c, d,in[ 0], 3);
+	ROUND2(d, a, b, c, in[4], 5);
+	ROUND2(c, d, a, b, in[8], 9);
+	ROUND2(b, c, d, a, in[12], 13);
+	ROUND2(a, b, c, d, in[1], 3);
+	ROUND2(d, a, b, c, in[5], 5);
+	ROUND2(c, d, a, b, in[9], 9);
+	ROUND2(b, c, d, a, in[13], 13);
+	ROUND2(a, b, c, d, in[2], 3);
+	ROUND2(d, a, b, c, in[6], 5);
+	ROUND2(c, d, a, b, in[10], 9);
+	ROUND2(b, c, d, a, in[14], 13);
+	ROUND2(a, b, c, d, in[3], 3);
+	ROUND2(d, a, b, c, in[7], 5);
+	ROUND2(c, d, a, b, in[11], 9);
+	ROUND2(b, c, d, a, in[15], 13);
+
+	ROUND3(a, b, c, d,in[ 0], 3);
+	ROUND3(d, a, b, c, in[8], 9);
+	ROUND3(c, d, a, b, in[4], 11);
+	ROUND3(b, c, d, a, in[12], 15);
+	ROUND3(a, b, c, d, in[2], 3);
+	ROUND3(d, a, b, c, in[10], 9);
+	ROUND3(c, d, a, b, in[6], 11);
+	ROUND3(b, c, d, a, in[14], 15);
+	ROUND3(a, b, c, d, in[1], 3);
+	ROUND3(d, a, b, c, in[9], 9);
+	ROUND3(c, d, a, b, in[5], 11);
+	ROUND3(b, c, d, a, in[13], 15);
+	ROUND3(a, b, c, d, in[3], 3);
+	ROUND3(d, a, b, c, in[11], 9);
+	ROUND3(c, d, a, b, in[7], 11);
+	ROUND3(b, c, d, a, in[15], 15);
+
+	hash[0] += a;
+	hash[1] += b;
+	hash[2] += c;
+	hash[3] += d;
+}
+
+static inline void md4_transform_helper(struct md4_ctx *ctx)
+{
+	le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
+	md4_transform(ctx->hash, ctx->block);
+}
+
+static void md4_init(struct md4_ctx *mctx)
+{
+	mctx->hash[0] = 0x67452301;
+	mctx->hash[1] = 0xefcdab89;
+	mctx->hash[2] = 0x98badcfe;
+	mctx->hash[3] = 0x10325476;
+	mctx->byte_count = 0;
+}
+
+static void md4_update(struct md4_ctx *mctx,
+		       const unsigned char *data, unsigned int len)
+{
+	const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+	mctx->byte_count += len;
+
+	if (avail > len) {
+		memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+		       data, len);
+		return;
+	}
+
+	memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+	       data, avail);
+
+	md4_transform_helper(mctx);
+	data += avail;
+	len -= avail;
+
+	while (len >= sizeof(mctx->block)) {
+		memcpy(mctx->block, data, sizeof(mctx->block));
+		md4_transform_helper(mctx);
+		data += sizeof(mctx->block);
+		len -= sizeof(mctx->block);
+	}
+
+	memcpy(mctx->block, data, len);
+}
+
+static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
+{
+	const unsigned int offset = mctx->byte_count & 0x3f;
+	char *p = (char *)mctx->block + offset;
+	int padding = 56 - (offset + 1);
+
+	*p++ = 0x80;
+	if (padding < 0) {
+		memset(p, 0x00, padding + sizeof (uint64_t));
+		md4_transform_helper(mctx);
+		p = (char *)mctx->block;
+		padding = 56;
+	}
+
+	memset(p, 0, padding);
+	mctx->block[14] = mctx->byte_count << 3;
+	mctx->block[15] = mctx->byte_count >> 29;
+	le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
+	                  sizeof(uint64_t)) / sizeof(uint32_t));
+	md4_transform(mctx->hash, mctx->block);
+	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
+	
+	snprintf(out, len, "%08X%08X%08X%08X",
+		 mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
+}
+
+static int parse_file(const char *fname, struct md4_ctx *md);
+
+/* Local include files, if in current dir. */
+static void include_file(const char *line, int maxlen, const char *base,
+			 struct md4_ctx *md)
+{
+	unsigned int i;
+
+	for (i = 0; line[i] != '"'; i++) {
+		if (i == maxlen) {
+			fprintf(stderr,
+				"sumversion: badly formed #include in %s\n",
+				base);
+			return;
+		}
+	}
+
+	{
+		const char *dirend;
+		char fname[i + strlen(base)];
+
+		dirend = strrchr(base, '/');
+		if (!dirend)
+			dirend = base;
+		else
+			dirend++;
+		memcpy(fname, base, dirend - base);
+		memcpy(fname + (dirend - base), line, i);
+		fname[(dirend - base) + i] = '\0';
+
+		parse_file(fname, md);
+	}
+}
+
+static inline void add_char(unsigned char c, struct md4_ctx *md)
+{
+	md4_update(md, &c, 1);
+}
+
+static int parse_string(const char *file, unsigned long len,
+			struct md4_ctx *md)
+{
+	unsigned long i;
+
+	add_char(file[0], md);
+	for (i = 1; i < len; i++) {
+		add_char(file[i], md);
+		if (file[i] == '"' && file[i-1] != '\\')
+			break;
+	}
+	return i;
+}
+
+static int parse_comment(const char *file, unsigned long len)
+{
+	unsigned long i;
+
+	for (i = 2; i < len; i++) {
+		if (file[i-1] == '*' && file[i] == '/')
+			break;
+	}
+	return i;
+}
+
+static int skip_whitespace(const char *file, unsigned long len)
+{
+	unsigned long i;
+
+	for (i = 0; i < len; i++) {
+		if (file[i] != ' ' && file[i] != '\t')
+			break;
+	}
+	return i;
+}
+
+#define strneq(str, literal) (strncmp((str), (literal), strlen(literal)) == 0)
+
+/* Just in case it does a (local) include. */
+static int parse_cpp_line(const char *file, unsigned long len,
+			  const char *base, struct md4_ctx *md)
+{
+	unsigned long i = 0;
+
+	add_char(file[i++], md);
+	i += skip_whitespace(file+i, len - i);
+	if (i + strlen("include") >= len)
+		return i;
+	if (!strneq(file + i, "include"))
+		return i;
+	md4_update(md, (unsigned char *)"include", strlen("include"));	
+	i += strlen("include");
+	i += skip_whitespace(file+i, len - i);
+	if (i >= len)
+		return i;
+	if (file[i] != '"')
+		return i-1;
+	include_file(file+i+1, len - i - 1, base, md);
+	return i-1;
+}
+
+/* FIXME: Handle .s files differently (eg. # starts comments) --RR */
+static int parse_file(const char *fname, struct md4_ctx *md)
+{
+	char *file;
+	unsigned long i, len;
+	int start_of_line = 1;
+
+	file = grab_file(fname, &len);
+	if (!file)
+		return 0;
+
+	for (i = 0; i < len; i++) {
+		/* Collapse and ignore \ and CR. */
+		if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') {
+			i += 2;
+			continue;
+		}
+
+		if (file[i] == '\n')
+			start_of_line = 1;
+
+		/* Ignore whitespace */
+		if (isspace(file[i]))
+			continue;
+
+		/* Handle strings as whole units */
+		if (file[i] == '"') {
+			i += parse_string(file+i, len - i, md);
+			start_of_line = 0;
+			continue;
+		}
+
+		/* Comments: ignore */
+		if (file[i] == '/' && file[i+1] == '*') {
+			i += parse_comment(file+i, len - i);
+			start_of_line = 0;
+			continue;
+		}
+
+		/* Potential #include files */
+		if (file[i] == '#' && start_of_line) {
+			i += parse_cpp_line(file+i, len - i, fname, md);
+			start_of_line = 0;
+			continue;
+		}
+
+		start_of_line = 0;
+		add_char(file[i], md);
+	}
+	return 1;
+}
+
+/* We have dir/file.o.  Open dir/.file.o.cmd, look for deps_ line to
+ * figure out source file. */
+static char *get_source_name(const char *objfile)
+{
+	char *cmd, *file, *p, *source = NULL;
+	const char *base;
+	unsigned long len, flen;
+
+	cmd = malloc(strlen(objfile) + sizeof("..cmd"));
+
+	base = strrchr(objfile, '/');
+	if (base) {
+		base++;
+		sprintf(cmd, "%.*s.%s.cmd", base - objfile, objfile, base);
+	} else 
+		sprintf(cmd, ".%s.cmd", objfile);
+
+	file = grab_file(cmd, &flen);
+	if (!file) {
+		fprintf(stderr, "Warning: could not find %s for %s\n",
+			cmd, objfile);
+		goto out;
+	}
+
+	/* There will be a line like so:
+		   deps_drivers/scsi/aic7xxx/aic7xxx_osm.o := \
+		   /home/sam/bk/v2.6/drivers/scsi/aic7xxx/aic7xxx_osm.c \
+	*/
+	/* Strictly illegal: file is not nul terminated. */
+	p = strstr(file, "\ndeps_");
+	if (!p) {
+		fprintf(stderr, "Warning: could not find deps_ line in %s\n",
+			cmd);
+		goto out;
+	}
+	p = strstr(p, ":=");
+	if (!p) {
+		fprintf(stderr, "Warning: could not find := line in %s\n",
+			cmd);
+		goto out;
+	}
+	p += strlen(":=");
+	while (*p == '\\' || isspace(*p))
+		p++;
+
+	len = strcspn(p, " \\\n");
+	source = malloc(len+1);
+	memcpy(source, p, len);
+	source[len] = '\0';
+out:
+	free(cmd);
+	return source;
+}
+
+static void get_version(const char *modname, char sum[])
+{
+	void *file;
+	unsigned long len;
+	struct md4_ctx md;
+	char *sources, *end, *fname;
+	const char *basename;
+	char filelist[sizeof(".tmp_versions/%s.mod") + strlen(modname)];
+
+	/* Source files for module are in .tmp_versions/modname.mod,
+	   after the first line. */
+	if (strrchr(modname, '/'))
+		basename = strrchr(modname, '/') + 1;
+	else
+		basename = modname;
+	sprintf(filelist, ".tmp_versions/%s", basename);
+	/* Truncate .o, add .mod */
+	strcpy(filelist + strlen(filelist)-2, ".mod");
+
+	file = grab_file(filelist, &len);
+	if (!file) {
+		fprintf(stderr, "Warning: could not find versions for %s\n",
+			filelist);
+		return;
+	}
+
+	sources = strchr(file, '\n');
+	if (!sources) {
+		fprintf(stderr, "Warning: malformed versions file for %s\n",
+			modname);
+		goto release;
+	}
+
+	sources++;
+	end = strchr(sources, '\n');
+	if (!end) {
+		fprintf(stderr, "Warning: bad ending versions file for %s\n",
+			modname);
+		goto release;
+	}
+	*end = '\0';
+
+	md4_init(&md);
+	for (fname = strtok(sources, " "); fname; fname = strtok(NULL, " ")) {
+		char *source = get_source_name(fname);
+		if (source && !parse_file(source, &md)) {
+			fprintf(stderr, "Warning: could not open %s: %s\n",
+				source, strerror(errno));
+			free(source);
+			goto release;
+		}
+		free(source);
+	}
+
+	/* sum is of form \0<padding>. */ 
+	md4_final_ascii(&md, sum, 1 + strlen(sum+1));
+release:
+	release_file(file, len);
+}
+
+static void write_version(const char *filename, const char *sum,
+			  unsigned long offset)
+{
+	int fd;
+
+	fd = open(filename, O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "Warning: changing sum in %s failed: %s\n",
+			filename, strerror(errno));
+		return;
+	}
+
+	if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+		fprintf(stderr, "Warning: changing sum in %s:%lu failed: %s\n",
+			filename, offset, strerror(errno));
+		goto out;
+	}
+
+	if (write(fd, sum, strlen(sum)+1) != strlen(sum)+1) {
+		fprintf(stderr, "Warning: writing sum in %s failed: %s\n",
+			filename, strerror(errno));
+		goto out;
+	}
+out:
+	close(fd);
+}
+
+void strip_rcs_crap(char *version)
+{
+	unsigned int len, full_len;
+
+	if (strncmp(version, "$Revision", strlen("$Revision")) != 0)
+		return;
+
+	/* Space for version string follows. */
+	full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2;
+
+	/* Move string to start with version number: prefix will be
+	 * $Revision$ or $Revision: */
+	len = strlen("$Revision");
+	if (version[len] == ':' || version[len] == '$')
+		len++;
+	while (isspace(version[len])) 
+		len++;
+	memmove(version, version+len, full_len-len);
+	full_len -= len;
+
+	/* Preserve up to next whitespace. */
+	len = 0;
+	while (version[len] && !isspace(version[len]))
+		len++;
+	memmove(version + len, version + strlen(version),
+		full_len - strlen(version));
+}
+
+/* If the modinfo contains a "version" value, then set this. */
+void maybe_frob_version(const char *modfilename,
+			void *modinfo,
+			unsigned long modinfo_len,
+			unsigned long modinfo_offset)
+{
+	char *version, *csum;
+
+	version = get_modinfo(modinfo, modinfo_len, "version");
+	if (!version)
+		return;
+
+	/* RCS $Revision gets stripped out. */
+	strip_rcs_crap(version);
+
+	/* Check against double sumversion */
+	if (strchr(version, ' '))
+		return;
+
+	/* Version contains embedded NUL: second half has space for checksum */
+	csum = version + strlen(version);
+	*(csum++) = ' ';
+	get_version(modfilename, csum);
+	write_version(modfilename, version,
+		      modinfo_offset + (version - (char *)modinfo));
+}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-02-23  3:51             ` Rusty Russell
@ 2004-02-23 21:17               ` Sam Ravnborg
  2004-02-24  6:13                 ` Rusty Russell
  0 siblings, 1 reply; 14+ messages in thread
From: Sam Ravnborg @ 2004-02-23 21:17 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Sam Ravnborg, Brian King, akpm, linux-kernel

On Mon, Feb 23, 2004 at 02:51:04PM +1100, Rusty Russell wrote:
> In message <20040222232317.GA20083@mars.ravnborg.org> you write:
> > The more correct approach is to list the .o files in the
> > .mod file. Then in sumversion find the corresponding .file.o.cmd, and parse
> > up the name of the corresponding source file (listed as the first filename
> > in the deps_ assignment, and pass this filename to grab_file.
> 
> OK, I've implemented that.  It doesn't complain about non-C files,
> although the parsing might be sub-optimal.
> 
> See get_source_name() for new code.  I also put the explicit depend on
> elfconfig.h in the Makefile.

Took a second look at it.
The reason why you parse the sourcefile, is to locate files included
from the local directory.
But this information is already available in the .module.o.cmd file,
so no reason to parse that information up from the .c file -
and eventually having troubles with .s files.

You can get rid of parse_cpp_line(), include_file(),
and some of the helpers when implementing this algorithm. So all
in all a good simplification.

Note also that in the original implementation you have missed
release_file() in a few places. But when you implement the above
you will hit them.

	Sam

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-02-23 21:17               ` Sam Ravnborg
@ 2004-02-24  6:13                 ` Rusty Russell
  2004-02-25 21:36                   ` Sam Ravnborg
  0 siblings, 1 reply; 14+ messages in thread
From: Rusty Russell @ 2004-02-24  6:13 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: Brian King, akpm, linux-kernel

In message <20040223211718.GA7610@mars.ravnborg.org> you write:
> But this information is already available in the .module.o.cmd file,
> so no reason to parse that information up from the .c file -
> and eventually having troubles with .s files.
> 
> You can get rid of parse_cpp_line(), include_file(),
> and some of the helpers when implementing this algorithm. So all
> in all a good simplification.

Yep, fixed this, and fixed the broken modules_install for Andrew.
This one actually boot tested.

> Note also that in the original implementation you have missed
> release_file() in a few places. But when you implement the above
> you will hit them.

Fixed them too.

Rusty.
--
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

Name: Add a MODULE_VERSION macro
Author: Rusty Russell
Status: Tested on 2.6.3-bk4

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.

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .29265-linux-2.6.3-bk4/include/linux/module.h .29265-linux-2.6.3-bk4.updated/include/linux/module.h
--- .29265-linux-2.6.3-bk4/include/linux/module.h	2004-02-04 15:39:14.000000000 +1100
+++ .29265-linux-2.6.3-bk4.updated/include/linux/module.h	2004-02-24 13:31:33.000000000 +1100
@@ -127,6 +127,24 @@ extern const struct gtype##_id __mod_##g
 #define MODULE_DEVICE_TABLE(type,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 */
 const struct exception_table_entry *search_exception_tables(unsigned long add);
 
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .29265-linux-2.6.3-bk4/scripts/Makefile .29265-linux-2.6.3-bk4.updated/scripts/Makefile
--- .29265-linux-2.6.3-bk4/scripts/Makefile	2003-09-29 10:26:16.000000000 +1000
+++ .29265-linux-2.6.3-bk4.updated/scripts/Makefile	2004-02-24 13:31:33.000000000 +1100
@@ -12,7 +12,7 @@ host-progs	:= fixdep split-include conma
 		   mk_elfconfig pnmtologo bin2c
 always		:= $(host-progs) empty.o
 
-modpost-objs	:= modpost.o file2alias.o
+modpost-objs	:= modpost.o file2alias.o sumversion.o
 
 subdir-$(CONFIG_MODVERSIONS)	+= genksyms
 
@@ -24,7 +24,7 @@ $(addprefix $(obj)/,$(filter-out fixdep,
 
 # 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   $@
       cmd_elfconfig = $(obj)/mk_elfconfig $(ARCH) < $< > $@
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .29265-linux-2.6.3-bk4/scripts/Makefile.build .29265-linux-2.6.3-bk4.updated/scripts/Makefile.build
--- .29265-linux-2.6.3-bk4/scripts/Makefile.build	2003-10-09 18:03:05.000000000 +1000
+++ .29265-linux-2.6.3-bk4.updated/scripts/Makefile.build	2004-02-24 13:31:33.000000000 +1100
@@ -64,8 +64,6 @@ endif
 
 # 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)) \
 	 $(if $(KBUILD_MODULES),$(obj-m)) \
 	 $(subdir-ym) $(always)
@@ -178,7 +176,7 @@ endef
 
 $(single-used-m): %.o: %.c FORCE
 	$(call if_changed_rule,cc_o_c)
-	$(touch-module)
+	@{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
 
 quiet_cmd_cc_lst_c = MKLST   $@
       cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
@@ -273,7 +271,7 @@ $(multi-used-y) : %.o: $(multi-objs-y) F
 
 $(multi-used-m) : %.o: $(multi-objs-m) FORCE
 	$(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)
 
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .29265-linux-2.6.3-bk4/scripts/Makefile.modinst .29265-linux-2.6.3-bk4.updated/scripts/Makefile.modinst
--- .29265-linux-2.6.3-bk4/scripts/Makefile.modinst	2003-09-22 10:04:52.000000000 +1000
+++ .29265-linux-2.6.3-bk4.updated/scripts/Makefile.modinst	2004-02-24 13:31:33.000000000 +1100
@@ -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)))
 
 ifneq ($(filter-out $(modules),$(__modules)),)
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .29265-linux-2.6.3-bk4/scripts/Makefile.modpost .29265-linux-2.6.3-bk4.updated/scripts/Makefile.modpost
--- .29265-linux-2.6.3-bk4/scripts/Makefile.modpost	2003-09-29 10:26:16.000000000 +1000
+++ .29265-linux-2.6.3-bk4.updated/scripts/Makefile.modpost	2004-02-24 13:31:33.000000000 +1100
@@ -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)))
 
 ifneq ($(filter-out $(modules),$(__modules)),)
+  $(warning Trouble: $(__modules) )
   $(warning *** Uh-oh, you have stale module entries. You messed with SUBDIRS,)
   $(warning     do not complain if something goes wrong.)
 endif
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .29265-linux-2.6.3-bk4/scripts/modpost.c .29265-linux-2.6.3-bk4.updated/scripts/modpost.c
--- .29265-linux-2.6.3-bk4/scripts/modpost.c	2004-02-18 23:54:38.000000000 +1100
+++ .29265-linux-2.6.3-bk4.updated/scripts/modpost.c	2004-02-24 13:31:33.000000000 +1100
@@ -65,15 +65,15 @@ new_module(char *modname)
 	struct module *mod;
 	char *p;
 	
+	mod = NOFAIL(malloc(sizeof(*mod)));
+	memset(mod, 0, sizeof(*mod));
+	mod->name = NOFAIL(strdup(modname));
+
 	/* strip trailing .o */
-	p = strstr(modname, ".o");
+	p = strstr(mod->name, ".o");
 	if (p)
 		*p = 0;
 
-	mod = NOFAIL(malloc(sizeof(*mod)));
-	memset(mod, 0, sizeof(*mod));
-	mod->name = modname;
-
 	/* add to list */
 	mod->next = modules;
 	modules = mod;
@@ -194,26 +194,25 @@ grab_file(const char *filename, unsigned
 	int fd;
 
 	fd = open(filename, O_RDONLY);
-	if (fd < 0) {
-		perror(filename);
-		abort();
-	}
-	if (fstat(fd, &st) != 0) {
-		perror(filename);
-		abort();
-	}
+	if (fstat(fd, &st) != 0)
+		return NULL;
 
 	*size = st.st_size;
 	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-	if (map == MAP_FAILED) {
-		perror(filename);
-		abort();
-	}
 	close(fd);
+
+	if (map == MAP_FAILED)
+		return NULL;
 	return map;
 }
 
 void
+release_file(void *file, unsigned long size)
+{
+	munmap(file, size);
+}
+
+void
 parse_elf(struct elf_info *info, const char *filename)
 {
 	unsigned int i;
@@ -222,6 +221,10 @@ parse_elf(struct elf_info *info, const c
 	Elf_Sym  *sym;
 
 	hdr = grab_file(filename, &info->size);
+	if (!hdr) {
+		perror(filename);
+		abort();
+	}
 	info->hdr = hdr;
 	if (info->size < sizeof(*hdr))
 		goto truncated;
@@ -239,11 +242,19 @@ parse_elf(struct elf_info *info, const c
 		sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
 		sechdrs[i].sh_size   = TO_NATIVE(sechdrs[i].sh_size);
 		sechdrs[i].sh_link   = TO_NATIVE(sechdrs[i].sh_link);
+		sechdrs[i].sh_name   = TO_NATIVE(sechdrs[i].sh_name);
 	}
 	/* Find symbol table. */
 	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)
 			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)
 			continue;
 
@@ -274,7 +285,7 @@ parse_elf(struct elf_info *info, const c
 void
 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_"
@@ -372,6 +383,8 @@ read_symbols(char *modname)
 		handle_modversions(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);
 
 	/* Our trick to get versioning for struct_module - it's
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .29265-linux-2.6.3-bk4/scripts/modpost.h .29265-linux-2.6.3-bk4.updated/scripts/modpost.h
--- .29265-linux-2.6.3-bk4/scripts/modpost.h	2003-09-22 10:06:44.000000000 +1000
+++ .29265-linux-2.6.3-bk4.updated/scripts/modpost.h	2004-02-24 13:31:33.000000000 +1100
@@ -80,9 +80,19 @@ struct elf_info {
 	Elf_Sym      *symtab_start;
 	Elf_Sym      *symtab_stop;
 	const char   *strtab;
+	char	     *modinfo;
+	unsigned int modinfo_len;
 };
 
 void handle_moddevtable(struct module *mod, struct elf_info *info,
 			Elf_Sym *sym, const char *symname);
 
 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);
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .29265-linux-2.6.3-bk4/scripts/sumversion.c .29265-linux-2.6.3-bk4.updated/scripts/sumversion.c
--- .29265-linux-2.6.3-bk4/scripts/sumversion.c	1970-01-01 10:00:00.000000000 +1000
+++ .29265-linux-2.6.3-bk4.updated/scripts/sumversion.c	2004-02-24 13:32:58.000000000 +1100
@@ -0,0 +1,550 @@
+#include <netinet/in.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include "modpost.h"
+
+/* Parse tag=value strings from .modinfo section */
+static char *next_string(char *string, unsigned long *secsize)
+{
+	/* Skip non-zero chars */
+	while (string[0]) {
+		string++;
+		if ((*secsize)-- <= 1)
+			return NULL;
+	}
+
+	/* Skip any zero padding. */
+	while (!string[0]) {
+		string++;
+		if ((*secsize)-- <= 1)
+			return NULL;
+	}
+	return string;
+}
+
+static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
+			 const char *tag)
+{
+	char *p;
+	unsigned int taglen = strlen(tag);
+	unsigned long size = modinfo_len;
+
+	for (p = modinfo; p; p = next_string(p, &size)) {
+		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
+			return p + taglen + 1;
+	}
+	return NULL;
+}
+
+/* 
+ * Stolen form Cryptographic API.
+ *
+ * MD4 Message Digest Algorithm (RFC1320).
+ *
+ * Implementation derived from Andrew Tridgell and Steve French's
+ * CIFS MD4 implementation, and the cryptoapi implementation
+ * originally based on the public domain implementation written
+ * by Colin Plumb in 1993.
+ *
+ * Copyright (c) Andrew Tridgell 1997-1998.
+ * Modified by Steve French (sfrench@us.ibm.com) 2002
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#define MD4_DIGEST_SIZE		16
+#define MD4_HMAC_BLOCK_SIZE	64
+#define MD4_BLOCK_WORDS		16
+#define MD4_HASH_WORDS		4
+
+struct md4_ctx {
+	uint32_t hash[MD4_HASH_WORDS];
+	uint32_t block[MD4_BLOCK_WORDS];
+	uint64_t byte_count;
+};
+
+static inline uint32_t lshift(uint32_t x, unsigned int s)
+{
+	x &= 0xFFFFFFFF;
+	return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
+{
+	return (x & y) | ((~x) & z);
+}
+
+static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
+{
+	return (x & y) | (x & z) | (y & z);
+}
+
+static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
+{
+	return x ^ y ^ z;
+}
+                        
+#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
+#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
+#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
+
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
+{
+	while (words--) {
+		*buf = ntohl(*buf);
+		buf++;
+	}
+}
+
+static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
+{
+	while (words--) {
+		*buf = htonl(*buf);
+		buf++;
+	}
+}
+
+static void md4_transform(uint32_t *hash, uint32_t const *in)
+{
+	uint32_t a, b, c, d;
+
+	a = hash[0];
+	b = hash[1];
+	c = hash[2];
+	d = hash[3];
+
+	ROUND1(a, b, c, d, in[0], 3);
+	ROUND1(d, a, b, c, in[1], 7);
+	ROUND1(c, d, a, b, in[2], 11);
+	ROUND1(b, c, d, a, in[3], 19);
+	ROUND1(a, b, c, d, in[4], 3);
+	ROUND1(d, a, b, c, in[5], 7);
+	ROUND1(c, d, a, b, in[6], 11);
+	ROUND1(b, c, d, a, in[7], 19);
+	ROUND1(a, b, c, d, in[8], 3);
+	ROUND1(d, a, b, c, in[9], 7);
+	ROUND1(c, d, a, b, in[10], 11);
+	ROUND1(b, c, d, a, in[11], 19);
+	ROUND1(a, b, c, d, in[12], 3);
+	ROUND1(d, a, b, c, in[13], 7);
+	ROUND1(c, d, a, b, in[14], 11);
+	ROUND1(b, c, d, a, in[15], 19);
+
+	ROUND2(a, b, c, d,in[ 0], 3);
+	ROUND2(d, a, b, c, in[4], 5);
+	ROUND2(c, d, a, b, in[8], 9);
+	ROUND2(b, c, d, a, in[12], 13);
+	ROUND2(a, b, c, d, in[1], 3);
+	ROUND2(d, a, b, c, in[5], 5);
+	ROUND2(c, d, a, b, in[9], 9);
+	ROUND2(b, c, d, a, in[13], 13);
+	ROUND2(a, b, c, d, in[2], 3);
+	ROUND2(d, a, b, c, in[6], 5);
+	ROUND2(c, d, a, b, in[10], 9);
+	ROUND2(b, c, d, a, in[14], 13);
+	ROUND2(a, b, c, d, in[3], 3);
+	ROUND2(d, a, b, c, in[7], 5);
+	ROUND2(c, d, a, b, in[11], 9);
+	ROUND2(b, c, d, a, in[15], 13);
+
+	ROUND3(a, b, c, d,in[ 0], 3);
+	ROUND3(d, a, b, c, in[8], 9);
+	ROUND3(c, d, a, b, in[4], 11);
+	ROUND3(b, c, d, a, in[12], 15);
+	ROUND3(a, b, c, d, in[2], 3);
+	ROUND3(d, a, b, c, in[10], 9);
+	ROUND3(c, d, a, b, in[6], 11);
+	ROUND3(b, c, d, a, in[14], 15);
+	ROUND3(a, b, c, d, in[1], 3);
+	ROUND3(d, a, b, c, in[9], 9);
+	ROUND3(c, d, a, b, in[5], 11);
+	ROUND3(b, c, d, a, in[13], 15);
+	ROUND3(a, b, c, d, in[3], 3);
+	ROUND3(d, a, b, c, in[11], 9);
+	ROUND3(c, d, a, b, in[7], 11);
+	ROUND3(b, c, d, a, in[15], 15);
+
+	hash[0] += a;
+	hash[1] += b;
+	hash[2] += c;
+	hash[3] += d;
+}
+
+static inline void md4_transform_helper(struct md4_ctx *ctx)
+{
+	le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
+	md4_transform(ctx->hash, ctx->block);
+}
+
+static void md4_init(struct md4_ctx *mctx)
+{
+	mctx->hash[0] = 0x67452301;
+	mctx->hash[1] = 0xefcdab89;
+	mctx->hash[2] = 0x98badcfe;
+	mctx->hash[3] = 0x10325476;
+	mctx->byte_count = 0;
+}
+
+static void md4_update(struct md4_ctx *mctx,
+		       const unsigned char *data, unsigned int len)
+{
+	const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+	mctx->byte_count += len;
+
+	if (avail > len) {
+		memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+		       data, len);
+		return;
+	}
+
+	memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+	       data, avail);
+
+	md4_transform_helper(mctx);
+	data += avail;
+	len -= avail;
+
+	while (len >= sizeof(mctx->block)) {
+		memcpy(mctx->block, data, sizeof(mctx->block));
+		md4_transform_helper(mctx);
+		data += sizeof(mctx->block);
+		len -= sizeof(mctx->block);
+	}
+
+	memcpy(mctx->block, data, len);
+}
+
+static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
+{
+	const unsigned int offset = mctx->byte_count & 0x3f;
+	char *p = (char *)mctx->block + offset;
+	int padding = 56 - (offset + 1);
+
+	*p++ = 0x80;
+	if (padding < 0) {
+		memset(p, 0x00, padding + sizeof (uint64_t));
+		md4_transform_helper(mctx);
+		p = (char *)mctx->block;
+		padding = 56;
+	}
+
+	memset(p, 0, padding);
+	mctx->block[14] = mctx->byte_count << 3;
+	mctx->block[15] = mctx->byte_count >> 29;
+	le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
+	                  sizeof(uint64_t)) / sizeof(uint32_t));
+	md4_transform(mctx->hash, mctx->block);
+	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
+	
+	snprintf(out, len, "%08X%08X%08X%08X",
+		 mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
+}
+
+static inline void add_char(unsigned char c, struct md4_ctx *md)
+{
+	md4_update(md, &c, 1);
+}
+
+static int parse_string(const char *file, unsigned long len,
+			struct md4_ctx *md)
+{
+	unsigned long i;
+
+	add_char(file[0], md);
+	for (i = 1; i < len; i++) {
+		add_char(file[i], md);
+		if (file[i] == '"' && file[i-1] != '\\')
+			break;
+	}
+	return i;
+}
+
+static int parse_comment(const char *file, unsigned long len)
+{
+	unsigned long i;
+
+	for (i = 2; i < len; i++) {
+		if (file[i-1] == '*' && file[i] == '/')
+			break;
+	}
+	return i;
+}
+
+/* FIXME: Handle .s files differently (eg. # starts comments) --RR */
+static int parse_file(const char *fname, struct md4_ctx *md)
+{
+	char *file;
+	unsigned long i, len;
+
+	file = grab_file(fname, &len);
+	if (!file)
+		return 0;
+
+	for (i = 0; i < len; i++) {
+		/* Collapse and ignore \ and CR. */
+		if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') {
+			i++;
+			continue;
+		}
+
+		/* Ignore whitespace */
+		if (isspace(file[i]))
+			continue;
+
+		/* Handle strings as whole units */
+		if (file[i] == '"') {
+			i += parse_string(file+i, len - i, md);
+			continue;
+		}
+
+		/* Comments: ignore */
+		if (file[i] == '/' && file[i+1] == '*') {
+			i += parse_comment(file+i, len - i);
+			continue;
+		}
+
+		add_char(file[i], md);
+	}
+	release_file(file, len);
+	return 1;
+}
+
+/* We have dir/file.o.  Open dir/.file.o.cmd, look for deps_ line to
+ * figure out source file. */
+static int parse_source_files(const char *objfile, struct md4_ctx *md)
+{
+	char *cmd, *file, *p, *end;
+	const char *base;
+	unsigned long flen;
+	int dirlen, ret = 0;
+
+	cmd = malloc(strlen(objfile) + sizeof("..cmd"));
+
+	base = strrchr(objfile, '/');
+	if (base) {
+		base++;
+		dirlen = base - objfile;
+		sprintf(cmd, "%.*s.%s.cmd", dirlen, objfile, base);
+	} else {
+		dirlen = 0;
+		sprintf(cmd, ".%s.cmd", objfile);
+	}
+
+	file = grab_file(cmd, &flen);
+	if (!file) {
+		fprintf(stderr, "Warning: could not find %s for %s\n",
+			cmd, objfile);
+		goto out;
+	}
+
+	/* There will be a line like so:
+		deps_drivers/net/dummy.o := \
+		  drivers/net/dummy.c \
+		    $(wildcard include/config/net/fastroute.h) \
+		  include/linux/config.h \
+		    $(wildcard include/config/h.h) \
+		  include/linux/module.h \
+
+	   Sum all files in the same dir or subdirs.
+	*/
+	/* Strictly illegal: file is not nul terminated. */
+	p = strstr(file, "\ndeps_");
+	if (!p) {
+		fprintf(stderr, "Warning: could not find deps_ line in %s\n",
+			cmd);
+		goto out_file;
+	}
+	p = strstr(p, ":=");
+	if (!p) {
+		fprintf(stderr, "Warning: could not find := line in %s\n",
+			cmd);
+		goto out_file;
+	}
+	p += strlen(":=");
+	p += strspn(p, " \\\n");
+
+	end = strstr(p, "\n\n");
+	if (!end) {
+		fprintf(stderr, "Warning: could not find end line in %s\n",
+			cmd);
+		goto out_file;
+	}
+
+	while (p < end) {
+		unsigned int len;
+
+		len = strcspn(p, " \\\n");
+		if (memcmp(objfile, p, dirlen) == 0) {
+			char source[len + 1];
+
+			memcpy(source, p, len);
+			source[len] = '\0';
+			printf("parsing %s\n", source);
+			if (!parse_file(source, md)) {
+				fprintf(stderr,
+					"Warning: could not open %s: %s\n",
+					source, strerror(errno));
+				goto out_file;
+			}
+		}
+		p += len;
+		p += strspn(p, " \\\n");
+	}
+
+	/* Everyone parsed OK */
+	ret = 1;
+out_file:
+	release_file(file, flen);
+out:
+	free(cmd);
+	return ret;
+}
+
+static int get_version(const char *modname, char sum[])
+{
+	void *file;
+	unsigned long len;
+	int ret = 0;
+	struct md4_ctx md;
+	char *sources, *end, *fname;
+	const char *basename;
+	char filelist[sizeof(".tmp_versions/%s.mod") + strlen(modname)];
+
+	/* Source files for module are in .tmp_versions/modname.mod,
+	   after the first line. */
+	if (strrchr(modname, '/'))
+		basename = strrchr(modname, '/') + 1;
+	else
+		basename = modname;
+	sprintf(filelist, ".tmp_versions/%s", basename);
+	/* Truncate .o, add .mod */
+	strcpy(filelist + strlen(filelist)-2, ".mod");
+
+	file = grab_file(filelist, &len);
+	if (!file) {
+		fprintf(stderr, "Warning: could not find versions for %s\n",
+			filelist);
+		return 0;
+	}
+
+	sources = strchr(file, '\n');
+	if (!sources) {
+		fprintf(stderr, "Warning: malformed versions file for %s\n",
+			modname);
+		goto release;
+	}
+
+	sources++;
+	end = strchr(sources, '\n');
+	if (!end) {
+		fprintf(stderr, "Warning: bad ending versions file for %s\n",
+			modname);
+		goto release;
+	}
+	*end = '\0';
+
+	md4_init(&md);
+	for (fname = strtok(sources, " "); fname; fname = strtok(NULL, " ")) {
+		if (!parse_source_files(fname, &md))
+			goto release;
+	}
+
+	/* sum is of form \0<padding>. */ 
+	md4_final_ascii(&md, sum, 1 + strlen(sum+1));
+	ret = 1;
+release:
+	release_file(file, len);
+	return ret;
+}
+
+static void write_version(const char *filename, const char *sum,
+			  unsigned long offset)
+{
+	int fd;
+
+	fd = open(filename, O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "Warning: changing sum in %s failed: %s\n",
+			filename, strerror(errno));
+		return;
+	}
+
+	if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+		fprintf(stderr, "Warning: changing sum in %s:%lu failed: %s\n",
+			filename, offset, strerror(errno));
+		goto out;
+	}
+
+	if (write(fd, sum, strlen(sum)+1) != strlen(sum)+1) {
+		fprintf(stderr, "Warning: writing sum in %s failed: %s\n",
+			filename, strerror(errno));
+		goto out;
+	}
+out:
+	close(fd);
+}
+
+void strip_rcs_crap(char *version)
+{
+	unsigned int len, full_len;
+
+	if (strncmp(version, "$Revision", strlen("$Revision")) != 0)
+		return;
+
+	/* Space for version string follows. */
+	full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2;
+
+	/* Move string to start with version number: prefix will be
+	 * $Revision$ or $Revision: */
+	len = strlen("$Revision");
+	if (version[len] == ':' || version[len] == '$')
+		len++;
+	while (isspace(version[len])) 
+		len++;
+	memmove(version, version+len, full_len-len);
+	full_len -= len;
+
+	/* Preserve up to next whitespace. */
+	len = 0;
+	while (version[len] && !isspace(version[len]))
+		len++;
+	memmove(version + len, version + strlen(version),
+		full_len - strlen(version));
+}
+
+/* If the modinfo contains a "version" value, then set this. */
+void maybe_frob_version(const char *modfilename,
+			void *modinfo,
+			unsigned long modinfo_len,
+			unsigned long modinfo_offset)
+{
+	char *version, *csum;
+
+	version = get_modinfo(modinfo, modinfo_len, "version");
+	if (!version)
+		return;
+
+	/* RCS $Revision gets stripped out. */
+	strip_rcs_crap(version);
+
+	/* Check against double sumversion */
+	if (strchr(version, ' '))
+		return;
+
+	/* Version contains embedded NUL: second half has space for checksum */
+	csum = version + strlen(version);
+	*(csum++) = ' ';
+	if (get_version(modfilename, csum))
+		write_version(modfilename, version,
+			      modinfo_offset + (version - (char *)modinfo));
+}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-02-24  6:13                 ` Rusty Russell
@ 2004-02-25 21:36                   ` Sam Ravnborg
  2004-02-26  1:50                     ` Rusty Russell
  0 siblings, 1 reply; 14+ messages in thread
From: Sam Ravnborg @ 2004-02-25 21:36 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Sam Ravnborg, Brian King, akpm, linux-kernel

Hi Rusty.

I have not yet fully understood why you want to parse every source file.
I can see in the implemntation that you only calculate the sum of
code-lines, and not comments.
But why do we want to add this complexity - compared to just
calculating the sum of the whole file?
If the calculated sum is being presented as based on the source code
I assume people can understand that the sum does not match even after
updating a comment.

The current implementation fails to locate include files in the local
directory when compiled using "make O=...".
This is due to the fact that some files are present in the _deps
file with full path, others with relative path.

Example:
  /home/sam/bk/v2.6/drivers/scsi/aic7xxx/aiclib.h \
  /home/sam/bk/v2.6/drivers/scsi/aic7xxx/aic7xxx.h \
    $(wildcard include/config/used.h) \
  drivers/scsi/aic7xxx/aic7xxx_reg.h \
  /home/sam/bk/v2.6/drivers/scsi/aic7xxx/aic7xxx_inline.h \


I took a quick look and cannot explain why gcc spits out include files
with different paths.

My next question. Since we only parse a subset of the headers, is it
really needed to parse any of them?
My thinking is that we should either:
a) parse all header files (except those marked with $(wildcard))
b) parse no header files.

See also a few specific comments below.

	Sam

> +/* We have dir/file.o.  Open dir/.file.o.cmd, look for deps_ line to
> + * figure out source file. */
> +static int parse_source_files(const char *objfile, struct md4_ctx *md)
> +{
> +	char *cmd, *file, *p, *end;
> +	const char *base;
> +	unsigned long flen;
> +	int dirlen, ret = 0;
> +
> +	cmd = malloc(strlen(objfile) + sizeof("..cmd"));

You miss a "+ 1" to count for trailing '\0'.

> +
> +	base = strrchr(objfile, '/');
> +	if (base) {
> +		base++;
> +		dirlen = base - objfile;
> +		sprintf(cmd, "%.*s.%s.cmd", dirlen, objfile, base);
> +	} else {
> +		dirlen = 0;
> +		sprintf(cmd, ".%s.cmd", objfile);
> +	}
> +
> +	file = grab_file(cmd, &flen);
> +	if (!file) {
> +		fprintf(stderr, "Warning: could not find %s for %s\n",
> +			cmd, objfile);
> +		goto out;
> +	}
> +
> +	/* There will be a line like so:
> +		deps_drivers/net/dummy.o := \
> +		  drivers/net/dummy.c \
> +		    $(wildcard include/config/net/fastroute.h) \
> +		  include/linux/config.h \
> +		    $(wildcard include/config/h.h) \
> +		  include/linux/module.h \
> +
> +	   Sum all files in the same dir or subdirs.
> +	*/
> +	/* Strictly illegal: file is not nul terminated. */
> +	p = strstr(file, "\ndeps_");
> +	if (!p) {
> +		fprintf(stderr, "Warning: could not find deps_ line in %s\n",
> +			cmd);
> +		goto out_file;
> +	}
> +	p = strstr(p, ":=");
> +	if (!p) {
> +		fprintf(stderr, "Warning: could not find := line in %s\n",
> +			cmd);
> +		goto out_file;
> +	}
> +	p += strlen(":=");
> +	p += strspn(p, " \\\n");
> +
> +	end = strstr(p, "\n\n");
> +	if (!end) {
> +		fprintf(stderr, "Warning: could not find end line in %s\n",
> +			cmd);
> +		goto out_file;
> +	}
> +
> +	while (p < end) {
> +		unsigned int len;
> +
> +		len = strcspn(p, " \\\n");
> +		if (memcmp(objfile, p, dirlen) == 0) {
> +			char source[len + 1];
gcc extension, you do not want to use malloc here?

> +
> +			memcpy(source, p, len);
> +			source[len] = '\0';
> +			printf("parsing %s\n", source);
Debug printf - to be deleted.

> +			if (!parse_file(source, md)) {
> +				fprintf(stderr,
> +					"Warning: could not open %s: %s\n",
> +					source, strerror(errno));
> +				goto out_file;
> +			}
> +		}
> +		p += len;
> +		p += strspn(p, " \\\n");
> +	}
> +
> +	/* Everyone parsed OK */
> +	ret = 1;
> +out_file:
> +	release_file(file, flen);
> +out:
> +	free(cmd);
> +	return ret;
> +}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-02-25 21:36                   ` Sam Ravnborg
@ 2004-02-26  1:50                     ` Rusty Russell
  2004-02-26  7:12                       ` Sam Ravnborg
  0 siblings, 1 reply; 14+ messages in thread
From: Rusty Russell @ 2004-02-26  1:50 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: Brian King, akpm, linux-kernel

In message <20040225213659.GA9985@mars.ravnborg.org> you write:
> Hi Rusty.
> 
> I have not yet fully understood why you want to parse every source file.
> I can see in the implemntation that you only calculate the sum of
> code-lines, and not comments.
> But why do we want to add this complexity - compared to just
> calculating the sum of the whole file?
> If the calculated sum is being presented as based on the source code
> I assume people can understand that the sum does not match even after
> updating a comment.

The strongest example is that Andrew Morton always "fixes" whitespace
as patches go through his tree.  It's about 50 lines of code, and it's
not slow (but has definite room for optimization).

> The current implementation fails to locate include files in the local
> directory when compiled using "make O=...".

There's no documentation I could find for "O=", BTW.  I'm not even
sure what it does...

> This is due to the fact that some files are present in the _deps
> file with full path, others with relative path.

Right. 8(

> My next question. Since we only parse a subset of the headers, is it
> really needed to parse any of them?
> My thinking is that we should either:
> a) parse all header files (except those marked with $(wildcard))
> b) parse no header files.

I was thinking of the driver author.  Driver consists of three .c
files, and a local .h file.  They want to catch anyone touching any of
these files.  But they don't want the sum to change just because
someone adds a new inline function to linux/kernel.h.

If it's impractical, we can just skip all the headers.  But it would
be a real loss.

> > +	cmd = malloc(strlen(objfile) + sizeof("..cmd"));
> 
> You miss a "+ 1" to count for trailing '\0'.

Um, sizeof() vs strlen().

> > +		len = strcspn(p, " \\\n");
> > +		if (memcmp(objfile, p, dirlen) == 0) {
> > +			char source[len + 1];
> gcc extension, you do not want to use malloc here?

Yeah, I love GCC.  It's also in ISO C, BTW.

> > +			printf("parsing %s\n", source);
> Debug printf - to be deleted.

Ack.

Thanks!
Rusty.
--
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-02-26  1:50                     ` Rusty Russell
@ 2004-02-26  7:12                       ` Sam Ravnborg
  0 siblings, 0 replies; 14+ messages in thread
From: Sam Ravnborg @ 2004-02-26  7:12 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Sam Ravnborg, Brian King, akpm, linux-kernel

On Thu, Feb 26, 2004 at 12:50:37PM +1100, Rusty Russell wrote:
> > The current implementation fails to locate include files in the local
> > directory when compiled using "make O=...".
> 
> There's no documentation I could find for "O=", BTW.  I'm not even
> sure what it does...
Check README in the kernel src.
Specify the output directory, allowing you to compile from RO media,
or just to have several kernel configs based on same src tree.

	Sam

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-01-20  1:17   ` Greg KH
  2004-01-20  7:47     ` Rusty Russell
@ 2004-03-10 20:49     ` Brian King
  2004-03-10 21:08       ` Greg KH
  1 sibling, 1 reply; 14+ messages in thread
From: Brian King @ 2004-03-10 20:49 UTC (permalink / raw)
  To: Greg KH
  Cc: Rusty Russell, Mike Anderson, linux-kernel, Christoph Hellwig,
	kai, sam, akpm

Looks like the MODULE_VERSION macro is now in the tree.
Greg, any status on the sysfs patch you mention below?

thanks,

Brian


Greg KH wrote:
> On Tue, Jan 20, 2004 at 11:57:38AM +1100, Rusty Russell wrote:
> 
>>In message <20040119214233.GF967@beaverton.ibm.com> you write:
>>
>>>Rusty,
>>>	Christoph mentioned that a MODULE_VERSION macro may be pending.
>>
>>Hey, thanks Christoph for the reminder.  I stopped when we were
>>frozen.
>>
>>This still seems to apply.  Do people think this is huge overkill, or
>>a work of obvious beauty and genius?
> 
> 
> Looks sane.  I'm guessing that modinfo can show this?
> 
> 
>>Doesn't put things in sysfs, but Greg was working on that for module
>>parameters... Greg?
> 
> 
> Oh yeah, I'll dig out that patch later this week.  An older version has
> been sitting in my bk tree forever, need to update it with the last
> changes you sent me.
> 
> thanks,
> 
> greg k-h
> 


-- 
Brian King
eServer Storage I/O
IBM Linux Technology Center


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Question on MODULE_VERSION macro
  2004-03-10 20:49     ` Brian King
@ 2004-03-10 21:08       ` Greg KH
  0 siblings, 0 replies; 14+ messages in thread
From: Greg KH @ 2004-03-10 21:08 UTC (permalink / raw)
  To: Brian King
  Cc: Rusty Russell, Mike Anderson, linux-kernel, Christoph Hellwig,
	kai, sam, akpm

On Wed, Mar 10, 2004 at 02:49:24PM -0600, Brian King wrote:
> Looks like the MODULE_VERSION macro is now in the tree.
> Greg, any status on the sysfs patch you mention below?

Already posted to lkml a week or so ago, and Rusty responded back with a
different patch.  I'll get to his response hopefully by the end of the
week...

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2004-03-10 21:13 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20040119214233.GF967@beaverton.ibm.com>
2004-01-20  0:57 ` Question on MODULE_VERSION macro Rusty Russell
2004-01-20  1:17   ` Greg KH
2004-01-20  7:47     ` Rusty Russell
2004-02-20 21:44       ` Brian King
2004-02-21  1:07         ` Rusty Russell
2004-02-22 23:23           ` Sam Ravnborg
2004-02-23  3:51             ` Rusty Russell
2004-02-23 21:17               ` Sam Ravnborg
2004-02-24  6:13                 ` Rusty Russell
2004-02-25 21:36                   ` Sam Ravnborg
2004-02-26  1:50                     ` Rusty Russell
2004-02-26  7:12                       ` Sam Ravnborg
2004-03-10 20:49     ` Brian King
2004-03-10 21:08       ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).