aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Jenkins <alan-jenkins@tuffmail.co.uk>2009-09-30 17:23:38 +0100
committerAlan Jenkins <alan-jenkins@tuffmail.co.uk>2009-10-01 10:15:24 +0100
commit1743de8a7c10c10f9f9e34255bf737515794219c (patch)
tree8bb70563898bfc60a64815b5db97655029959a3e
parent1a8d5a031e8d6c007af77a6102693fa188ea4bc3 (diff)
downloadmodule-init-tools-1743de8a7c10c10f9f9e34255bf737515794219c.tar.gz
modprobe: Don't assume module absent if no /sys/module/<module>/initstate
/sys/module/<module>/initstate only appeared in 2.6.20. If it is not present, we cannot tell whether the module has finished loading succesfully. In this case module_in_kernel() should return -1 (undefined). Take care to to distinguish between "initstate disappeared because the module was just unloaded" and "initstate is absent but the module is still present". "Fork bombing" side effect of this bug is described in [1]. A followup patch will add a fallback to /proc/modules. 1. http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=524940 Thanks to Modestas Vainius <modestas@vainius.eu> for explaining the problem. Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
-rw-r--r--modprobe.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/modprobe.c b/modprobe.c
index 999f56e..2b45510 100644
--- a/modprobe.c
+++ b/modprobe.c
@@ -560,14 +560,26 @@ static int module_in_kernel(const char *modname, unsigned int *usecount)
if (ret < 0)
return (errno == ENOENT) ? 0 : -1; /* Not found or unknown. */
- /* Wait for the existing module to either go live or disappear. */
nofail_asprintf(&name, "/sys/module/%s/initstate", modname);
- while (1) {
- ret = read_attribute(name, attr, ATTR_LEN);
- if (ret != 1 || streq(attr, "live\n"))
- break;
+ ret = read_attribute(name, attr, ATTR_LEN);
+ if (ret == 0) {
+ free(name);
+ nofail_asprintf(&name, "/sys/module/%s", modname);
+ if (stat(name, &finfo) < 0) {
+ /* module was removed before we could read initstate */
+ ret = 0;
+ } else {
+ /* initstate not available (2.6.19 or earlier) */
+ ret = -1;
+ }
+ free(name);
+ return ret;
+ }
+ /* Wait for the existing module to either go live or disappear. */
+ while (ret == 1 && !streq(attr, "live\n")) {
usleep(100000);
+ ret = read_attribute(name, attr, ATTR_LEN);
}
free(name);