defer firmware load until after filesystems are mounted

In some situations a driver could try to request firmware before
/system is mounted.  Previously we'd fail the request.  Now we
will retry the read-from-filesystem every 100ms until we find the
firmware or we've finished the "fs" and "post-fs" stages of init.

Change-Id: Ie32402f7d41c818bf20f3297286ed5f99705b72c
This commit is contained in:
Brian Swetland 2011-03-24 15:45:30 -07:00
parent e31f2cdde6
commit 8d48c8e457
3 changed files with 36 additions and 9 deletions

View File

@ -551,13 +551,19 @@ out:
return ret;
}
static int is_booting(void)
{
return access("/dev/.booting", F_OK) == 0;
}
static void process_firmware_event(struct uevent *uevent)
{
char *root, *loading, *data, *file1 = NULL, *file2 = NULL;
int l, loading_fd, data_fd, fw_fd;
int booting = is_booting();
log_event_print("firmware event { '%s', '%s' }\n",
uevent->path, uevent->firmware);
INFO("firmware: loading '%s' for '%s'\n",
uevent->firmware, uevent->path);
l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
if (l == -1)
@ -587,19 +593,29 @@ static void process_firmware_event(struct uevent *uevent)
if(data_fd < 0)
goto loading_close_out;
try_loading_again:
fw_fd = open(file1, O_RDONLY);
if(fw_fd < 0) {
fw_fd = open(file2, O_RDONLY);
if (fw_fd < 0) {
if (booting) {
/* If we're not fully booted, we may be missing
* filesystems needed for firmware, wait and retry.
*/
usleep(100000);
booting = is_booting();
goto try_loading_again;
}
INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno);
write(loading_fd, "-1", 2);
goto data_close_out;
}
}
if(!load_firmware(fw_fd, loading_fd, data_fd))
log_event_print("firmware copy success { '%s', '%s' }\n", root, uevent->firmware);
INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
else
log_event_print("firmware copy failure { '%s', '%s' }\n", root, uevent->firmware);
INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);
close(fw_fd);
data_close_out:
@ -620,7 +636,6 @@ root_free_out:
static void handle_firmware_event(struct uevent *uevent)
{
pid_t pid;
int status;
int ret;
if(strcmp(uevent->subsystem, "firmware"))
@ -634,10 +649,6 @@ static void handle_firmware_event(struct uevent *uevent)
if (!pid) {
process_firmware_event(uevent);
exit(EXIT_SUCCESS);
} else {
do {
ret = waitpid(pid, &status, 0);
} while (ret == -1 && errno == EINTR);
}
}

View File

@ -651,6 +651,10 @@ static int check_startup_action(int nargs, char **args)
ERROR("init startup failure\n");
exit(1);
}
/* signal that we hit this point */
unlink("/dev/.booting");
return 0;
}
@ -708,6 +712,9 @@ int main(int argc, char **argv)
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
/* indicate that booting is in progress to background fw loaders, etc */
close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
/* We must have some place other than / to create the
* device nodes for kmsg and null, otherwise we won't
* be able to remount / read-only later on.

View File

@ -20,6 +20,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <private/android_filesystem_config.h>
#include "ueventd.h"
@ -37,6 +39,13 @@ int ueventd_main(int argc, char **argv)
int nr;
char tmp[32];
/* Prevent fire-and-forget children from becoming zombies.
* If we should need to wait() for some children in the future
* (as opposed to none right now), double-forking here instead
* of ignoring SIGCHLD may be the better solution.
*/
signal(SIGCHLD, SIG_IGN);
open_devnull_stdio();
log_init();