init: refactor: add support for doing early coldboot
We don't want to spend time creating devices that are unncessesary during early (init first-stage) mount. So, refactor the devices code tha allows us to call into coldboot and has the - ability to only create devices that are specified by the caller - ability to stop coldboot cycle when all devices that the caller is interested in - ability to run coldboot for a specific syspath - ability to run ueventd code unmodified Test: Tested boot on angler, sailfish Change-Id: Id8f3492380696760414eadc20d624d300c904f8e Signed-off-by: Sandeep Patil <sspatil@google.com>
This commit is contained in:
parent
ea23983a9c
commit
957e4ab0b5
113
init/devices.cpp
113
init/devices.cpp
|
@ -64,18 +64,6 @@ extern struct selabel_handle *sehandle;
|
|||
|
||||
static int device_fd = -1;
|
||||
|
||||
struct uevent {
|
||||
const char *action;
|
||||
const char *path;
|
||||
const char *subsystem;
|
||||
const char *firmware;
|
||||
const char *partition_name;
|
||||
const char *device_name;
|
||||
int partition_num;
|
||||
int major;
|
||||
int minor;
|
||||
};
|
||||
|
||||
struct perms_ {
|
||||
char *name;
|
||||
char *attr;
|
||||
|
@ -879,9 +867,15 @@ static void handle_firmware_event(uevent* uevent) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool inline should_stop_coldboot(coldboot_action_t act)
|
||||
{
|
||||
return (act == COLDBOOT_STOP || act == COLDBOOT_FINISH);
|
||||
}
|
||||
|
||||
#define UEVENT_MSG_LEN 2048
|
||||
|
||||
static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*))
|
||||
template<typename T>
|
||||
static inline coldboot_action_t handle_device_fd_with(const T& handle_uevent)
|
||||
{
|
||||
char msg[UEVENT_MSG_LEN+2];
|
||||
int n;
|
||||
|
@ -894,14 +888,18 @@ static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*))
|
|||
|
||||
struct uevent uevent;
|
||||
parse_event(msg, &uevent);
|
||||
handle_uevent(&uevent);
|
||||
coldboot_action_t act = handle_uevent(&uevent);
|
||||
if (should_stop_coldboot(act))
|
||||
return act;
|
||||
}
|
||||
|
||||
return COLDBOOT_CONTINUE;
|
||||
}
|
||||
|
||||
void handle_device_fd()
|
||||
coldboot_action_t handle_device_fd(coldboot_callback fn)
|
||||
{
|
||||
handle_device_fd_with(
|
||||
[](struct uevent *uevent) {
|
||||
coldboot_action_t ret = handle_device_fd_with(
|
||||
[&](uevent* uevent) -> coldboot_action_t {
|
||||
if (selinux_status_updated() > 0) {
|
||||
struct selabel_handle *sehandle2;
|
||||
sehandle2 = selinux_android_file_context_handle();
|
||||
|
@ -911,9 +909,21 @@ void handle_device_fd()
|
|||
}
|
||||
}
|
||||
|
||||
handle_device_event(uevent);
|
||||
handle_firmware_event(uevent);
|
||||
// default is to always create the devices
|
||||
coldboot_action_t act = COLDBOOT_CREATE;
|
||||
if (fn) {
|
||||
act = fn(uevent);
|
||||
}
|
||||
|
||||
if (act == COLDBOOT_CREATE || act == COLDBOOT_STOP) {
|
||||
handle_device_event(uevent);
|
||||
handle_firmware_event(uevent);
|
||||
}
|
||||
|
||||
return act;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Coldboot walks parts of the /sys tree and pokes the uevent files
|
||||
|
@ -925,21 +935,24 @@ void handle_device_fd()
|
|||
** socket's buffer.
|
||||
*/
|
||||
|
||||
static void do_coldboot(DIR *d)
|
||||
static coldboot_action_t do_coldboot(DIR *d, coldboot_callback fn)
|
||||
{
|
||||
struct dirent *de;
|
||||
int dfd, fd;
|
||||
coldboot_action_t act = COLDBOOT_CONTINUE;
|
||||
|
||||
dfd = dirfd(d);
|
||||
|
||||
fd = openat(dfd, "uevent", O_WRONLY);
|
||||
if(fd >= 0) {
|
||||
if (fd >= 0) {
|
||||
write(fd, "add\n", 4);
|
||||
close(fd);
|
||||
handle_device_fd();
|
||||
act = handle_device_fd(fn);
|
||||
if (should_stop_coldboot(act))
|
||||
return act;
|
||||
}
|
||||
|
||||
while((de = readdir(d))) {
|
||||
while (!should_stop_coldboot(act) && (de = readdir(d))) {
|
||||
DIR *d2;
|
||||
|
||||
if(de->d_type != DT_DIR || de->d_name[0] == '.')
|
||||
|
@ -953,34 +966,39 @@ static void do_coldboot(DIR *d)
|
|||
if(d2 == 0)
|
||||
close(fd);
|
||||
else {
|
||||
do_coldboot(d2);
|
||||
act = do_coldboot(d2, fn);
|
||||
closedir(d2);
|
||||
}
|
||||
}
|
||||
|
||||
// default is always to continue looking for uevents
|
||||
return act;
|
||||
}
|
||||
|
||||
static void coldboot(const char *path)
|
||||
static coldboot_action_t coldboot(const char *path, coldboot_callback fn)
|
||||
{
|
||||
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
|
||||
if(d) {
|
||||
do_coldboot(d.get());
|
||||
if (d) {
|
||||
return do_coldboot(d.get(), fn);
|
||||
}
|
||||
|
||||
return COLDBOOT_CONTINUE;
|
||||
}
|
||||
|
||||
static void early_uevent_handler(struct uevent *uevent, const char *base, bool is_block)
|
||||
static coldboot_action_t early_uevent_handler(struct uevent *uevent, const char *base, bool is_block)
|
||||
{
|
||||
const char *name;
|
||||
char devpath[DEVPATH_LEN];
|
||||
|
||||
if (is_block && strncmp(uevent->subsystem, "block", 5))
|
||||
return;
|
||||
return COLDBOOT_STOP;
|
||||
|
||||
name = parse_device_name(uevent, MAX_DEV_NAME);
|
||||
if (!name) {
|
||||
LOG(ERROR) << "Failed to parse dev name from uevent: " << uevent->action
|
||||
<< " " << uevent->partition_name << " " << uevent->partition_num
|
||||
<< " " << uevent->major << ":" << uevent->minor;
|
||||
return;
|
||||
return COLDBOOT_STOP;
|
||||
}
|
||||
|
||||
snprintf(devpath, sizeof(devpath), "%s%s", base, name);
|
||||
|
@ -989,6 +1007,8 @@ static void early_uevent_handler(struct uevent *uevent, const char *base, bool i
|
|||
dev_t dev = makedev(uevent->major, uevent->minor);
|
||||
mode_t mode = 0600 | (is_block ? S_IFBLK : S_IFCHR);
|
||||
mknod(devpath, mode, dev);
|
||||
|
||||
return COLDBOOT_STOP;
|
||||
}
|
||||
|
||||
void early_create_dev(const std::string& syspath, early_device_type dev_type)
|
||||
|
@ -1009,11 +1029,11 @@ void early_create_dev(const std::string& syspath, early_device_type dev_type)
|
|||
|
||||
write(fd, "add\n", 4);
|
||||
handle_device_fd_with(dev_type == EARLY_BLOCK_DEV ?
|
||||
[](struct uevent *uevent) {
|
||||
early_uevent_handler(uevent, "/dev/block/", true);
|
||||
[](uevent* uevent) -> coldboot_action_t {
|
||||
return early_uevent_handler(uevent, "/dev/block/", true);
|
||||
} :
|
||||
[](struct uevent *uevent) {
|
||||
early_uevent_handler(uevent, "/dev/", false);
|
||||
[](uevent* uevent) -> coldboot_action_t {
|
||||
return early_uevent_handler(uevent, "/dev/", false);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1026,7 +1046,7 @@ void early_device_socket_close() {
|
|||
close(device_fd);
|
||||
}
|
||||
|
||||
void device_init() {
|
||||
void device_init(const char* path, coldboot_callback fn) {
|
||||
sehandle = selinux_android_file_context_handle();
|
||||
selinux_status_open(true);
|
||||
|
||||
|
@ -1043,10 +1063,25 @@ void device_init() {
|
|||
}
|
||||
|
||||
Timer t;
|
||||
coldboot("/sys/class");
|
||||
coldboot("/sys/block");
|
||||
coldboot("/sys/devices");
|
||||
close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
|
||||
coldboot_action_t act;
|
||||
if (!path) {
|
||||
act = coldboot("/sys/class", fn);
|
||||
if (!should_stop_coldboot(act)) {
|
||||
act = coldboot("/sys/block", fn);
|
||||
if (!should_stop_coldboot(act)) {
|
||||
act = coldboot("/sys/devices", fn);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
act = coldboot(path, fn);
|
||||
}
|
||||
|
||||
// If we have a callback, then do as it says. If no, then the default is
|
||||
// to always create COLDBOOT_DONE file.
|
||||
if (!fn || (act == COLDBOOT_FINISH)) {
|
||||
close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
|
||||
}
|
||||
|
||||
LOG(INFO) << "Coldboot took " << t;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,36 @@
|
|||
#ifndef _INIT_DEVICES_H
|
||||
#define _INIT_DEVICES_H
|
||||
|
||||
#include <functional>
|
||||
#include <sys/stat.h>
|
||||
|
||||
extern void handle_device_fd();
|
||||
extern void device_init(void);
|
||||
enum coldboot_action_t {
|
||||
// coldboot continues without creating the device for the uevent
|
||||
COLDBOOT_CONTINUE = 0,
|
||||
// coldboot continues after creating the device for the uevent
|
||||
COLDBOOT_CREATE,
|
||||
// coldboot stops after creating the device for uevent but doesn't
|
||||
// create the COLDBOOT_DONE file
|
||||
COLDBOOT_STOP,
|
||||
// same as COLDBOOT_STOP, but creates the COLDBOOT_DONE file
|
||||
COLDBOOT_FINISH
|
||||
};
|
||||
|
||||
struct uevent {
|
||||
const char* action;
|
||||
const char* path;
|
||||
const char* subsystem;
|
||||
const char* firmware;
|
||||
const char* partition_name;
|
||||
const char* device_name;
|
||||
int partition_num;
|
||||
int major;
|
||||
int minor;
|
||||
};
|
||||
|
||||
typedef std::function<coldboot_action_t(struct uevent* uevent)> coldboot_callback;
|
||||
extern coldboot_action_t handle_device_fd(coldboot_callback fn = nullptr);
|
||||
extern void device_init(const char* path = nullptr, coldboot_callback fn = nullptr);
|
||||
|
||||
enum early_device_type { EARLY_BLOCK_DEV, EARLY_CHAR_DEV };
|
||||
|
||||
|
|
Loading…
Reference in New Issue