From 943bca8c7206f8d34038f04da1d534d8f66c3944 Mon Sep 17 00:00:00 2001
From: scjody <scjody>
Date: Tue, 20 Nov 2007 20:41:06 +0000
Subject: [PATCH] Branch b1_6

Improved support for dependencies between external modules: add a patch to
SLES 9 and RHEL 4 to modernize their module symbol handling, and copy the
symbol version file around to use this information properly.

b=12842
i=johann
i=zhenyu.xu
---
 lustre/autoconf/lustre-core.m4                | 170 +++++----
 ...odpost_external_module_updates_rhel4.patch | 347 ++++++++++++++++++
 ...odpost_external_module_updates_sles9.patch | 338 +++++++++++++++++
 lustre/kernel_patches/series/2.6-rhel4.series |   1 +
 .../series/2.6-suse-newer.series              |   1 +
 5 files changed, 779 insertions(+), 78 deletions(-)
 create mode 100644 lustre/kernel_patches/patches/modpost_external_module_updates_rhel4.patch
 create mode 100644 lustre/kernel_patches/patches/modpost_external_module_updates_sles9.patch

diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4
index c01c974623..e1e4eb6cf7 100644
--- a/lustre/autoconf/lustre-core.m4
+++ b/lustre/autoconf/lustre-core.m4
@@ -793,6 +793,18 @@ LB_LINUX_TRY_COMPILE([
 ])
 ])
 
+# LC_SYMVERFILE
+# SLES 9 uses a different name for this file - unsure about vanilla kernels
+# around this version, but it matters for servers only.
+AC_DEFUN([LC_SYMVERFILE],
+         [AC_MSG_CHECKING([name of symverfile])
+          if grep -q Modules.symvers $LINUX/scripts/Makefile.modpost ; then
+              SYMVERFILE=Modules.symvers
+          else
+              SYMVERFILE=Module.symvers
+          fi
+	  AC_MSG_RESULT($SYMVERFILE)
+          AC_SUBST(SYMVERFILE)])
 
 # LC_DQUOTOFF_MUTEX
 # after 2.6.17 dquote use mutex instead if semaphore
@@ -1145,84 +1157,86 @@ LB_LINUX_TRY_COMPILE([
 # Lustre linux kernel checks
 #
 AC_DEFUN([LC_PROG_LINUX],
-[ LC_LUSTRE_VERSION_H
-if test x$enable_server = xyes ; then
-        LC_CONFIG_BACKINGFS
-fi
-LC_CONFIG_PINGER
-LC_CONFIG_CHECKSUM
-LC_CONFIG_LIBLUSTRE_RECOVERY
-LC_CONFIG_QUOTA
-LC_CONFIG_HEALTH_CHECK_WRITE
-LC_CONFIG_LRU_RESIZE
-
-LC_TASK_PPTR
-# RHEL4 patches
-LC_EXPORT_TRUNCATE_COMPLETE
-LC_EXPORT_D_REHASH_COND
-LC_EXPORT___D_REHASH
-LC_EXPORT_NODE_TO_CPUMASK
-
-LC_STRUCT_KIOBUF
-LC_FUNC_COND_RESCHED
-LC_FUNC_ZAP_PAGE_RANGE
-LC_FUNC_PDE
-LC_FUNC_DIRECT_IO
-LC_HEADER_MM_INLINE
-LC_STRUCT_INODE
-LC_FUNC_REGISTER_CACHE
-LC_FUNC_GRAB_CACHE_PAGE_NOWAIT_GFP
-LC_FUNC_DEV_SET_RDONLY
-LC_FUNC_FILEMAP_FDATAWRITE
-LC_STRUCT_STATFS
-LC_FUNC_PAGE_MAPPED
-LC_STRUCT_FILE_OPS_UNLOCKED_IOCTL
-LC_FILEMAP_POPULATE
-LC_D_ADD_UNIQUE
-LC_BIT_SPINLOCK_H
-LC_XATTR_ACL
-LC_STRUCT_INTENT_FILE
-LC_POSIX_ACL_XATTR_H
-LC_EXPORT___IGET
-LC_FUNC_SET_FS_PWD
-LC_FUNC_MS_FLOCK_LOCK
-LC_FUNC_HAVE_CAN_SLEEP_ARG
-LC_FUNC_F_OP_FLOCK
-LC_QUOTA_READ
-LC_COOKIE_FOLLOW_LINK
-LC_FUNC_RCU
-
-# does the kernel have VFS intent patches?
-LC_VFS_INTENT_PATCHES
-
-# 2.6.15
-LC_INODE_I_MUTEX
-
-# 2.6.17
-LC_DQUOTOFF_MUTEX
-
-# 2.6.18
-LC_NR_PAGECACHE
-LC_STATFS_DENTRY_PARAM
-LC_VFS_KERN_MOUNT
-LC_INVALIDATEPAGE_RETURN_INT
-LC_UMOUNTBEGIN_HAS_VFSMOUNT
-
-#2.6.18 + RHEL5 (fc6)
-LC_PG_FS_MISC
-
-# 2.6.19
-LC_INODE_BLKSIZE
-LC_VFS_READDIR_U64_INO
-LC_GENERIC_FILE_READ
-LC_GENERIC_FILE_WRITE
-
-# 2.6.20
-LC_CANCEL_DIRTY_PAGE
-
-# raid5-zerocopy patch
-LC_PAGE_CONSTANT
-])
+         [LC_LUSTRE_VERSION_H
+          if test x$enable_server = xyes ; then
+              LC_CONFIG_BACKINGFS
+          fi
+          LC_CONFIG_PINGER
+          LC_CONFIG_CHECKSUM
+          LC_CONFIG_LIBLUSTRE_RECOVERY
+          LC_CONFIG_QUOTA
+          LC_CONFIG_HEALTH_CHECK_WRITE
+          LC_CONFIG_LRU_RESIZE
+
+          LC_TASK_PPTR
+          # RHEL4 patches
+          LC_EXPORT_TRUNCATE_COMPLETE
+          LC_EXPORT_D_REHASH_COND
+          LC_EXPORT___D_REHASH
+          LC_EXPORT_NODE_TO_CPUMASK
+
+          LC_STRUCT_KIOBUF
+          LC_FUNC_COND_RESCHED
+          LC_FUNC_ZAP_PAGE_RANGE
+          LC_FUNC_PDE
+          LC_FUNC_DIRECT_IO
+          LC_HEADER_MM_INLINE
+          LC_STRUCT_INODE
+          LC_FUNC_REGISTER_CACHE
+          LC_FUNC_GRAB_CACHE_PAGE_NOWAIT_GFP
+          LC_FUNC_DEV_SET_RDONLY
+          LC_FUNC_FILEMAP_FDATAWRITE
+          LC_STRUCT_STATFS
+          LC_FUNC_PAGE_MAPPED
+          LC_STRUCT_FILE_OPS_UNLOCKED_IOCTL
+          LC_FILEMAP_POPULATE
+          LC_D_ADD_UNIQUE
+          LC_BIT_SPINLOCK_H
+          LC_XATTR_ACL
+          LC_STRUCT_INTENT_FILE
+          LC_POSIX_ACL_XATTR_H
+          LC_EXPORT___IGET
+          LC_FUNC_SET_FS_PWD
+          LC_FUNC_MS_FLOCK_LOCK
+          LC_FUNC_HAVE_CAN_SLEEP_ARG
+          LC_FUNC_F_OP_FLOCK
+          LC_QUOTA_READ
+          LC_COOKIE_FOLLOW_LINK
+          LC_FUNC_RCU
+
+          # does the kernel have VFS intent patches?
+          LC_VFS_INTENT_PATCHES
+
+          # 2.6.15
+          LC_INODE_I_MUTEX
+
+          # SLES 10 (at least)
+          LC_SYMVERFILE
+
+          # 2.6.17
+          LC_DQUOTOFF_MUTEX
+
+          # 2.6.18
+          LC_NR_PAGECACHE
+          LC_STATFS_DENTRY_PARAM
+          LC_VFS_KERN_MOUNT
+          LC_INVALIDATEPAGE_RETURN_INT
+          LC_UMOUNTBEGIN_HAS_VFSMOUNT
+
+          #2.6.18 + RHEL5 (fc6)
+          LC_PG_FS_MISC
+
+          # 2.6.19
+          LC_INODE_BLKSIZE
+          LC_VFS_READDIR_U64_INO
+          LC_GENERIC_FILE_READ
+          LC_GENERIC_FILE_WRITE
+
+          # 2.6.20
+          LC_CANCEL_DIRTY_PAGE
+
+          # raid5-zerocopy patch
+          LC_PAGE_CONSTANT])
 
 #
 # LC_CONFIG_CLIENT_SERVER
diff --git a/lustre/kernel_patches/patches/modpost_external_module_updates_rhel4.patch b/lustre/kernel_patches/patches/modpost_external_module_updates_rhel4.patch
new file mode 100644
index 0000000000..9fdfe79bec
--- /dev/null
+++ b/lustre/kernel_patches/patches/modpost_external_module_updates_rhel4.patch
@@ -0,0 +1,347 @@
+Index: linux-2.6.9-55.EL/scripts/Makefile.modpost
+===================================================================
+--- linux-2.6.9-55.EL.orig/scripts/Makefile.modpost
++++ linux-2.6.9-55.EL/scripts/Makefile.modpost
+@@ -38,7 +38,8 @@ _modpost: __modpost
+ include .config
+ include scripts/Makefile.lib
+ 
+-symverfile := $(objtree)/Module.symvers
++kernelsymfile := $(objtree)/Module.symvers
++modulesymfile := $(KBUILD_EXTMOD)/Module.symvers
+ 
+ # Step 1), find all modules listed in $(MODVERDIR)/
+ __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
+@@ -52,7 +53,9 @@ _modpost: $(modules)
+ quiet_cmd_modpost = MODPOST
+       cmd_modpost = scripts/mod/modpost            \
+         $(if $(CONFIG_MODVERSIONS),-m)             \
+-	$(if $(KBUILD_EXTMOD),-i,-o) $(symverfile) \
++ 	$(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
++ 	$(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
++ 	$(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
+ 	$(filter-out FORCE,$^)
+ 
+ .PHONY: __modpost
+Index: linux-2.6.9-55.EL/scripts/mod/modpost.c
+===================================================================
+--- linux-2.6.9-55.EL.orig/scripts/mod/modpost.c
++++ linux-2.6.9-55.EL/scripts/mod/modpost.c
+@@ -1,7 +1,8 @@
+ /* Postprocess module symbol versions
+  *
+  * Copyright 2003       Kai Germaschewski
+- *           2002-2003  Rusty Russell, IBM Corporation
++ *           2002-2004  Rusty Russell, IBM Corporation
++ * Copyright 2006       Sam Ravnborg
+  *
+  * Based in part on module-init-tools/depmod.c,file2alias
+  *
+@@ -18,6 +19,8 @@
+ int modversions = 0;
+ /* Warn about undefined symbols? (do so if we have vmlinux) */
+ int have_vmlinux = 0;
++/* If we are modposting external module set to 1 */
++static int external_module = 0;
+ 
+ void
+ fatal(const char *fmt, ...)
+@@ -45,6 +48,19 @@ warn(const char *fmt, ...)
+ 	va_end(arglist);
+ }
+ 
++int
++is_vmlinux(const char *modname)
++{
++	const char *myname;
++
++	if ((myname = strrchr(modname, '/')))
++		myname++;
++	else
++		myname = modname;
++
++	return strcmp(myname, "vmlinux") == 0;
++}
++
+ void *do_nofail(void *ptr, const char *file, int line, const char *expr)
+ {
+ 	if (!ptr) {
+@@ -102,6 +118,10 @@ struct symbol {
+ 	struct module *module;
+ 	unsigned int crc;
+ 	int crc_valid;
++	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
++	unsigned int kernel:1;     /* 1 if symbol is from kernel
++				    *  (only for external modules) **/
++	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers */
+ 	char name[0];
+ };
+ 
+@@ -136,8 +156,8 @@ alloc_symbol(const char *name, struct sy
+ 
+ /* For the hash of exported symbols */
+ 
+-void
+-new_symbol(const char *name, struct module *module, unsigned int *crc)
++static struct symbol *
++new_symbol(const char *name, struct module *module)
+ {
+ 	unsigned int hash;
+ 	struct symbol *new;
+@@ -145,10 +165,7 @@ new_symbol(const char *name, struct modu
+ 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
+ 	new = symbolhash[hash] = alloc_symbol(name, symbolhash[hash]);
+ 	new->module = module;
+-	if (crc) {
+-		new->crc = *crc;
+-		new->crc_valid = 1;
+-	}
++	return new;
+ }
+ 
+ struct symbol *
+@@ -169,19 +186,29 @@ find_symbol(const char *name)
+ 
+ /* Add an exported symbol - it may have already been added without a
+  * CRC, in this case just update the CRC */
+-void
+-add_exported_symbol(const char *name, struct module *module, unsigned int *crc)
++static struct symbol *
++sym_add_exported(const char *name, struct module *mod)
+ {
+ 	struct symbol *s = find_symbol(name);
+ 
+ 	if (!s) {
+-		new_symbol(name, module, crc);
+-		return;
+-	}
+-	if (crc) {
+-		s->crc = *crc;
+-		s->crc_valid = 1;
++		s = new_symbol(name, mod);
+ 	}
++	s->preloaded = 0;
++	s->vmlinux   = is_vmlinux(mod->name);
++	s->kernel    = 0;
++	return s;
++}
++
++static void
++sym_update_crc(const char *name, struct module *mod, unsigned int crc)
++{
++	struct symbol *s = find_symbol(name);
++
++	if (!s)
++		s = new_symbol(name, mod);
++	s->crc = crc;
++	s->crc_valid = 1;
+ }
+ 
+ void *
+@@ -341,13 +368,13 @@ handle_modversions(struct module *mod, s
+ 		/* CRC'd symbol */
+ 		if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
+ 			crc = (unsigned int) sym->st_value;
+-			add_exported_symbol(symname + strlen(CRC_PFX),
+-					    mod, &crc);
++			sym_update_crc(symname + strlen(CRC_PFX), mod, crc);
+ 		}
+ 		break;
+ 	case SHN_UNDEF:
+ 		/* undefined symbol */
+-		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL)
++		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
++		    ELF_ST_BIND(sym->st_info) != STB_WEAK)
+ 			break;
+ 		/* ignore global offset table */
+ 		if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
+@@ -373,8 +400,7 @@ handle_modversions(struct module *mod, s
+ 	default:
+ 		/* All exported symbols */
+ 		if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
+-			add_exported_symbol(symname + strlen(KSYMTAB_PFX),
+-					    mod, NULL);
++			sym_add_exported(symname + strlen(KSYMTAB_PFX), mod);
+ 		}
+ 		if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
+ 			mod->has_init = 1;
+@@ -384,19 +410,6 @@ handle_modversions(struct module *mod, s
+ 	}
+ }
+ 
+-int
+-is_vmlinux(const char *modname)
+-{
+-	const char *myname;
+-
+-	if ((myname = strrchr(modname, '/')))
+-		myname++;
+-	else
+-		myname = modname;
+-
+-	return strcmp(myname, "vmlinux") == 0;
+-}
+-
+ void
+ read_symbols(char *modname)
+ {
+@@ -412,9 +425,7 @@ read_symbols(char *modname)
+ 	/* When there's no vmlinux, don't print warnings about
+ 	 * unresolved symbols (since there'll be too many ;) */
+ 	if (is_vmlinux(modname)) {
+-		unsigned int fake_crc = 0;
+ 		have_vmlinux = 1;
+-		add_exported_symbol("struct_module", mod, &fake_crc);
+ 		mod->skip = 1;
+ 	}
+ 
+@@ -426,6 +437,7 @@ read_symbols(char *modname)
+ 	}
+ 	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
+@@ -451,12 +463,7 @@ buf_printf(struct buffer *buf, const cha
+ 	
+ 	va_start(ap, fmt);
+ 	len = vsnprintf(tmp, SZ, fmt, ap);
+-	if (buf->size - buf->pos < len + 1) {
+-		buf->size += 128;
+-		buf->p = realloc(buf->p, buf->size);
+-	}
+-	strncpy(buf->p + buf->pos, tmp, len + 1);
+-	buf->pos += len;
++	buf_write(buf, tmp, len);
+ 	va_end(ap);
+ }
+ 
+@@ -464,7 +471,7 @@ void
+ buf_write(struct buffer *buf, const char *s, int len)
+ {
+ 	if (buf->size - buf->pos < len) {
+-		buf->size += len;
++		buf->size += len + SZ;
+ 		buf->p = realloc(buf->p, buf->size);
+ 	}
+ 	strncpy(buf->p + buf->pos, s, len);
+@@ -506,8 +513,8 @@ add_versions(struct buffer *b, struct mo
+ 		exp = find_symbol(s->name);
+ 		if (!exp || exp->module == mod) {
+ 			if (have_vmlinux)
+-				fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
+-				"undefined!\n",	s->name, mod->name);
++				warn("\"%s\" [%s.ko] undefined!\n",
++				     s->name, mod->name);
+ 			continue;
+ 		}
+ 		s->module = exp->module;
+@@ -615,8 +622,11 @@ write_if_changed(struct buffer *b, const
+ 	fclose(file);
+ }
+ 
++/* parse Module.symvers file. line format:
++ * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
++ **/
+ void
+-read_dump(const char *fname)
++read_dump(const char *fname, unsigned int kernel)
+ {
+ 	unsigned long size, pos = 0;
+ 	void *file = grab_file(fname, &size);
+@@ -630,6 +640,7 @@ read_dump(const char *fname)
+ 		char *symname, *modname, *d;
+ 		unsigned int crc;
+ 		struct module *mod;
++                struct symbol *s;
+ 
+ 		if (!(symname = strchr(line, '\t')))
+ 			goto fail;
+@@ -650,13 +661,30 @@ read_dump(const char *fname)
+ 			mod = new_module(NOFAIL(strdup(modname)));
+ 			mod->skip = 1;
+ 		}
+-		add_exported_symbol(symname, mod, &crc);
++                s = sym_add_exported(symname, mod);
++		s->kernel    = kernel;
++		s->preloaded = 1;
++		sym_update_crc(symname, mod, crc);
+ 	}
+ 	return;
+ fail:
+ 	fatal("parse error in symbol dump file\n");
+ }
+ 
++/* For normal builds always dump all symbols.
++ * For external modules only dump symbols
++ * that are not read from kernel Module.symvers.
++ **/
++static int
++dump_sym(struct symbol *sym)
++{
++	if (!external_module)
++		return 1;
++	if (sym->vmlinux || sym->kernel)
++		return 0;
++	return 1;
++}
++
+ void
+ write_dump(const char *fname)
+ {
+@@ -667,15 +695,10 @@ write_dump(const char *fname)
+ 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
+ 		symbol = symbolhash[n];
+ 		while (symbol) {
+-			symbol = symbol->next;
+-		}
+-	}
+-
+-	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
+-		symbol = symbolhash[n];
+-		while (symbol) {
+-			buf_printf(&buf, "0x%08x\t%s\t%s\n", symbol->crc,
+-				symbol->name, symbol->module->name);
++			if (dump_sym(symbol))
++				buf_printf(&buf, "0x%08x\t%s\t%s\n",
++					symbol->crc, symbol->name,
++					symbol->module->name);
+ 			symbol = symbol->next;
+ 		}
+ 	}
+@@ -688,13 +711,18 @@ main(int argc, char **argv)
+ 	struct module *mod;
+ 	struct buffer buf = { };
+ 	char fname[SZ];
+-	char *dump_read = NULL, *dump_write = NULL;
++	char *kernel_read = NULL, *module_read = NULL;
++	char *dump_write = NULL;
+ 	int opt;
+ 
+-	while ((opt = getopt(argc, argv, "i:mo:")) != -1) {
++	while ((opt = getopt(argc, argv, "i:I:mo:")) != -1) {
+ 		switch(opt) {
+ 			case 'i':
+-				dump_read = optarg;
++				kernel_read = optarg;
++				break;
++			case 'I':
++				module_read = optarg;
++				external_module = 1;
+ 				break;
+ 			case 'm':
+ 				modversions = 1;
+@@ -707,8 +735,10 @@ main(int argc, char **argv)
+ 		}
+ 	}
+ 
+-	if (dump_read)
+-		read_dump(dump_read);
++	if (kernel_read)
++		read_dump(kernel_read, 1);
++	if (module_read)
++		read_dump(module_read, 0);
+ 
+ 	while (optind < argc) {
+ 		read_symbols(argv[optind++]);
diff --git a/lustre/kernel_patches/patches/modpost_external_module_updates_sles9.patch b/lustre/kernel_patches/patches/modpost_external_module_updates_sles9.patch
new file mode 100644
index 0000000000..9ca07650ca
--- /dev/null
+++ b/lustre/kernel_patches/patches/modpost_external_module_updates_sles9.patch
@@ -0,0 +1,338 @@
+Index: linux-2.6.5-7.286/scripts/Makefile.modpost
+===================================================================
+--- linux-2.6.5-7.286.orig/scripts/Makefile.modpost
++++ linux-2.6.5-7.286/scripts/Makefile.modpost
+@@ -38,7 +38,8 @@ _modpost: __modpost
+ include .config
+ include scripts/Makefile.lib
+ 
+-symverfile := $(objtree)/Module.symvers
++kernelsymfile := $(objtree)/Module.symvers
++modulesymfile := $(KBUILD_EXTMOD)/Module.symvers
+ 
+ # Step 1), find all modules listed in $(MODVERDIR)/
+ __modules := $(shell head -q -n1 /dev/null $(wildcard $(MODVERDIR)/*.mod))
+@@ -51,7 +52,9 @@ _modpost: $(modules)
+ #  Includes step 3,4
+ quiet_cmd_modpost = MODPOST
+       cmd_modpost = scripts/modpost \
+-	$(if $(KBUILD_EXTMOD),-i,-o) $(symverfile) \
++ 	$(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
++ 	$(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
++ 	$(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
+ 	-s $(firstword $(wildcard $(dir $(MODVERDIR))/Module.supported \
+ 				  $(objtree)/Module.supported /dev/null)) \
+ 	$(filter-out FORCE,$^)
+Index: linux-2.6.5-7.286/scripts/modpost.c
+===================================================================
+--- linux-2.6.5-7.286.orig/scripts/modpost.c
++++ linux-2.6.5-7.286/scripts/modpost.c
+@@ -1,7 +1,8 @@
+ /* Postprocess module symbol versions
+  *
+  * Copyright 2003       Kai Germaschewski
+- *           2002-2003  Rusty Russell, IBM Corporation
++ *           2002-2004  Rusty Russell, IBM Corporation
++ * Copyright 2006       Sam Ravnborg
+  *
+  * Based in part on module-init-tools/depmod.c,file2alias
+  *
+@@ -18,6 +19,8 @@
+ int modversions = 0;
+ /* Warn about undefined symbols? (do so if we have vmlinux) */
+ int have_vmlinux = 0;
++/* If we are modposting external module set to 1 */
++static int external_module = 0;
+ 
+ void
+ fatal(const char *fmt, ...)
+@@ -45,6 +48,19 @@ warn(const char *fmt, ...)
+ 	va_end(arglist);
+ }
+ 
++int
++is_vmlinux(const char *modname)
++{
++	const char *myname;
++
++	if ((myname = strrchr(modname, '/')))
++		myname++;
++	else
++		myname = modname;
++
++	return strcmp(myname, "vmlinux") == 0;
++}
++
+ void *do_nofail(void *ptr, const char *expr)
+ {
+ 	if (!ptr) {
+@@ -101,6 +117,9 @@ struct symbol {
+ 	struct module *module;
+ 	unsigned int crc;
+ 	int crc_valid;
++	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
++	unsigned int kernel:1;     /* 1 if symbol is from kernel
++				    *  (only for external modules) **/
+ 	char name[0];
+ };
+ 
+@@ -135,8 +154,8 @@ alloc_symbol(const char *name, struct sy
+ 
+ /* For the hash of exported symbols */
+ 
+-void
+-new_symbol(const char *name, struct module *module, unsigned int *crc)
++static struct symbol *
++new_symbol(const char *name, struct module *module)
+ {
+ 	unsigned int hash;
+ 	struct symbol *new;
+@@ -144,10 +163,7 @@ new_symbol(const char *name, struct modu
+ 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
+ 	new = symbolhash[hash] = alloc_symbol(name, symbolhash[hash]);
+ 	new->module = module;
+-	if (crc) {
+-		new->crc = *crc;
+-		new->crc_valid = 1;
+-	}
++	return new;
+ }
+ 
+ struct symbol *
+@@ -168,19 +184,28 @@ find_symbol(const char *name)
+ 
+ /* Add an exported symbol - it may have already been added without a
+  * CRC, in this case just update the CRC */
+-void
+-add_exported_symbol(const char *name, struct module *module, unsigned int *crc)
++static struct symbol *
++sym_add_exported(const char *name, struct module *mod)
+ {
+ 	struct symbol *s = find_symbol(name);
+ 
+ 	if (!s) {
+-		new_symbol(name, module, crc);
+-		return;
+-	}
+-	if (crc) {
+-		s->crc = *crc;
+-		s->crc_valid = 1;
++		s = new_symbol(name, mod);
+ 	}
++	s->vmlinux   = is_vmlinux(mod->name);
++	s->kernel    = 0;
++	return s;
++}
++
++static void
++sym_update_crc(const char *name, struct module *mod, unsigned int crc)
++{
++	struct symbol *s = find_symbol(name);
++
++	if (!s)
++		s = new_symbol(name, mod);
++	s->crc = crc;
++	s->crc_valid = 1;
+ }
+ 
+ void *
+@@ -339,8 +364,7 @@ handle_modversions(struct module *mod, s
+ 		/* CRC'd symbol */
+ 		if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
+ 			crc = (unsigned int) sym->st_value;
+-			add_exported_symbol(symname + strlen(CRC_PFX),
+-					    mod, &crc);
++			sym_update_crc(symname + strlen(CRC_PFX), mod, crc);
+ 			modversions = 1;
+ 		}
+ 		break;
+@@ -372,26 +396,12 @@ handle_modversions(struct module *mod, s
+ 	default:
+ 		/* All exported symbols */
+ 		if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
+-			add_exported_symbol(symname + strlen(KSYMTAB_PFX),
+-					    mod, NULL);
++			sym_add_exported(symname + strlen(KSYMTAB_PFX), mod);
+ 		}
+ 		break;
+ 	}
+ }
+ 
+-int
+-is_vmlinux(const char *modname)
+-{
+-	const char *myname;
+-
+-	if ((myname = strrchr(modname, '/')))
+-		myname++;
+-	else
+-		myname = modname;
+-
+-	return strcmp(myname, "vmlinux") == 0;
+-}
+-
+ static struct {
+ 	void *file;
+ 	unsigned long size;
+@@ -451,12 +461,7 @@ read_symbols(char *modname)
+ 	/* When there's no vmlinux, don't print warnings about
+ 	 * unresolved symbols (since there'll be too many ;) */
+ 	if (is_vmlinux(modname)) {
+-		unsigned int fake_crc = 0;
+ 		have_vmlinux = 1;
+-		/* May not have this if !CONFIG_MODULE_UNLOAD: fake it.
+-		   If it appears, we'll get the real CRC. */
+-		add_exported_symbol("cleanup_module", mod, &fake_crc);
+-		add_exported_symbol("struct_module", mod, &fake_crc);
+ 		mod->skip = 1;
+ 	}
+ 
+@@ -499,12 +504,7 @@ buf_printf(struct buffer *buf, const cha
+ 	
+ 	va_start(ap, fmt);
+ 	len = vsnprintf(tmp, SZ, fmt, ap);
+-	if (buf->size - buf->pos < len + 1) {
+-		buf->size += 128;
+-		buf->p = realloc(buf->p, buf->size);
+-	}
+-	strncpy(buf->p + buf->pos, tmp, len + 1);
+-	buf->pos += len;
++	buf_write(buf, tmp, len);
+ 	va_end(ap);
+ }
+ 
+@@ -512,7 +512,7 @@ void
+ buf_write(struct buffer *buf, const char *s, int len)
+ {
+ 	if (buf->size - buf->pos < len) {
+-		buf->size += len;
++		buf->size += len + SZ;
+ 		buf->p = realloc(buf->p, buf->size);
+ 	}
+ 	strncpy(buf->p + buf->pos, s, len);
+@@ -522,7 +522,7 @@ buf_write(struct buffer *buf, const char
+ /* Header for the generated file */
+ 
+ void
+-add_header(struct buffer *b)
++add_header(struct buffer *b, struct module *mod)
+ {
+ 	buf_printf(b, "#include <linux/module.h>\n");
+ 	buf_printf(b, "#include <linux/vermagic.h>\n");
+@@ -676,8 +676,11 @@ read_supported(const char *fname)
+ 		; /* ignore error */
+ }
+ 
++/* parse Module.symvers file. line format:
++ * 0x12345678<tab>symbol<tab>module[<tab>something]
++ **/
+ void
+-read_dump(const char *fname)
++read_dump(const char *fname, unsigned int kernel)
+ {
+ 	unsigned long size, pos = 0;
+ 	void *file = grab_file(fname, &size);
+@@ -691,6 +694,7 @@ read_dump(const char *fname)
+ 		char *symname, *modname, *d;
+ 		unsigned int crc;
+ 		struct module *mod;
++                struct symbol *s;
+ 
+ 		if (!(symname = strchr(line, '\t')))
+ 			goto fail;
+@@ -712,13 +716,29 @@ read_dump(const char *fname)
+ 			mod = new_module(NOFAIL(strdup(modname)));
+ 			mod->skip = 1;
+ 		}
+-		add_exported_symbol(symname, mod, &crc);
++                s = sym_add_exported(symname, mod);
++		s->kernel    = kernel;
++		sym_update_crc(symname, mod, crc);
+ 	}
+ 	return;
+ fail:
+ 	fatal("parse error in symbol dump file\n");
+ }
+ 
++/* For normal builds always dump all symbols.
++ * For external modules only dump symbols
++ * that are not read from kernel Module.symvers.
++ **/
++static int
++dump_sym(struct symbol *sym)
++{
++	if (!external_module)
++		return 1;
++	if (sym->vmlinux || sym->kernel)
++		return 0;
++	return 1;
++}
++
+ void
+ write_dump(const char *fname)
+ {
+@@ -729,15 +749,10 @@ write_dump(const char *fname)
+ 	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
+ 		symbol = symbolhash[n];
+ 		while (symbol) {
+-			symbol = symbol->next;
+-		}
+-	}
+-
+-	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
+-		symbol = symbolhash[n];
+-		while (symbol) {
+-			buf_printf(&buf, "0x%08x\t%s\t%s\n", symbol->crc,
+-				symbol->name, symbol->module->name);
++			if (dump_sym(symbol))
++				buf_printf(&buf, "0x%08x\t%s\t%s\n",
++					symbol->crc, symbol->name,
++					symbol->module->name);
+ 			symbol = symbol->next;
+ 		}
+ 	}
+@@ -750,14 +765,19 @@ main(int argc, char **argv)
+ 	struct module *mod;
+ 	struct buffer buf = { };
+ 	char fname[SZ];
+-	char *dump_read = NULL, *dump_write = NULL;
++	char *kernel_read = NULL, *module_read = NULL;
++	char *dump_write = NULL;
+ 	char *supp = NULL;
+ 	int opt;
+ 
+-	while ((opt = getopt(argc, argv, "i:o:s:")) != -1) {
++	while ((opt = getopt(argc, argv, "i:I:o:s:")) != -1) {
+ 		switch(opt) {
+ 			case 'i':
+-				dump_read = optarg;
++				kernel_read = optarg;
++				break;
++			case 'I':
++				module_read = optarg;
++				external_module = 1;
+ 				break;
+ 			case 'o':
+ 				dump_write = optarg;
+@@ -773,8 +793,10 @@ main(int argc, char **argv)
+ 	if (supp)
+ 		read_supported(supp);
+ 
+-	if (dump_read)
+-		read_dump(dump_read);
++	if (kernel_read)
++		read_dump(kernel_read, 1);
++	if (module_read)
++		read_dump(module_read, 0);
+ 
+ 	while (optind < argc) {
+ 		read_symbols(argv[optind++]);
+@@ -786,7 +808,7 @@ main(int argc, char **argv)
+ 
+ 		buf.pos = 0;
+ 
+-		add_header(&buf);
++		add_header(&buf, mod);
+ 		add_supported_flag(&buf, mod);
+ 		add_versions(&buf, mod);
+ 		add_depends(&buf, mod, modules);
diff --git a/lustre/kernel_patches/series/2.6-rhel4.series b/lustre/kernel_patches/series/2.6-rhel4.series
index 13383a7414..95e090b909 100644
--- a/lustre/kernel_patches/series/2.6-rhel4.series
+++ b/lustre/kernel_patches/series/2.6-rhel4.series
@@ -29,3 +29,4 @@ quota-deadlock-on-pagelock-core.patch
 quota-umount-race-fix.patch
 quota-deadlock-on-pagelock-ext3.patch
 vfs-keep-inode-hashed-for-clear-inode.patch
+modpost_external_module_updates_rhel4.patch
diff --git a/lustre/kernel_patches/series/2.6-suse-newer.series b/lustre/kernel_patches/series/2.6-suse-newer.series
index e2c53bdf00..90ede2df35 100644
--- a/lustre/kernel_patches/series/2.6-suse-newer.series
+++ b/lustre/kernel_patches/series/2.6-suse-newer.series
@@ -13,3 +13,4 @@ bitops_ext2_find_next_le_bit-2.6.patch
 2.6.5-quotafix.patch
 vfs_intent-reduce-stack-usage-2.6-suse-newer.patch
 atomic_add_return-sles9.patch
+modpost_external_module_updates_sles9.patch
-- 
GitLab