first_stage_init: support kernel module directories
Kernel modules may be located within directories in /lib/modules. Attempt to load kernel modules from each directory that has a name starting with the major and minor version of the currently running kernel. If a single kernel module is successfully loaded from a directory, that directory is treated as the correct kernel module directory for the system. No other kernel module directories are searched and any kernel module load errors in that directory are fatal. If the attempt to load the first kernel module from a directory fails, or if there are no kernel modules in a directory, then the search proceeds to the next directory. If no kernel module is successfully loaded from any directory as above, an attempt is made to load kernel modules from the top level at /lib/modules/. Bug: 157645635 Change-Id: I92eadd8617f03a645da460ccb776bc04fa541f00 Merged-In: I92eadd8617f03a645da460ccb776bc04fa541f00
This commit is contained in:
parent
8bafa9e28e
commit
e35d217958
|
@ -24,6 +24,7 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
@ -99,6 +100,77 @@ bool ForceNormalBoot(const std::string& cmdline) {
|
|||
|
||||
} // namespace
|
||||
|
||||
std::string GetModuleLoadList(bool recovery, const std::string& dir_path) {
|
||||
auto module_load_file = "modules.load";
|
||||
if (recovery) {
|
||||
struct stat fileStat;
|
||||
std::string recovery_load_path = dir_path + "/modules.load.recovery";
|
||||
if (!stat(recovery_load_path.c_str(), &fileStat)) {
|
||||
module_load_file = "modules.load.recovery";
|
||||
}
|
||||
}
|
||||
|
||||
return module_load_file;
|
||||
}
|
||||
|
||||
#define MODULE_BASE_DIR "/lib/modules"
|
||||
bool LoadKernelModules(bool recovery, bool want_console) {
|
||||
struct utsname uts;
|
||||
if (uname(&uts)) {
|
||||
LOG(FATAL) << "Failed to get kernel version.";
|
||||
}
|
||||
int major, minor;
|
||||
if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
|
||||
LOG(FATAL) << "Failed to parse kernel version " << uts.release;
|
||||
}
|
||||
|
||||
std::unique_ptr<DIR, decltype(&closedir)> base_dir(opendir(MODULE_BASE_DIR), closedir);
|
||||
if (!base_dir) {
|
||||
LOG(INFO) << "Unable to open /lib/modules, skipping module loading.";
|
||||
return true;
|
||||
}
|
||||
dirent* entry;
|
||||
std::vector<std::string> module_dirs;
|
||||
while ((entry = readdir(base_dir.get()))) {
|
||||
if (entry->d_type != DT_DIR) {
|
||||
continue;
|
||||
}
|
||||
int dir_major, dir_minor;
|
||||
if (sscanf(entry->d_name, "%d.%d", &dir_major, &dir_minor) != 2 || dir_major != major ||
|
||||
dir_minor != minor) {
|
||||
continue;
|
||||
}
|
||||
module_dirs.emplace_back(entry->d_name);
|
||||
}
|
||||
|
||||
// Sort the directories so they are iterated over during module loading
|
||||
// in a consistent order. Alphabetical sorting is fine here because the
|
||||
// kernel version at the beginning of the directory name must match the
|
||||
// current kernel version, so the sort only applies to a label that
|
||||
// follows the kernel version, for example /lib/modules/5.4 vs.
|
||||
// /lib/modules/5.4-gki.
|
||||
std::sort(module_dirs.begin(), module_dirs.end());
|
||||
|
||||
for (const auto& module_dir : module_dirs) {
|
||||
std::string dir_path = MODULE_BASE_DIR "/";
|
||||
dir_path.append(module_dir);
|
||||
Modprobe m({dir_path}, GetModuleLoadList(recovery, dir_path));
|
||||
bool retval = m.LoadListedModules(!want_console);
|
||||
int modules_loaded = m.GetModuleCount();
|
||||
if (modules_loaded > 0) {
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
Modprobe m({MODULE_BASE_DIR}, GetModuleLoadList(recovery, MODULE_BASE_DIR));
|
||||
bool retval = m.LoadListedModules(!want_console);
|
||||
int modules_loaded = m.GetModuleCount();
|
||||
if (modules_loaded > 0) {
|
||||
return retval;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int FirstStageMain(int argc, char** argv) {
|
||||
if (REBOOT_BOOTLOADER_ON_PANIC) {
|
||||
InstallRebootSignalHandlers();
|
||||
|
@ -190,18 +262,9 @@ int FirstStageMain(int argc, char** argv) {
|
|||
old_root_dir.reset();
|
||||
}
|
||||
|
||||
std::string module_load_file = "modules.load";
|
||||
if (IsRecoveryMode() && !ForceNormalBoot(cmdline)) {
|
||||
struct stat fileStat;
|
||||
std::string recovery_load_path = "/lib/modules/modules.load.recovery";
|
||||
if (!stat(recovery_load_path.c_str(), &fileStat)) {
|
||||
module_load_file = "modules.load.recovery";
|
||||
}
|
||||
}
|
||||
|
||||
Modprobe m({"/lib/modules"}, module_load_file);
|
||||
auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline) : 0;
|
||||
if (!m.LoadListedModules(!want_console)) {
|
||||
|
||||
if (!LoadKernelModules(IsRecoveryMode() && !ForceNormalBoot(cmdline), want_console)) {
|
||||
if (want_console != FirstStageConsoleParam::DISABLED) {
|
||||
LOG(ERROR) << "Failed to load kernel modules, starting console";
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue