Adds /dev/block/by-name/<partition> symlinks

During uevent processing, some "by-name" symlinks will be created.
    /dev/block/<type>/<device>/by-name/<partition>

<type> can be: platform, pci or vbd.
<device> might be: soc.0/f9824900.sdhci, soc.0/f9824900.sdhci, etc.
<partition> might be: system, vendor, system_a, system_b, etc.

e.g., on a non-A/B device:
    /dev/block/platform/soc.0/f9824900.sdhci/by-name/system
    /dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor

On a A/B device:
    /dev/block/platform/soc/1da4000.ufshc/by-name/system_a
    /dev/block/platform/soc/1da4000.ufshc/by-name/system_b
    /dev/block/platform/soc/1da4000.ufshc/by-name/vendor_a
    /dev/block/platform/soc/1da4000.ufshc/by-name/vendor_b

However, those symlinks are "device-specific".

This change adds the "generic" symlinks in ueventd, in addition to
the existing symlinks, when the possible "boot devices" are specified
in device tree. e.g.,

    &firmware_android {
	compatible = "android,firmware";
	boot_devices ="soc/1da4000.ufshc,soc.0/f9824900.sdhci";
    }

The following symlinks will then be created on the aforementioned non-A/B
and A/B devices, respectively.

    /dev/block/by-name/system
    /dev/block/by-name/vendor

    /dev/block/by-name/system_a
    /dev/block/by-name/system_b
    /dev/block/by-name/vendor_a
    /dev/block/by-name/vendor_b

Note that both <type> and <device> are skipped in the newly create symlinks.
It assumes there is no more than one devices with the same <partition>,
which is the assumption of current first stage mount flow.

Finally, when 'boot_devices' in DT is absent, it fallbacks to extract
'boot_devices' from fstab settings. e.g., using 'soc/1da4000.ufshc',
'soc.0/f9824900.sdhci' for a fstab with the following content:

   /dev/block/platform/soc/1da4000.ufshc/by-name/system
   /dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor

Bug: 78613232
Test: adb shell ls /dev/block/by-name
Change-Id: Iec920b5a72409b6a2bdbeeb290f0a3acd2046b5d
This commit is contained in:
Bowgo Tsai 2018-05-16 18:33:44 +08:00
parent 60fab88ecc
commit 8eec38f4e4
6 changed files with 95 additions and 12 deletions

View File

@ -686,6 +686,49 @@ static struct fstab *in_place_merge(struct fstab *a, struct fstab *b)
return a;
}
/* Extracts <device>s from the by-name symlinks specified in a fstab:
* /dev/block/<type>/<device>/by-name/<partition>
*
* <type> can be: platform, pci or vbd.
*
* For example, given the following entries in the input fstab:
* /dev/block/platform/soc/1da4000.ufshc/by-name/system
* /dev/block/pci/soc.0/f9824900.sdhci/by-name/vendor
* it returns a set { "soc/1da4000.ufshc", "soc.0/f9824900.sdhci" }.
*/
static std::set<std::string> extract_boot_devices(const fstab& fstab) {
std::set<std::string> boot_devices;
for (int i = 0; i < fstab.num_entries; i++) {
std::string blk_device(fstab.recs[i].blk_device);
// Skips blk_device that doesn't conform to the format.
if (!android::base::StartsWith(blk_device, "/dev/block") ||
android::base::StartsWith(blk_device, "/dev/block/by-name") ||
android::base::StartsWith(blk_device, "/dev/block/bootdevice/by-name")) {
continue;
}
// Skips non-by_name blk_device.
// /dev/block/<type>/<device>/by-name/<partition>
// ^ slash_by_name
auto slash_by_name = blk_device.find("/by-name");
if (slash_by_name == std::string::npos) continue;
blk_device.erase(slash_by_name); // erases /by-name/<partition>
// Erases /dev/block/, now we have <type>/<device>
blk_device.erase(0, std::string("/dev/block/").size());
// <type>/<device>
// ^ first_slash
auto first_slash = blk_device.find('/');
if (first_slash == std::string::npos) continue;
auto boot_device = blk_device.substr(first_slash + 1);
if (!boot_device.empty()) boot_devices.insert(std::move(boot_device));
}
return boot_devices;
}
struct fstab *fs_mgr_read_fstab(const char *fstab_path)
{
FILE *fstab_file;
@ -863,6 +906,23 @@ struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const st
return nullptr;
}
std::set<std::string> fs_mgr_get_boot_devices() {
// boot_devices can be specified in device tree.
std::string dt_value;
std::string file_name = get_android_dt_dir() + "/boot_devices";
if (read_dt_file(file_name, &dt_value)) {
auto boot_devices = android::base::Split(dt_value, ",");
return std::set<std::string>(boot_devices.begin(), boot_devices.end());
}
// Fallback to extract boot devices from fstab.
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
fs_mgr_free_fstab);
if (fstab) return extract_boot_devices(*fstab);
return {};
}
int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_VOLDMANAGED;

View File

@ -22,6 +22,7 @@
#include <stdint.h>
#include <stdio.h>
#include <set>
#include <string>
/*
@ -89,5 +90,6 @@ int fs_mgr_is_logical(const struct fstab_rec* fstab);
int fs_mgr_has_sysfs_path(const struct fstab_rec* fstab);
std::string fs_mgr_get_slot_suffix();
std::set<std::string> fs_mgr_get_boot_devices();
#endif /* __CORE_FS_TAB_H */

View File

