When loading modules with other modules in the same linker file, depending on each other, currently the kernel linker chokes. Example: the uhub, uhci, ohci and usb modules are (for unrelated reasons) linked into one big file. It is however impossible currently to preload that file because the dependencies are not found if MODULE_DEPEND and MODULE_VERSION are added in appropriate places. Currently we do the following: for all linker files (A) check dependencies for all modules in linker file against found_modules if resolves (B) add the modules to found_modules The attached patch changes this to for all linker files (B) create a list of modules in the file (file_modules) (A) check dependencies for all modules in linker file against found_modules and file_modules if resolves (C) concatenate file_modules to found_modules Step A and B are reversed and a copy loop (C) has been added. As a side effect it is now also possible for modules to depend on themselves (usb_depend_on_usb): % nm /modules/usb.ko | grep depend_on 00019bc0 d _uhub_depend_on_usb 00019e88 d _usb_depend_on_usb Comments? Nick P.S.: I am aware of the people involved being at Usenix, so I'll postpone committing this until they have had time to comment on it. -- [EMAIL PROTECTED] [EMAIL PROTECTED] USB project http://www.etla.net/~n_hibma/
Index: kern_linker.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_linker.c,v retrieving revision 1.46 diff -w -u -r1.46 kern_linker.c --- kern_linker.c 2000/05/26 02:04:34 1.46 +++ kern_linker.c 2000/06/19 23:36:24 @@ -923,11 +923,11 @@ */ static modlist_t -modlist_lookup(const char *name) +modlist_lookup(modlisthead_t *modules, const char *name) { modlist_t mod; - for (mod = TAILQ_FIRST(&found_modules); mod; mod = TAILQ_NEXT(mod, link)) { + for (mod = TAILQ_FIRST(modules); mod; mod = TAILQ_NEXT(mod, link)) { if (!strcmp(mod->name, name)) return mod; } @@ -960,10 +960,12 @@ int i; int resolves; modlist_t mod; + modlisthead_t file_modules; TAILQ_INIT(&loaded_files); TAILQ_INIT(&depended_files); TAILQ_INIT(&found_modules); + TAILQ_INIT(&file_modules); error = 0; modptr = NULL; @@ -1002,7 +1004,7 @@ if (mp->md_type != MDT_VERSION) continue; modname = mp->md_cval; - if (modlist_lookup(modname) != NULL) { + if (modlist_lookup(&found_modules, modname) != NULL) { printf("module %s already present!\n", modname); /* XXX what can we do? this is a build error. :-( */ continue; @@ -1025,34 +1027,20 @@ for (lf = TAILQ_FIRST(&loaded_files); lf; lf = TAILQ_NEXT(lf, loaded)) { deps = (struct linker_set*) linker_file_lookup_symbol(lf, MDT_SETNAME, 0); - /* - * First, look to see if we would successfully link with this stuff. - */ + resolves = 1; /* unless we know otherwise */ + if (deps) { - for (i = 0; i < deps->ls_length; i++) { - mp = linker_reloc_ptr(lf, deps->ls_items[i]); - if (mp->md_type != MDT_DEPEND) - continue; - modname = linker_reloc_ptr(lf, mp->md_cval); - if (modlist_lookup(modname) == NULL) { - /* ok, the module isn't here yet, we are not finished */ - resolves = 0; - } - } - } /* - * OK, if we found our modules, we can link. So, "provide" the - * modules inside and add it to the end of the link order list. + * First, find all the modules that are contained in the file. */ - if (resolves) { - if (deps) { for (i = 0; i < deps->ls_length; i++) { mp = linker_reloc_ptr(lf, deps->ls_items[i]); if (mp->md_type != MDT_VERSION) continue; modname = linker_reloc_ptr(lf, mp->md_cval); - if (modlist_lookup(modname) != NULL) { + if (modlist_lookup(&found_modules, modname) != NULL + || modlist_lookup(&file_modules, modname) != NULL) { printf("module %s already present!\n", modname); linker_file_unload(lf); TAILQ_REMOVE(&loaded_files, lf, loaded); @@ -1064,9 +1052,38 @@ bzero(mod, sizeof(*mod)); mod->container = lf; mod->name = modname; - TAILQ_INSERT_TAIL(&found_modules, mod, link); + TAILQ_INSERT_TAIL(&file_modules, mod, link); + } + + /* + * Then, look to see if we would successfully link with this stuff. + */ + for (i = 0; i < deps->ls_length; i++) { + mp = linker_reloc_ptr(lf, deps->ls_items[i]); + if (mp->md_type != MDT_DEPEND) + continue; + modname = linker_reloc_ptr(lf, mp->md_cval); + if (modlist_lookup(&found_modules, modname) == NULL + && modlist_lookup(&file_modules, modname) == NULL) { + /* ok, the module isn't here yet, we are not finished */ + resolves = 0; } } + } + /* + * OK, if we found our modules, we can link. So, "provide" the + * modules inside and add it to the end of the link order list. + */ + if (resolves) { + /* + * Copy the list of modules found in the file into the global + * list of modules available. + */ + while ((mod = TAILQ_FIRST(&file_modules))) { + TAILQ_REMOVE(&file_modules, mod, link); + TAILQ_INSERT_TAIL(&found_modules, mod, link); + } + TAILQ_REMOVE(&loaded_files, lf, loaded); TAILQ_INSERT_TAIL(&depended_files, lf, loaded); /* @@ -1075,6 +1092,11 @@ * Also, we've busted the tailq next pointer with the REMOVE. */ goto restart; + } else { + while ((mod = TAILQ_FIRST(&file_modules))) { + TAILQ_REMOVE(&file_modules, mod, link); + free(mod, M_LINKER); + } } } @@ -1106,7 +1128,7 @@ if (mp->md_type != MDT_DEPEND) continue; modname = linker_reloc_ptr(lf, mp->md_cval); - mod = modlist_lookup(modname); + mod = modlist_lookup(&found_modules, modname); mod->container->refs++; error = linker_file_add_dependancy(lf, mod->container); if (error) @@ -1311,7 +1333,7 @@ if (mp->md_type != MDT_VERSION) continue; modname = linker_reloc_ptr(lf, mp->md_cval); - if (modlist_lookup(modname) != NULL) { + if (modlist_lookup(&found_modules, modname) != NULL) { printf("module %s already present!\n", modname); return EEXIST; } @@ -1334,7 +1356,7 @@ } if (j < deps->ls_length) /* early exit, it's a self reference */ continue; - mod = modlist_lookup(modname); + mod = modlist_lookup(&found_modules, modname); if (mod) { /* woohoo, it's loaded already */ lfdep = mod->container; lfdep->refs++;