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

modpost: refactor error handling and clarify error/fatal difference

We have 3 log functions. fatal() is special because it lets modpost bail
out immediately. The difference between warn() and error() is the only
prefix parts ("WARNING:" vs "ERROR:").

In my understanding, the expected handling of error() is to propagate
the return code of the function to the exit code of modpost, as
check_exports() etc. already does. This is a good manner in general
because we should display as many error messages as possible in a
single run of modpost.

What is annoying about fatal() is that it kills modpost at the first
error. People would need to run Kbuild again and again until they fix
all errors.

But, unfortunately, people tend to do:
"This case should not be allowed. Let's replace warn() with fatal()."

One of the reasons is probably it is tedious to manually hoist the error
code to the main() function.

This commit refactors error() so any single call for it automatically
makes modpost return the error code.

I also added comments in modpost.h for warn(), error(), and fatal().

Please use fatal() only when you have a strong reason to do so.
For example:

- Memory shortage (i.e. malloc() etc. has failed)
- The ELF file is broken, and there is no point to continue parsing
- Something really odd has happened

For general coding errors, please use error().

Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
Tested-by: Quentin Perret <qperret@google.com>

+27 -29
+14 -29
scripts/mod/modpost.c
··· 40 40 /* If set to 1, only warn (instead of error) about missing ns imports */ 41 41 static int allow_missing_ns_imports; 42 42 43 + static bool error_occurred; 44 + 43 45 enum export { 44 46 export_plain, export_unused, export_gpl, 45 47 export_unused_gpl, export_gpl_future, export_unknown ··· 80 78 81 79 if (loglevel == LOG_FATAL) 82 80 exit(1); 81 + if (loglevel == LOG_ERROR) 82 + error_occurred = true; 83 83 } 84 84 85 85 static inline bool strends(const char *str, const char *postfix) ··· 2178 2174 } 2179 2175 } 2180 2176 2181 - static int check_exports(struct module *mod) 2177 + static void check_exports(struct module *mod) 2182 2178 { 2183 2179 struct symbol *s, *exp; 2184 - int err = 0; 2185 2180 2186 2181 for (s = mod->unres; s; s = s->next) { 2187 2182 const char *basename; 2188 2183 exp = find_symbol(s->name); 2189 2184 if (!exp || exp->module == mod) { 2190 - if (have_vmlinux && !s->weak) { 2185 + if (have_vmlinux && !s->weak) 2191 2186 modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR, 2192 2187 "\"%s\" [%s.ko] undefined!\n", 2193 2188 s->name, mod->name); 2194 - if (!warn_unresolved) 2195 - err = 1; 2196 - } 2197 2189 continue; 2198 2190 } 2199 2191 basename = strrchr(mod->name, '/'); ··· 2203 2203 modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR, 2204 2204 "module %s uses symbol %s from namespace %s, but does not import it.\n", 2205 2205 basename, exp->name, exp->namespace); 2206 - if (!allow_missing_ns_imports) 2207 - err = 1; 2208 2206 add_namespace(&mod->missing_namespaces, exp->namespace); 2209 2207 } 2210 2208 ··· 2210 2212 check_for_gpl_usage(exp->export, basename, exp->name); 2211 2213 check_for_unused(exp->export, basename, exp->name); 2212 2214 } 2213 - 2214 - return err; 2215 2215 } 2216 2216 2217 - static int check_modname_len(struct module *mod) 2217 + static void check_modname_len(struct module *mod) 2218 2218 { 2219 2219 const char *mod_name; 2220 2220 ··· 2221 2225 mod_name = mod->name; 2222 2226 else 2223 2227 mod_name++; 2224 - if (strlen(mod_name) >= MODULE_NAME_LEN) { 2228 + if (strlen(mod_name) >= MODULE_NAME_LEN) 2225 2229 error("module name is too long [%s.ko]\n", mod->name); 2226 - return 1; 2227 - } 2228 - 2229 - return 0; 2230 2230 } 2231 2231 2232 2232 /** ··· 2281 2289 /** 2282 2290 * Record CRCs for unresolved symbols 2283 2291 **/ 2284 - static int add_versions(struct buffer *b, struct module *mod) 2292 + static void add_versions(struct buffer *b, struct module *mod) 2285 2293 { 2286 2294 struct symbol *s, *exp; 2287 - int err = 0; 2288 2295 2289 2296 for (s = mod->unres; s; s = s->next) { 2290 2297 exp = find_symbol(s->name); ··· 2295 2304 } 2296 2305 2297 2306 if (!modversions) 2298 - return err; 2307 + return; 2299 2308 2300 2309 buf_printf(b, "\n"); 2301 2310 buf_printf(b, "static const struct modversion_info ____versions[]\n"); ··· 2312 2321 if (strlen(s->name) >= MODULE_NAME_LEN) { 2313 2322 error("too long symbol \"%s\" [%s.ko]\n", 2314 2323 s->name, mod->name); 2315 - err = 1; 2316 2324 break; 2317 2325 } 2318 2326 buf_printf(b, "\t{ %#8x, \"%s\" },\n", ··· 2319 2329 } 2320 2330 2321 2331 buf_printf(b, "};\n"); 2322 - 2323 - return err; 2324 2332 } 2325 2333 2326 2334 static void add_depends(struct buffer *b, struct module *mod) ··· 2542 2554 char *missing_namespace_deps = NULL; 2543 2555 char *dump_write = NULL, *files_source = NULL; 2544 2556 int opt; 2545 - int err; 2546 2557 int n; 2547 2558 struct dump_list *dump_read_start = NULL; 2548 2559 struct dump_list **dump_read_iter = &dump_read_start; ··· 2611 2624 if (!have_vmlinux) 2612 2625 warn("Symbol info of vmlinux is missing. Unresolved symbol check will be entirely skipped.\n"); 2613 2626 2614 - err = 0; 2615 - 2616 2627 for (mod = modules; mod; mod = mod->next) { 2617 2628 char fname[PATH_MAX]; 2618 2629 ··· 2619 2634 2620 2635 buf.pos = 0; 2621 2636 2622 - err |= check_modname_len(mod); 2623 - err |= check_exports(mod); 2637 + check_modname_len(mod); 2638 + check_exports(mod); 2624 2639 2625 2640 add_header(&buf, mod); 2626 2641 add_intree_flag(&buf, !external_module); 2627 2642 add_retpoline(&buf); 2628 2643 add_staging_flag(&buf, mod->name); 2629 - err |= add_versions(&buf, mod); 2644 + add_versions(&buf, mod); 2630 2645 add_depends(&buf, mod); 2631 2646 add_moddevtable(&buf, mod); 2632 2647 add_srcversion(&buf, mod); ··· 2656 2671 2657 2672 free(buf.p); 2658 2673 2659 - return err; 2674 + return error_occurred ? 1 : 0; 2660 2675 }
+13
scripts/mod/modpost.h
··· 201 201 202 202 void modpost_log(enum loglevel loglevel, const char *fmt, ...); 203 203 204 + /* 205 + * warn - show the given message, then let modpost continue running, still 206 + * allowing modpost to exit successfully. This should be used when 207 + * we still allow to generate vmlinux and modules. 208 + * 209 + * error - show the given message, then let modpost continue running, but fail 210 + * in the end. This should be used when we should stop building vmlinux 211 + * or modules, but we can continue running modpost to catch as many 212 + * issues as possible. 213 + * 214 + * fatal - show the given message, and bail out immediately. This should be 215 + * used when there is no point to continue running modpost. 216 + */ 204 217 #define warn(fmt, args...) modpost_log(LOG_WARN, fmt, ##args) 205 218 #define error(fmt, args...) modpost_log(LOG_ERROR, fmt, ##args) 206 219 #define fatal(fmt, args...) modpost_log(LOG_FATAL, fmt, ##args)