@ -329,6 +329,10 @@ std::vector<std::string> DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uev
<< partition_name_sanitized << "'";
}
links.emplace_back(link_path + "/by-name/" + partition_name_sanitized);
// Adds symlink: /dev/block/by-name/<partition_name>.
if (boot_devices_.find(device) != boot_devices_.end()) {
links.emplace_back("/dev/block/by-name/" + partition_name_sanitized);
}
}
auto last_slash = uevent.path.rfind('/');
@ -346,8 +350,14 @@ void DeviceHandler::HandleDevice(const std::string& action, const std::string& d
PLOG(ERROR) << "Failed to create directory " << Dirname(link);
}
if (symlink(devpath.c_str(), link.c_str()) && errno != EEXIST) {
PLOG(ERROR) << "Failed to symlink " << devpath << " to " << link;
if (symlink(devpath.c_str(), link.c_str())) {
if (errno != EEXIST) {
PLOG(ERROR) << "Failed to symlink " << devpath << " to " << link;
} else if (std::string link_path;
Readlink(link, &link_path) && link_path != devpath) {
PLOG(ERROR) << "Failed to symlink " << devpath << " to " << link
<< ", which already links to: " << link_path;
}
}
}
}
@ -411,16 +421,18 @@ void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
std::vector<SysfsPermissions> sysfs_permissions,
std::vector<Subsystem> subsystems, bool skip_restorecon)
std::vector<Subsystem> subsystems, std::set<std::string> boot_devices,
bool skip_restorecon)
: dev_permissions_(std::move(dev_permissions)),
sysfs_permissions_(std::move(sysfs_permissions)),
subsystems_(std::move(subsystems)),
boot_devices_(std::move(boot_devices)),
skip_restorecon_(skip_restorecon),
sysfs_mount_point_("/sys") {}
DeviceHandler::DeviceHandler()
: DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
std::vector<Subsystem>{}, false) {}
std::vector<Subsystem>{}, std::set<std::string>{}, false) {}
} // namespace init
} // namespace android

View File

@ -21,6 +21,7 @@
#include <sys/types.h>
#include <algorithm>
#include <set>
#include <string>
#include <vector>
@ -103,8 +104,8 @@ class DeviceHandler {
DeviceHandler();
DeviceHandler(std::vector<Permissions> dev_permissions,
std::vector<SysfsPermissions> sysfs_permissions,
std::vector<Subsystem> subsystems, bool skip_restorecon);
std::vector<SysfsPermissions> sysfs_permissions, std::vector<Subsystem> subsystems,
std::set<std::string> boot_devices, bool skip_restorecon);
~DeviceHandler(){};
void HandleDeviceEvent(const Uevent& uevent);
@ -125,6 +126,7 @@ class DeviceHandler {
std::vector<Permissions> dev_permissions_;
std::vector<SysfsPermissions> sysfs_permissions_;
std::vector<Subsystem> subsystems_;
std::set<std::string> boot_devices_;
bool skip_restorecon_;
std::string sysfs_mount_point_;
};

View File

@ -77,7 +77,7 @@ class FirstStageMount {
std::unique_ptr<LogicalPartitionTable> dm_linear_table_;
std::vector<fstab_rec*> mount_fstab_recs_;
std::set<std::string> required_devices_partition_names_;
DeviceHandler device_handler_;
std::unique_ptr<DeviceHandler> device_handler_;
UeventListener uevent_listener_;
};
@ -147,6 +147,11 @@ FirstStageMount::FirstStageMount()
if (IsDmLinearEnabled()) {
dm_linear_table_ = android::fs_mgr::LoadPartitionsFromDeviceTree();
}
auto boot_devices = fs_mgr_get_boot_devices();
device_handler_ =
std::make_unique<DeviceHandler>(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
std::vector<Subsystem>{}, std::move(boot_devices), false);
}
std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
@ -205,7 +210,7 @@ bool FirstStageMount::InitRequiredDevices() {
bool found = false;
auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
if (uevent.path == dm_path) {
device_handler_.HandleDeviceEvent(uevent);
device_handler_->HandleDeviceEvent(uevent);
found = true;
return ListenerAction::kStop;
}
@ -262,7 +267,7 @@ ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const
if (iter != required_devices_partition_names_.end()) {
LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
required_devices_partition_names_.erase(iter);
device_handler_.HandleDeviceEvent(uevent);
device_handler_->HandleDeviceEvent(uevent);
if (required_devices_partition_names_.empty()) {
return ListenerAction::kStop;
} else {
@ -299,7 +304,7 @@ bool FirstStageMount::InitMappedDevice(const std::string& dm_device) {
auto verity_callback = [&device_name, &dm_device, this, &found](const Uevent& uevent) {
if (uevent.device_name == device_name) {
LOG(VERBOSE) << "Creating device-mapper device : " << dm_device;
device_handler_.HandleDeviceEvent(uevent);
device_handler_->HandleDeviceEvent(uevent);
found = true;
return ListenerAction::kStop;
}
@ -469,7 +474,7 @@ ListenerAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) {
// is not empty. e.g.,
// - /dev/block/platform/soc.0/f9824900.sdhci/by-name/modem
// - /dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1
std::vector<std::string> links = device_handler_.GetBlockDeviceSymlinks(uevent);
std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
if (!links.empty()) {
auto[it, inserted] = by_name_symlink_map_.emplace(uevent.partition_name, links[0]);
if (!inserted) {

View File

@ -30,6 +30,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <fstab/fstab.h>
#include <selinux/android.h>
#include <selinux/selinux.h>
@ -242,8 +243,9 @@ DeviceHandler CreateDeviceHandler() {
std::string hardware = android::base::GetProperty("ro.hardware", "");
parser.ParseConfig("/ueventd." + hardware + ".rc");
auto boot_devices = fs_mgr_get_boot_devices();
return DeviceHandler(std::move(dev_permissions), std::move(sysfs_permissions),
std::move(subsystems), true);
std::move(subsystems), std::move(boot_devices), true);
}
int ueventd_main(int argc, char** argv) {