init/fs_mgr: prototype first-stage dm-linear support
This adds an API to fs_mgr for reading dm-linear tables out of device trees and issuing device-mapper ioctls. The device tree code will be implemented separately. The dm-linear structures in fs_mgr are organized assuming we may want to pull them from sources other than DT (for example, text files, binary blobs, or something hardcoded for testing). File systems which are mounted from these logical partitions have specific fstab requirements. The block device must be a partition name, and if Verified Boot is used, that name must match the vbmeta partition name. Second, the entry must have the "logical" fs_mgr flag. Example fstab entry: vendor /vendor ext4 ro wait,logical Example fstab entry in device tree: vendor { compatible = "android,fstab"; dev = "vendor"; type = "ext4"; mnt_flags = "ro"; fs_mgr_flags = "wait,slotselect,avb,logical"; }; Bug: 78914864 Test: N/A Change-Id: I4d8878ea8858f26310119616cadc3ee0dd08566c
This commit is contained in:
parent
c8dd6b74e6
commit
62e5b20b50
11 changed files with 385 additions and 26 deletions
|
@ -42,6 +42,7 @@ cc_library_static {
|
|||
"fs_mgr_verity.cpp",
|
||||
"fs_mgr_avb.cpp",
|
||||
"fs_mgr_avb_ops.cpp",
|
||||
"fs_mgr_dm_linear.cpp",
|
||||
],
|
||||
static_libs: [
|
||||
"libfec",
|
||||
|
|
|
@ -794,6 +794,29 @@ static bool call_vdc(const std::vector<std::string>& args) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool fs_mgr_update_logical_partition(struct fstab_rec* rec) {
|
||||
// Logical partitions are specified with a named partition rather than a
|
||||
// block device, so if the block device is a path, then it has already
|
||||
// been updated.
|
||||
if (rec->blk_device[0] == '/') {
|
||||
return true;
|
||||
}
|
||||
|
||||
android::base::unique_fd dm_fd(open("/dev/device-mapper", O_RDONLY));
|
||||
if (dm_fd < 0) {
|
||||
PLOG(ERROR) << "open /dev/device-mapper failed";
|
||||
return false;
|
||||
}
|
||||
struct dm_ioctl io;
|
||||
std::string device_name;
|
||||
if (!fs_mgr_dm_get_device_name(&io, rec->blk_device, dm_fd, &device_name)) {
|
||||
return false;
|
||||
}
|
||||
free(rec->blk_device);
|
||||
rec->blk_device = strdup(device_name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
/* When multiple fstab records share the same mount_point, it will
|
||||
* try to mount each one in turn, and ignore any duplicates after a
|
||||
* first successful mount.
|
||||
|
@ -845,6 +868,13 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
|
|||
}
|
||||
}
|
||||
|
||||
if ((fstab->recs[i].fs_mgr_flags & MF_LOGICAL)) {
|
||||
if (!fs_mgr_update_logical_partition(&fstab->recs[i])) {
|
||||
LERROR << "Could not set up logical partition, skipping!";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
|
||||
!fs_mgr_wait_for_file(fstab->recs[i].blk_device, 20s)) {
|
||||
LERROR << "Skipping '" << fstab->recs[i].blk_device << "' during mount_all";
|
||||
|
@ -1065,6 +1095,13 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
|
|||
return FS_MGR_DOMNT_FAILED;
|
||||
}
|
||||
|
||||
if ((fstab->recs[i].fs_mgr_flags & MF_LOGICAL)) {
|
||||
if (!fs_mgr_update_logical_partition(&fstab->recs[i])) {
|
||||
LERROR << "Could not set up logical partition, skipping!";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* First check the filesystem if requested */
|
||||
if (fstab->recs[i].fs_mgr_flags & MF_WAIT && !fs_mgr_wait_for_file(n_blk_device, 20s)) {
|
||||
LERROR << "Skipping mounting '" << n_blk_device << "'";
|
||||
|
|
|
@ -585,7 +585,13 @@ SetUpAvbHashtreeResult FsManagerAvbHandle::SetUpAvbHashtree(struct fstab_rec* fs
|
|||
|
||||
// Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
|
||||
// to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix.
|
||||
std::string partition_name(basename(fstab_entry->blk_device));
|
||||
std::string partition_name;
|
||||
if (fstab_entry->fs_mgr_flags & MF_LOGICAL) {
|
||||
partition_name = fstab_entry->logical_partition_name;
|
||||
} else {
|
||||
partition_name = basename(fstab_entry->blk_device);
|
||||
}
|
||||
|
||||
if (fstab_entry->fs_mgr_flags & MF_SLOTSELECT) {
|
||||
auto ab_suffix = partition_name.rfind(fs_mgr_get_slot_suffix());
|
||||
if (ab_suffix != std::string::npos) {
|
||||
|
|
141
fs_mgr/fs_mgr_dm_linear.cpp
Normal file
141
fs_mgr/fs_mgr_dm_linear.cpp
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "fs_mgr_dm_linear.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
#include "fs_mgr_priv.h"
|
||||
#include "fs_mgr_priv_dm_ioctl.h"
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
std::string LogicalPartitionExtent::Serialize() const {
|
||||
// Note: we need to include an explicit null-terminator.
|
||||
std::string argv =
|
||||
android::base::StringPrintf("%s %" PRIu64, block_device_.c_str(), first_sector_);
|
||||
argv.push_back(0);
|
||||
|
||||
// The kernel expects each target to be aligned.
|
||||
size_t spec_bytes = sizeof(struct dm_target_spec) + argv.size();
|
||||
size_t padding = ((spec_bytes + 7) & ~7) - spec_bytes;
|
||||
for (size_t i = 0; i < padding; i++) {
|
||||
argv.push_back(0);
|
||||
}
|
||||
|
||||
struct dm_target_spec spec;
|
||||
spec.sector_start = logical_sector_;
|
||||
spec.length = num_sectors_;
|
||||
spec.status = 0;
|
||||
strcpy(spec.target_type, "linear");
|
||||
spec.next = sizeof(struct dm_target_spec) + argv.size();
|
||||
|
||||
return std::string((char*)&spec, sizeof(spec)) + argv;
|
||||
}
|
||||
|
||||
static bool LoadDmTable(int dm_fd, const LogicalPartition& partition) {
|
||||
// Combine all dm_target_spec buffers together.
|
||||
std::string target_string;
|
||||
for (const auto& extent : partition.extents) {
|
||||
target_string += extent.Serialize();
|
||||
}
|
||||
|
||||
// Allocate the ioctl buffer.
|
||||
size_t buffer_size = sizeof(struct dm_ioctl) + target_string.size();
|
||||
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(buffer_size);
|
||||
|
||||
// Initialize the ioctl buffer header, then copy our target specs in.
|
||||
struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
|
||||
fs_mgr_dm_ioctl_init(io, buffer_size, partition.name);
|
||||
io->target_count = partition.extents.size();
|
||||
if (partition.attributes & kPartitionReadonly) {
|
||||
io->flags |= DM_READONLY_FLAG;
|
||||
}
|
||||
memcpy(io + 1, target_string.c_str(), target_string.size());
|
||||
|
||||
if (ioctl(dm_fd, DM_TABLE_LOAD, io)) {
|
||||
PERROR << "Failed ioctl() on DM_TABLE_LOAD, partition " << partition.name;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadTablesAndActivate(int dm_fd, const LogicalPartition& partition) {
|
||||
if (!LoadDmTable(dm_fd, partition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct dm_ioctl io;
|
||||
return fs_mgr_dm_resume_table(&io, partition.name, dm_fd);
|
||||
}
|
||||
|
||||
static bool CreateDmDeviceForPartition(int dm_fd, const LogicalPartition& partition) {
|
||||
struct dm_ioctl io;
|
||||
if (!fs_mgr_dm_create_device(&io, partition.name, dm_fd)) {
|
||||
return false;
|
||||
}
|
||||
if (!LoadTablesAndActivate(dm_fd, partition)) {
|
||||
// Remove the device rather than leave it in an inactive state.
|
||||
fs_mgr_dm_destroy_device(&io, partition.name, dm_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
LINFO << "Created device-mapper device: " << partition.name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateLogicalPartitions(const LogicalPartitionTable& table) {
|
||||
android::base::unique_fd dm_fd(open("/dev/device-mapper", O_RDWR));
|
||||
if (dm_fd < 0) {
|
||||
PLOG(ERROR) << "failed to open /dev/device-mapper";
|
||||
return false;
|
||||
}
|
||||
for (const auto& partition : table.partitions) {
|
||||
if (!CreateDmDeviceForPartition(dm_fd, partition)) {
|
||||
LOG(ERROR) << "could not create dm-linear device for partition: " << partition.name;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
|
@ -109,6 +109,7 @@ static struct flag_list fs_mgr_flags[] = {
|
|||
{"logicalblk=", MF_LOGICALBLKSIZE},
|
||||
{"sysfs_path=", MF_SYSFS},
|
||||
{"defaults", 0},
|
||||
{"logical", MF_LOGICAL},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
|
@ -445,10 +446,6 @@ static std::string read_fstab_from_dt() {
|
|||
LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
|
||||
return {};
|
||||
}
|
||||
if (!StartsWith(value, "/dev")) {
|
||||
LERROR << "dt_fstab: Invalid device node for partition " << dp->d_name;
|
||||
return {};
|
||||
}
|
||||
fstab_entry.push_back(value);
|
||||
|
||||
std::string mount_point;
|
||||
|
@ -631,6 +628,10 @@ static struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
|
|||
fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
|
||||
fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
|
||||
fstab->recs[cnt].sysfs_path = flag_vals.sysfs_path;
|
||||
if (fstab->recs[cnt].fs_mgr_flags & MF_LOGICAL) {
|
||||
fstab->recs[cnt].logical_partition_name = strdup(fstab->recs[cnt].blk_device);
|
||||
}
|
||||
|
||||
cnt++;
|
||||
}
|
||||
/* If an A/B partition, modify block device to be the real block device */
|
||||
|
@ -797,6 +798,7 @@ void fs_mgr_free_fstab(struct fstab *fstab)
|
|||
for (i = 0; i < fstab->num_entries; i++) {
|
||||
/* Free the pointers return by strdup(3) */
|
||||
free(fstab->recs[i].blk_device);
|
||||
free(fstab->recs[i].logical_partition_name);
|
||||
free(fstab->recs[i].mount_point);
|
||||
free(fstab->recs[i].fs_type);
|
||||
free(fstab->recs[i].fs_options);
|
||||
|
@ -944,3 +946,7 @@ int fs_mgr_has_sysfs_path(const struct fstab_rec *fstab)
|
|||
{
|
||||
return fstab->fs_mgr_flags & MF_SYSFS;
|
||||
}
|
||||
|
||||
int fs_mgr_is_logical(const struct fstab_rec* fstab) {
|
||||
return fstab->fs_mgr_flags & MF_LOGICAL;
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
#define MF_WAIT 0x1
|
||||
#define MF_CHECK 0x2
|
||||
#define MF_CRYPT 0x4
|
||||
|
@ -111,6 +112,8 @@
|
|||
#define MF_AVB 0X2000000
|
||||
#define MF_KEYDIRECTORY 0X4000000
|
||||
#define MF_SYSFS 0X8000000
|
||||
#define MF_LOGICAL 0x10000000
|
||||
// clang-format on
|
||||
|
||||
#define DM_BUF_SIZE 4096
|
||||
|
||||
|
|
|
@ -36,19 +36,30 @@ bool fs_mgr_update_for_slotselect(struct fstab *fstab) {
|
|||
std::string ab_suffix;
|
||||
|
||||
for (n = 0; n < fstab->num_entries; n++) {
|
||||
if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) {
|
||||
char *tmp;
|
||||
fstab_rec& record = fstab->recs[n];
|
||||
if (record.fs_mgr_flags & MF_SLOTSELECT) {
|
||||
if (ab_suffix.empty()) {
|
||||
ab_suffix = fs_mgr_get_slot_suffix();
|
||||
// Return false if failed to get ab_suffix when MF_SLOTSELECT is specified.
|
||||
if (ab_suffix.empty()) return false;
|
||||
}
|
||||
if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, ab_suffix.c_str()) > 0) {
|
||||
free(fstab->recs[n].blk_device);
|
||||
fstab->recs[n].blk_device = tmp;
|
||||
} else {
|
||||
|
||||
char* new_blk_device;
|
||||
if (asprintf(&new_blk_device, "%s%s", record.blk_device, ab_suffix.c_str()) <= 0) {
|
||||
return false;
|
||||
}
|
||||
free(record.blk_device);
|
||||
record.blk_device = new_blk_device;
|
||||
|
||||
char* new_partition_name;
|
||||
if (record.logical_partition_name) {
|
||||
if (asprintf(&new_partition_name, "%s%s", record.logical_partition_name,
|
||||
ab_suffix.c_str()) <= 0) {
|
||||
return false;
|
||||
}
|
||||
free(record.logical_partition_name);
|
||||
record.logical_partition_name = new_partition_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -76,6 +76,7 @@ void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_de
|
|||
bool fs_mgr_load_verity_state(int* mode);
|
||||
bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
|
||||
int fs_mgr_swapon_all(struct fstab *fstab);
|
||||
bool fs_mgr_update_logical_partition(struct fstab_rec* rec);
|
||||
|
||||
int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
|
||||
|
||||
|
|
99
fs_mgr/include/fs_mgr_dm_linear.h
Normal file
99
fs_mgr/include/fs_mgr_dm_linear.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __CORE_FS_MGR_DM_LINEAR_H
|
||||
#define __CORE_FS_MGR_DM_LINEAR_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
static const uint32_t kPartitionReadonly = 0x1;
|
||||
|
||||
class LogicalPartitionExtent {
|
||||
public:
|
||||
LogicalPartitionExtent() : logical_sector_(0), first_sector_(0), num_sectors_(0) {}
|
||||
LogicalPartitionExtent(uint64_t logical_sector, uint64_t first_sector, uint64_t num_sectors,
|
||||
const std::string& block_device)
|
||||
: logical_sector_(logical_sector),
|
||||
first_sector_(first_sector),
|
||||
num_sectors_(num_sectors),
|
||||
block_device_(block_device) {}
|
||||
|
||||
// Return a string containing the dm_target_spec buffer needed to use this
|
||||
// extent in a device-mapper table.
|
||||
std::string Serialize() const;
|
||||
|
||||
const std::string& block_device() const { return block_device_; }
|
||||
|
||||
private:
|
||||
// Logical sector this extent represents in the presented block device.
|
||||
// This is equal to the previous extent's logical sector plus the number
|
||||
// of sectors in that extent. The first extent always starts at 0.
|
||||
uint64_t logical_sector_;
|
||||
// First 512-byte sector of this extent, on the source block device.
|
||||
uint64_t first_sector_;
|
||||
// Number of 512-byte sectors.
|
||||
uint64_t num_sectors_;
|
||||
// Target block device.
|
||||
std::string block_device_;
|
||||
};
|
||||
|
||||
struct LogicalPartition {
|
||||
LogicalPartition() : attributes(0), num_sectors(0) {}
|
||||
|
||||
std::string name;
|
||||
uint32_t attributes;
|
||||
// Number of 512-byte sectors total.
|
||||
uint64_t num_sectors;
|
||||
// List of extents.
|
||||
std::vector<LogicalPartitionExtent> extents;
|
||||
};
|
||||
|
||||
struct LogicalPartitionTable {
|
||||
// List of partitions in the partition table.
|
||||
std::vector<LogicalPartition> partitions;
|
||||
};
|
||||
|
||||
// Load a dm-linear table from the device tree if one is available; otherwise,
|
||||
// return null.
|
||||
std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree();
|
||||
|
||||
// Create device-mapper devices for the given partition table.
|
||||
//
|
||||
// On success, two devices nodes will be created for each partition, both
|
||||
// pointing to the same device:
|
||||
// /dev/block/dm-<N> where N is a sequential ID assigned by device-mapper.
|
||||
// /dev/block/dm-<name> where |name| is the partition name.
|
||||
//
|
||||
bool CreateLogicalPartitions(const LogicalPartitionTable& table);
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
|
||||
#endif // __CORE_FS_MGR_DM_LINEAR_H
|
|
@ -37,6 +37,7 @@ struct fstab {
|
|||
|
||||
struct fstab_rec {
|
||||
char* blk_device;
|
||||
char* logical_partition_name;
|
||||
char* mount_point;
|
||||
char* fs_type;
|
||||
unsigned long flags;
|
||||
|
@ -84,6 +85,7 @@ int fs_mgr_is_slotselect(const struct fstab_rec* fstab);
|
|||
int fs_mgr_is_nofail(const struct fstab_rec* fstab);
|
||||
int fs_mgr_is_latemount(const struct fstab_rec* fstab);
|
||||
int fs_mgr_is_quota(const struct fstab_rec* fstab);
|
||||
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();
|
||||
|
|
|
@ -33,11 +33,13 @@
|
|||
#include "devices.h"
|
||||
#include "fs_mgr.h"
|
||||
#include "fs_mgr_avb.h"
|
||||
#include "fs_mgr_dm_linear.h"
|
||||
#include "uevent.h"
|
||||
#include "uevent_listener.h"
|
||||
#include "util.h"
|
||||
|
||||
using android::base::Timer;
|
||||
using android::fs_mgr::LogicalPartitionTable;
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
@ -58,18 +60,21 @@ class FirstStageMount {
|
|||
protected:
|
||||
ListenerAction HandleBlockDevice(const std::string& name, const Uevent&);
|
||||
bool InitRequiredDevices();
|
||||
bool InitVerityDevice(const std::string& verity_device);
|
||||
bool InitMappedDevice(const std::string& verity_device);
|
||||
bool CreateLogicalPartitions();
|
||||
bool MountPartitions();
|
||||
bool GetBackingDmLinearDevices();
|
||||
|
||||
virtual ListenerAction UeventCallback(const Uevent& uevent);
|
||||
|
||||
// Pure virtual functions.
|
||||
virtual bool GetRequiredDevices() = 0;
|
||||
virtual bool GetDmVerityDevices() = 0;
|
||||
virtual bool SetUpDmVerity(fstab_rec* fstab_rec) = 0;
|
||||
|
||||
bool need_dm_verity_;
|
||||
|
||||
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
|
||||
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_;
|
||||
|
@ -82,7 +87,7 @@ class FirstStageMountVBootV1 : public FirstStageMount {
|
|||
~FirstStageMountVBootV1() override = default;
|
||||
|
||||
protected:
|
||||
bool GetRequiredDevices() override;
|
||||
bool GetDmVerityDevices() override;
|
||||
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
|
||||
};
|
||||
|
||||
|
@ -95,7 +100,7 @@ class FirstStageMountVBootV2 : public FirstStageMount {
|
|||
|
||||
protected:
|
||||
ListenerAction UeventCallback(const Uevent& uevent) override;
|
||||
bool GetRequiredDevices() override;
|
||||
bool GetDmVerityDevices() override;
|
||||
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
|
||||
bool InitAvbHandle();
|
||||
|
||||
|
@ -114,6 +119,17 @@ static bool inline IsRecoveryMode() {
|
|||
return access("/sbin/recovery", F_OK) == 0;
|
||||
}
|
||||
|
||||
static inline bool IsDmLinearEnabled() {
|
||||
bool enabled = false;
|
||||
import_kernel_cmdline(
|
||||
false, [&enabled](const std::string& key, const std::string& value, bool in_qemu) {
|
||||
if (key == "androidboot.lrap" && value == "1") {
|
||||
enabled = true;
|
||||
}
|
||||
});
|
||||
return enabled;
|
||||
}
|
||||
|
||||
// Class Definitions
|
||||
// -----------------
|
||||
FirstStageMount::FirstStageMount()
|
||||
|
@ -127,6 +143,10 @@ FirstStageMount::FirstStageMount()
|
|||
} else {
|
||||
LOG(INFO) << "Failed to read fstab from device tree";
|
||||
}
|
||||
|
||||
if (IsDmLinearEnabled()) {
|
||||
dm_linear_table_ = android::fs_mgr::LoadPartitionsFromDeviceTree();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
|
||||
|
@ -138,7 +158,7 @@ std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
|
|||
}
|
||||
|
||||
bool FirstStageMount::DoFirstStageMount() {
|
||||
if (mount_fstab_recs_.empty()) {
|
||||
if (!dm_linear_table_ && mount_fstab_recs_.empty()) {
|
||||
// Nothing to mount.
|
||||
LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
|
||||
return true;
|
||||
|
@ -146,13 +166,30 @@ bool FirstStageMount::DoFirstStageMount() {
|
|||
|
||||
if (!InitDevices()) return false;
|
||||
|
||||
if (!CreateLogicalPartitions()) return false;
|
||||
|
||||
if (!MountPartitions()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FirstStageMount::InitDevices() {
|
||||
return GetRequiredDevices() && InitRequiredDevices();
|
||||
return GetBackingDmLinearDevices() && GetDmVerityDevices() && InitRequiredDevices();
|
||||
}
|
||||
|
||||
bool FirstStageMount::GetBackingDmLinearDevices() {
|
||||
// Add any additional devices required for dm-linear mappings.
|
||||
if (!dm_linear_table_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& partition : dm_linear_table_->partitions) {
|
||||
for (const auto& extent : partition.extents) {
|
||||
const std::string& partition_name = android::base::Basename(extent.block_device());
|
||||
required_devices_partition_names_.emplace(partition_name);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Creates devices with uevent->partition_name matching one in the member variable
|
||||
|
@ -163,7 +200,7 @@ bool FirstStageMount::InitRequiredDevices() {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (need_dm_verity_) {
|
||||
if (dm_linear_table_ || need_dm_verity_) {
|
||||
const std::string dm_path = "/devices/virtual/misc/device-mapper";
|
||||
bool found = false;
|
||||
auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
|
||||
|
@ -210,6 +247,13 @@ bool FirstStageMount::InitRequiredDevices() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool FirstStageMount::CreateLogicalPartitions() {
|
||||
if (!dm_linear_table_) {
|
||||
return true;
|
||||
}
|
||||
return android::fs_mgr::CreateLogicalPartitions(*dm_linear_table_.get());
|
||||
}
|
||||
|
||||
ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent) {
|
||||
// Matches partition name to create device nodes.
|
||||
// Both required_devices_partition_names_ and uevent->partition_name have A/B
|
||||
|
@ -247,14 +291,14 @@ ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) {
|
|||
}
|
||||
|
||||
// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
|
||||
bool FirstStageMount::InitVerityDevice(const std::string& verity_device) {
|
||||
const std::string device_name(basename(verity_device.c_str()));
|
||||
bool FirstStageMount::InitMappedDevice(const std::string& dm_device) {
|
||||
const std::string device_name(basename(dm_device.c_str()));
|
||||
const std::string syspath = "/sys/block/" + device_name;
|
||||
bool found = false;
|
||||
|
||||
auto verity_callback = [&device_name, &verity_device, this, &found](const Uevent& uevent) {
|
||||
auto verity_callback = [&device_name, &dm_device, this, &found](const Uevent& uevent) {
|
||||
if (uevent.device_name == device_name) {
|
||||
LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
|
||||
LOG(VERBOSE) << "Creating device-mapper device : " << dm_device;
|
||||
device_handler_.HandleDeviceEvent(uevent);
|
||||
found = true;
|
||||
return ListenerAction::kStop;
|
||||
|
@ -279,6 +323,14 @@ bool FirstStageMount::InitVerityDevice(const std::string& verity_device) {
|
|||
|
||||
bool FirstStageMount::MountPartitions() {
|
||||
for (auto fstab_rec : mount_fstab_recs_) {
|
||||
if (fs_mgr_is_logical(fstab_rec)) {
|
||||
if (!fs_mgr_update_logical_partition(fstab_rec)) {
|
||||
return false;
|
||||
}
|
||||
if (!InitMappedDevice(fstab_rec->blk_device)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!SetUpDmVerity(fstab_rec)) {
|
||||
PLOG(ERROR) << "Failed to setup verity for '" << fstab_rec->mount_point << "'";
|
||||
return false;
|
||||
|
@ -291,7 +343,7 @@ bool FirstStageMount::MountPartitions() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool FirstStageMountVBootV1::GetRequiredDevices() {
|
||||
bool FirstStageMountVBootV1::GetDmVerityDevices() {
|
||||
std::string verity_loc_device;
|
||||
need_dm_verity_ = false;
|
||||
|
||||
|
@ -344,7 +396,7 @@ bool FirstStageMountVBootV1::SetUpDmVerity(fstab_rec* fstab_rec) {
|
|||
// The exact block device name (fstab_rec->blk_device) is changed to
|
||||
// "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
|
||||
// first stage.
|
||||
return InitVerityDevice(fstab_rec->blk_device);
|
||||
return InitMappedDevice(fstab_rec->blk_device);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -371,7 +423,7 @@ FirstStageMountVBootV2::FirstStageMountVBootV2() : avb_handle_(nullptr) {
|
|||
}
|
||||
}
|
||||
|
||||
bool FirstStageMountVBootV2::GetRequiredDevices() {
|
||||
bool FirstStageMountVBootV2::GetDmVerityDevices() {
|
||||
need_dm_verity_ = false;
|
||||
|
||||
// fstab_rec->blk_device has A/B suffix.
|
||||
|
@ -444,7 +496,7 @@ bool FirstStageMountVBootV2::SetUpDmVerity(fstab_rec* fstab_rec) {
|
|||
// The exact block device name (fstab_rec->blk_device) is changed to
|
||||
// "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
|
||||
// first stage.
|
||||
return InitVerityDevice(fstab_rec->blk_device);
|
||||
return InitMappedDevice(fstab_rec->blk_device);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue