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:
Sandeep Patil 2017-02-07 18:11:37 -08:00
parent ea23983a9c
commit 957e4ab0b5
2 changed files with 102 additions and 41 deletions

View File

@ -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;
}

View File

@ -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 };