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:
parent
e31f2cdde6
commit
8d48c8e457
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue