diff options
author | Alan Jenkins <alan-jenkins@tuffmail.co.uk> | 2009-09-30 17:23:38 +0100 |
---|---|---|
committer | Alan Jenkins <alan-jenkins@tuffmail.co.uk> | 2009-10-01 10:15:24 +0100 |
commit | 1743de8a7c10c10f9f9e34255bf737515794219c (patch) | |
tree | 8bb70563898bfc60a64815b5db97655029959a3e | |
parent | 1a8d5a031e8d6c007af77a6102693fa188ea4bc3 (diff) | |
download | module-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.c | 22 |
1 files changed, 17 insertions, 5 deletions
@@ -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); |