aboutsummaryrefslogtreecommitdiff
path: root/modutils
diff options
context:
space:
mode:
authorGravatar Denys Vlasenko <vda.linux@googlemail.com>2015-02-12 16:18:39 +0100
committerGravatar Denys Vlasenko <vda.linux@googlemail.com>2015-02-12 17:05:14 +0100
commit1fd844267c3ad60e9122e141768e823e6ad74a28 (patch)
tree2a02a15313320bcb3a7d53f02743603a79a4333e /modutils
parent622a7aab2c4a918c0e71931505f5c38d66d81ad9 (diff)
downloadbusybox-1fd844267c3ad60e9122e141768e823e6ad74a28.tar.gz
busybox-1fd844267c3ad60e9122e141768e823e6ad74a28.tar.bz2
modprobe-small: if concurrent module load did not succeed, wait
usecase: two sd cards are being mounted in parallel at same time on dual core. example modules which are getting loaded is nls_cp437. While one module is being loaded , it makes state in /proc/modules as 'coming' and then starts doing its module init function (in our case - registering nls). meanwhile on other core, if modprobe returns that is has already been loaded, then it will continue and search for the nls list which is not yet finished from first module init. This fails resulting in not mounting sd card. function old new delta process_module 667 746 +79 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'modutils')
-rw-r--r--modutils/modprobe-small.c50
1 files changed, 41 insertions, 9 deletions
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
index 6b0a4400c..598965968 100644
--- a/modutils/modprobe-small.c
+++ b/modutils/modprobe-small.c
@@ -536,17 +536,49 @@ static module_info** find_alias(const char *alias)
// TODO: open only once, invent config_rewind()
static int already_loaded(const char *name)
{
- int ret = 0;
- char *s;
- parser_t *parser = config_open2("/proc/modules", xfopen_for_read);
- while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) {
- if (strcmp(s, name) == 0) {
- ret = 1;
- break;
+ int ret, namelen;
+ char *line;
+ FILE *fp;
+
+ ret = 5 * 2;
+ again:
+ fp = fopen_for_read("/proc/modules");
+ if (!fp)
+ return 0;
+ namelen = strlen(name);
+ while ((line = xmalloc_fgetline(fp)) != NULL) {
+ char *live;
+
+ // Examples from kernel 3.14.6:
+ //pcspkr 12718 0 - Live 0xffffffffa017e000
+ //snd_timer 28690 2 snd_seq,snd_pcm, Live 0xffffffffa025e000
+ //i915 801405 2 - Live 0xffffffffa0096000
+ if (strncmp(line, name, namelen) != 0 || line[namelen] != ' ') {
+ free(line);
+ continue;
}
+ live = strstr(line, " Live");
+ free(line);
+ if (!live) {
+ /* State can be Unloading, Loading, or Live.
+ * modprobe must not return prematurely if we see "Loading":
+ * it can cause further programs to assume load completed,
+ * but it did not (yet)!
+ * Wait up to 5*20 ms for it to resolve.
+ */
+ ret -= 2;
+ if (ret == 0)
+ break; /* huh? report as "not loaded" */
+ fclose(fp);
+ usleep(20*1000);
+ goto again;
+ }
+ ret = 1;
+ break;
}
- config_close(parser);
- return ret;
+ fclose(fp);
+
+ return ret | 1;
}
#else
#define already_loaded(name) 0