Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus

* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus:
module: add MODULE_STATE_GOING notifier call
module: Enhance verify_export_symbols
module: set unused_gpl_crcs instead of overwriting unused_crcs
module: neaten __find_symbol, rename to find_symbol
module: reduce module image and resident size
module: make module_sect_attrs private to kernel/module.c

+172 -166
+1 -18
include/linux/module.h
··· 190 190 extern typeof(sym) sym; \ 191 191 __CRC_SYMBOL(sym, sec) \ 192 192 static const char __kstrtab_##sym[] \ 193 - __attribute__((section("__ksymtab_strings"))) \ 193 + __attribute__((section("__ksymtab_strings"), aligned(1))) \ 194 194 = MODULE_SYMBOL_PREFIX #sym; \ 195 195 static const struct kernel_symbol __ksymtab_##sym \ 196 196 __used \ ··· 228 228 MODULE_STATE_COMING, 229 229 MODULE_STATE_GOING, 230 230 }; 231 - 232 - /* Similar stuff for section attributes. */ 233 - struct module_sect_attr 234 - { 235 - struct module_attribute mattr; 236 - char *name; 237 - unsigned long address; 238 - }; 239 - 240 - struct module_sect_attrs 241 - { 242 - struct attribute_group grp; 243 - int nsections; 244 - struct module_sect_attr attrs[0]; 245 - }; 246 - 247 - struct module_param_attrs; 248 231 249 232 struct module 250 233 {
+171 -148
kernel/module.c
··· 164 164 return NULL; 165 165 } 166 166 167 - static void printk_unused_warning(const char *name) 167 + static bool always_ok(bool gplok, bool warn, const char *name) 168 168 { 169 - printk(KERN_WARNING "Symbol %s is marked as UNUSED, " 170 - "however this module is using it.\n", name); 171 - printk(KERN_WARNING "This symbol will go away in the future.\n"); 172 - printk(KERN_WARNING "Please evalute if this is the right api to use, " 173 - "and if it really is, submit a report the linux kernel " 174 - "mailinglist together with submitting your code for " 175 - "inclusion.\n"); 169 + return true; 176 170 } 177 171 178 - /* Find a symbol, return value, crc and module which owns it */ 179 - static unsigned long __find_symbol(const char *name, 180 - struct module **owner, 181 - const unsigned long **crc, 182 - int gplok) 172 + static bool printk_unused_warning(bool gplok, bool warn, const char *name) 173 + { 174 + if (warn) { 175 + printk(KERN_WARNING "Symbol %s is marked as UNUSED, " 176 + "however this module is using it.\n", name); 177 + printk(KERN_WARNING 178 + "This symbol will go away in the future.\n"); 179 + printk(KERN_WARNING 180 + "Please evalute if this is the right api to use and if " 181 + "it really is, submit a report the linux kernel " 182 + "mailinglist together with submitting your code for " 183 + "inclusion.\n"); 184 + } 185 + return true; 186 + } 187 + 188 + static bool gpl_only_unused_warning(bool gplok, bool warn, const char *name) 189 + { 190 + if (!gplok) 191 + return false; 192 + return printk_unused_warning(gplok, warn, name); 193 + } 194 + 195 + static bool gpl_only(bool gplok, bool warn, const char *name) 196 + { 197 + return gplok; 198 + } 199 + 200 + static bool warn_if_not_gpl(bool gplok, bool warn, const char *name) 201 + { 202 + if (!gplok && warn) { 203 + printk(KERN_WARNING "Symbol %s is being used " 204 + "by a non-GPL module, which will not " 205 + "be allowed in the future\n", name); 206 + printk(KERN_WARNING "Please see the file " 207 + "Documentation/feature-removal-schedule.txt " 208 + "in the kernel source tree for more details.\n"); 209 + } 210 + return true; 211 + } 212 + 213 + struct symsearch { 214 + const struct kernel_symbol *start, *stop; 215 + const unsigned long *crcs; 216 + bool (*check)(bool gplok, bool warn, const char *name); 217 + }; 218 + 219 + /* Look through this array of symbol tables for a symbol match which 220 + * passes the check function. */ 221 + static const struct kernel_symbol *search_symarrays(const struct symsearch *arr, 222 + unsigned int num, 223 + const char *name, 224 + bool gplok, 225 + bool warn, 226 + const unsigned long **crc) 227 + { 228 + unsigned int i; 229 + const struct kernel_symbol *ks; 230 + 231 + for (i = 0; i < num; i++) { 232 + ks = lookup_symbol(name, arr[i].start, arr[i].stop); 233 + if (!ks || !arr[i].check(gplok, warn, name)) 234 + continue; 235 + 236 + if (crc) 237 + *crc = symversion(arr[i].crcs, ks - arr[i].start); 238 + return ks; 239 + } 240 + return NULL; 241 + } 242 + 243 + /* Find a symbol, return value, (optional) crc and (optional) module 244 + * which owns it */ 245 + static unsigned long find_symbol(const char *name, 246 + struct module **owner, 247 + const unsigned long **crc, 248 + bool gplok, 249 + bool warn) 183 250 { 184 251 struct module *mod; 185 252 const struct kernel_symbol *ks; 253 + const struct symsearch arr[] = { 254 + { __start___ksymtab, __stop___ksymtab, __start___kcrctab, 255 + always_ok }, 256 + { __start___ksymtab_gpl, __stop___ksymtab_gpl, 257 + __start___kcrctab_gpl, gpl_only }, 258 + { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future, 259 + __start___kcrctab_gpl_future, warn_if_not_gpl }, 260 + { __start___ksymtab_unused, __stop___ksymtab_unused, 261 + __start___kcrctab_unused, printk_unused_warning }, 262 + { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl, 263 + __start___kcrctab_unused_gpl, gpl_only_unused_warning }, 264 + }; 186 265 187 266 /* Core kernel first. */ 188 - *owner = NULL; 189 - ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab); 267 + ks = search_symarrays(arr, ARRAY_SIZE(arr), name, gplok, warn, crc); 190 268 if (ks) { 191 - *crc = symversion(__start___kcrctab, (ks - __start___ksymtab)); 192 - return ks->value; 193 - } 194 - if (gplok) { 195 - ks = lookup_symbol(name, __start___ksymtab_gpl, 196 - __stop___ksymtab_gpl); 197 - if (ks) { 198 - *crc = symversion(__start___kcrctab_gpl, 199 - (ks - __start___ksymtab_gpl)); 200 - return ks->value; 201 - } 202 - } 203 - ks = lookup_symbol(name, __start___ksymtab_gpl_future, 204 - __stop___ksymtab_gpl_future); 205 - if (ks) { 206 - if (!gplok) { 207 - printk(KERN_WARNING "Symbol %s is being used " 208 - "by a non-GPL module, which will not " 209 - "be allowed in the future\n", name); 210 - printk(KERN_WARNING "Please see the file " 211 - "Documentation/feature-removal-schedule.txt " 212 - "in the kernel source tree for more " 213 - "details.\n"); 214 - } 215 - *crc = symversion(__start___kcrctab_gpl_future, 216 - (ks - __start___ksymtab_gpl_future)); 217 - return ks->value; 218 - } 219 - 220 - ks = lookup_symbol(name, __start___ksymtab_unused, 221 - __stop___ksymtab_unused); 222 - if (ks) { 223 - printk_unused_warning(name); 224 - *crc = symversion(__start___kcrctab_unused, 225 - (ks - __start___ksymtab_unused)); 226 - return ks->value; 227 - } 228 - 229 - if (gplok) 230 - ks = lookup_symbol(name, __start___ksymtab_unused_gpl, 231 - __stop___ksymtab_unused_gpl); 232 - if (ks) { 233 - printk_unused_warning(name); 234 - *crc = symversion(__start___kcrctab_unused_gpl, 235 - (ks - __start___ksymtab_unused_gpl)); 269 + if (owner) 270 + *owner = NULL; 236 271 return ks->value; 237 272 } 238 273 239 274 /* Now try modules. */ 240 275 list_for_each_entry(mod, &modules, list) { 241 - *owner = mod; 242 - ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms); 243 - if (ks) { 244 - *crc = symversion(mod->crcs, (ks - mod->syms)); 245 - return ks->value; 246 - } 276 + struct symsearch arr[] = { 277 + { mod->syms, mod->syms + mod->num_syms, mod->crcs, 278 + always_ok }, 279 + { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms, 280 + mod->gpl_crcs, gpl_only }, 281 + { mod->gpl_future_syms, 282 + mod->gpl_future_syms + mod->num_gpl_future_syms, 283 + mod->gpl_future_crcs, warn_if_not_gpl }, 284 + { mod->unused_syms, 285 + mod->unused_syms + mod->num_unused_syms, 286 + mod->unused_crcs, printk_unused_warning }, 287 + { mod->unused_gpl_syms, 288 + mod->unused_gpl_syms + mod->num_unused_gpl_syms, 289 + mod->unused_gpl_crcs, gpl_only_unused_warning }, 290 + }; 247 291 248 - if (gplok) { 249 - ks = lookup_symbol(name, mod->gpl_syms, 250 - mod->gpl_syms + mod->num_gpl_syms); 251 - if (ks) { 252 - *crc = symversion(mod->gpl_crcs, 253 - (ks - mod->gpl_syms)); 254 - return ks->value; 255 - } 256 - } 257 - ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms); 292 + ks = search_symarrays(arr, ARRAY_SIZE(arr), 293 + name, gplok, warn, crc); 258 294 if (ks) { 259 - printk_unused_warning(name); 260 - *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms)); 261 - return ks->value; 262 - } 263 - 264 - if (gplok) { 265 - ks = lookup_symbol(name, mod->unused_gpl_syms, 266 - mod->unused_gpl_syms + mod->num_unused_gpl_syms); 267 - if (ks) { 268 - printk_unused_warning(name); 269 - *crc = symversion(mod->unused_gpl_crcs, 270 - (ks - mod->unused_gpl_syms)); 271 - return ks->value; 272 - } 273 - } 274 - ks = lookup_symbol(name, mod->gpl_future_syms, 275 - (mod->gpl_future_syms + 276 - mod->num_gpl_future_syms)); 277 - if (ks) { 278 - if (!gplok) { 279 - printk(KERN_WARNING "Symbol %s is being used " 280 - "by a non-GPL module, which will not " 281 - "be allowed in the future\n", name); 282 - printk(KERN_WARNING "Please see the file " 283 - "Documentation/feature-removal-schedule.txt " 284 - "in the kernel source tree for more " 285 - "details.\n"); 286 - } 287 - *crc = symversion(mod->gpl_future_crcs, 288 - (ks - mod->gpl_future_syms)); 295 + if (owner) 296 + *owner = mod; 289 297 return ks->value; 290 298 } 291 299 } 300 + 292 301 DEBUGP("Failed to find symbol %s\n", name); 293 302 return -ENOENT; 294 303 } ··· 745 736 if (!forced && module_refcount(mod) != 0) 746 737 wait_for_zero_refcount(mod); 747 738 739 + mutex_unlock(&module_mutex); 748 740 /* Final destruction now noone is using it. */ 749 - if (mod->exit != NULL) { 750 - mutex_unlock(&module_mutex); 741 + if (mod->exit != NULL) 751 742 mod->exit(); 752 - mutex_lock(&module_mutex); 753 - } 743 + blocking_notifier_call_chain(&module_notify_list, 744 + MODULE_STATE_GOING, mod); 745 + mutex_lock(&module_mutex); 754 746 /* Store the name of the last unloaded module for diagnostic purposes */ 755 747 strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module)); 756 748 free_module(mod); ··· 787 777 void __symbol_put(const char *symbol) 788 778 { 789 779 struct module *owner; 790 - const unsigned long *crc; 791 780 792 781 preempt_disable(); 793 - if (IS_ERR_VALUE(__find_symbol(symbol, &owner, &crc, 1))) 782 + if (IS_ERR_VALUE(find_symbol(symbol, &owner, NULL, true, false))) 794 783 BUG(); 795 784 module_put(owner); 796 785 preempt_enable(); ··· 933 924 struct module *mod) 934 925 { 935 926 const unsigned long *crc; 936 - struct module *owner; 937 927 938 - if (IS_ERR_VALUE(__find_symbol("struct_module", 939 - &owner, &crc, 1))) 928 + if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc, true, false))) 940 929 BUG(); 941 - return check_version(sechdrs, versindex, "struct_module", mod, 942 - crc); 930 + return check_version(sechdrs, versindex, "struct_module", mod, crc); 943 931 } 944 932 945 933 /* First part is kernel version, which we ignore. */ ··· 980 974 unsigned long ret; 981 975 const unsigned long *crc; 982 976 983 - ret = __find_symbol(name, &owner, &crc, 984 - !(mod->taints & TAINT_PROPRIETARY_MODULE)); 977 + ret = find_symbol(name, &owner, &crc, 978 + !(mod->taints & TAINT_PROPRIETARY_MODULE), true); 985 979 if (!IS_ERR_VALUE(ret)) { 986 980 /* use_module can fail due to OOM, 987 981 or module initialization or unloading */ ··· 997 991 * J. Corbet <corbet@lwn.net> 998 992 */ 999 993 #if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS) 994 + struct module_sect_attr 995 + { 996 + struct module_attribute mattr; 997 + char *name; 998 + unsigned long address; 999 + }; 1000 + 1001 + struct module_sect_attrs 1002 + { 1003 + struct attribute_group grp; 1004 + unsigned int nsections; 1005 + struct module_sect_attr attrs[0]; 1006 + }; 1007 + 1000 1008 static ssize_t module_sect_show(struct module_attribute *mattr, 1001 1009 struct module *mod, char *buf) 1002 1010 { ··· 1021 1001 1022 1002 static void free_sect_attrs(struct module_sect_attrs *sect_attrs) 1023 1003 { 1024 - int section; 1004 + unsigned int section; 1025 1005 1026 1006 for (section = 0; section < sect_attrs->nsections; section++) 1027 1007 kfree(sect_attrs->attrs[section].name); ··· 1382 1362 { 1383 1363 struct module *owner; 1384 1364 unsigned long value; 1385 - const unsigned long *crc; 1386 1365 1387 1366 preempt_disable(); 1388 - value = __find_symbol(symbol, &owner, &crc, 1); 1367 + value = find_symbol(symbol, &owner, NULL, true, true); 1389 1368 if (IS_ERR_VALUE(value)) 1390 1369 value = 0; 1391 1370 else if (strong_try_module_get(owner)) ··· 1401 1382 */ 1402 1383 static int verify_export_symbols(struct module *mod) 1403 1384 { 1404 - const char *name = NULL; 1405 - unsigned long i, ret = 0; 1385 + unsigned int i; 1406 1386 struct module *owner; 1407 - const unsigned long *crc; 1387 + const struct kernel_symbol *s; 1388 + struct { 1389 + const struct kernel_symbol *sym; 1390 + unsigned int num; 1391 + } arr[] = { 1392 + { mod->syms, mod->num_syms }, 1393 + { mod->gpl_syms, mod->num_gpl_syms }, 1394 + { mod->gpl_future_syms, mod->num_gpl_future_syms }, 1395 + { mod->unused_syms, mod->num_unused_syms }, 1396 + { mod->unused_gpl_syms, mod->num_unused_gpl_syms }, 1397 + }; 1408 1398 1409 - for (i = 0; i < mod->num_syms; i++) 1410 - if (!IS_ERR_VALUE(__find_symbol(mod->syms[i].name, 1411 - &owner, &crc, 1))) { 1412 - name = mod->syms[i].name; 1413 - ret = -ENOEXEC; 1414 - goto dup; 1399 + for (i = 0; i < ARRAY_SIZE(arr); i++) { 1400 + for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { 1401 + if (!IS_ERR_VALUE(find_symbol(s->name, &owner, 1402 + NULL, true, false))) { 1403 + printk(KERN_ERR 1404 + "%s: exports duplicate symbol %s" 1405 + " (owned by %s)\n", 1406 + mod->name, s->name, module_name(owner)); 1407 + return -ENOEXEC; 1408 + } 1415 1409 } 1416 - 1417 - for (i = 0; i < mod->num_gpl_syms; i++) 1418 - if (!IS_ERR_VALUE(__find_symbol(mod->gpl_syms[i].name, 1419 - &owner, &crc, 1))) { 1420 - name = mod->gpl_syms[i].name; 1421 - ret = -ENOEXEC; 1422 - goto dup; 1423 - } 1424 - 1425 - dup: 1426 - if (ret) 1427 - printk(KERN_ERR "%s: exports duplicate symbol %s (owned by %s)\n", 1428 - mod->name, name, module_name(owner)); 1429 - 1430 - return ret; 1410 + } 1411 + return 0; 1431 1412 } 1432 1413 1433 1414 /* Change all symbols so that st_value encodes the pointer directly. */ ··· 1833 1814 unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME); 1834 1815 #endif 1835 1816 1836 - /* Don't keep modinfo section */ 1817 + /* Don't keep modinfo and version sections. */ 1837 1818 sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; 1819 + sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC; 1838 1820 #ifdef CONFIG_KALLSYMS 1839 1821 /* Keep symbol and string tables for decoding later. */ 1840 1822 sechdrs[symindex].sh_flags |= SHF_ALLOC; ··· 1997 1977 mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; 1998 1978 mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr; 1999 1979 if (unusedgplcrcindex) 2000 - mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr; 1980 + mod->unused_gpl_crcs 1981 + = (void *)sechdrs[unusedgplcrcindex].sh_addr; 2001 1982 2002 1983 #ifdef CONFIG_MODVERSIONS 2003 1984 if ((mod->num_syms && !crcindex) || ··· 2192 2171 mod->state = MODULE_STATE_GOING; 2193 2172 synchronize_sched(); 2194 2173 module_put(mod); 2174 + blocking_notifier_call_chain(&module_notify_list, 2175 + MODULE_STATE_GOING, mod); 2195 2176 mutex_lock(&module_mutex); 2196 2177 free_module(mod); 2197 2178 mutex_unlock(&module_mutex);