Allow mapping of raw block devices to partition names

Allow mapping of raw block devices (those without a partition table)
to partition names for first stage mount and ueventd.  For example, a
block device `vdb` that contains only an ext4 metadata partition could
be mapped to `metadata` such that /dev/block/by-name/metadata is
created.

The mapping is provided by the `androidboot.partition_map` bootconfig
or kernel command line parameter.

Bug: 159943320
Test: boot with raw vdb,metadata;vdc,userdata partitions
Change-Id: Ib6a939d6fb88b85c46c81d613425a127627a734b
This commit is contained in:
Tom Cherry 2021-07-30 09:54:36 -07:00
parent 56a05e1fd8
commit 96e5f9b5b8
3 changed files with 48 additions and 1 deletions

View file

@ -87,7 +87,13 @@ ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent,
auto iter = devices->find(name);
if (iter == devices->end()) {
return ListenerAction::kContinue;
auto partition_name = DeviceHandler::GetPartitionNameForDevice(uevent.device_name);
if (!partition_name.empty()) {
iter = devices->find(partition_name);
}
if (iter == devices->end()) {
return ListenerAction::kContinue;
}
}
LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name;

View file

@ -46,6 +46,7 @@ using android::base::Dirname;
using android::base::ReadFileToString;
using android::base::Readlink;
using android::base::Realpath;
using android::base::Split;
using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::Trim;
@ -187,6 +188,36 @@ void SysfsPermissions::SetPermissions(const std::string& path) const {
}
}
std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_device) {
static const auto partition_map = [] {
std::vector<std::pair<std::string, std::string>> partition_map;
auto parser = [&partition_map](const std::string& key, const std::string& value) {
if (key != "androidboot.partition_map") {
return;
}
for (const auto& map : Split(value, ";")) {
auto map_pieces = Split(map, ",");
if (map_pieces.size() != 2) {
LOG(ERROR) << "Expected a comma separated device,partition mapping, but found '"
<< map << "'";
continue;
}
partition_map.emplace_back(map_pieces[0], map_pieces[1]);
}
};
ImportKernelCmdline(parser);
ImportBootconfig(parser);
return partition_map;
}();
for (const auto& [device, partition] : partition_map) {
if (query_device == device) {
return partition;
}
}
return {};
}
// Given a path that may start with a platform device, find the parent platform device by finding a
// parent directory with a 'subsystem' symlink that points to the platform bus.
// If it doesn't start with a platform device, return false
@ -376,6 +407,10 @@ std::vector<std::string> DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uev
// If we don't have a partition name but we are a partition on a boot device, create a
// symlink of /dev/block/by-name/<device_name> for symmetry.
links.emplace_back("/dev/block/by-name/" + uevent.device_name);
auto partition_name = GetPartitionNameForDevice(uevent.device_name);
if (!partition_name.empty()) {
links.emplace_back("/dev/block/by-name/" + partition_name);
}
}
auto last_slash = uevent.path.rfind('/');

View file

@ -122,6 +122,12 @@ class DeviceHandler : public UeventHandler {
std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
// `androidboot.partition_map` allows associating a partition name for a raw block device
// through a comma separated and semicolon deliminated list. For example,
// `androidboot.partition_map=vdb,metadata;vdc,userdata` maps `vdb` to `metadata` and `vdc` to
// `userdata`.
static std::string GetPartitionNameForDevice(const std::string& device);
private:
bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions(