blob: 804069a3c5e68d27740bceb8ea2d4baab8ee6672 [file] [log] [blame]
/*
* 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 <liblp/reader.h>
#include "fs_mgr_priv.h"
namespace android {
namespace fs_mgr {
using DeviceMapper = android::dm::DeviceMapper;
using DmTable = android::dm::DmTable;
using DmTarget = android::dm::DmTarget;
using DmTargetZero = android::dm::DmTargetZero;
using DmTargetLinear = android::dm::DmTargetLinear;
static bool CreateDmTable(const std::string& block_device, const LpMetadata& metadata,
const LpMetadataPartition& partition, DmTable* table) {
uint64_t sector = 0;
for (size_t i = 0; i < partition.num_extents; i++) {
const auto& extent = metadata.extents[partition.first_extent_index + i];
std::unique_ptr<DmTarget> target;
switch (extent.target_type) {
case LP_TARGET_TYPE_ZERO:
target = std::make_unique<DmTargetZero>(sector, extent.num_sectors);
break;
case LP_TARGET_TYPE_LINEAR:
target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, block_device,
extent.target_data);
break;
default:
LOG(ERROR) << "Unknown target type in metadata: " << extent.target_type;
return false;
}
if (!table->AddTarget(std::move(target))) {
return false;
}
sector += extent.num_sectors;
}
if (partition.attributes & LP_PARTITION_ATTR_READONLY) {
table->set_readonly(true);
}
return true;
}
static bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata,
const LpMetadataPartition& partition, bool force_writable,
const std::chrono::milliseconds& timeout_ms, std::string* path) {
DeviceMapper& dm = DeviceMapper::Instance();
DmTable table;
if (!CreateDmTable(block_device, metadata, partition, &table)) {
return false;
}
if (force_writable) {
table.set_readonly(false);
}
std::string name = GetPartitionName(partition);
if (!dm.CreateDevice(name, table)) {
return false;
}
if (!dm.GetDmDevicePathByName(name, path)) {
return false;
}
if (timeout_ms > std::chrono::milliseconds::zero()) {
if (!fs_mgr_wait_for_file(*path, timeout_ms, FileWaitMode::Exists)) {
DestroyLogicalPartition(name, {});
LERROR << "Timed out waiting for device path: " << *path;
return false;
}
}
LINFO << "Created logical partition " << name << " on device " << *path;
return true;
}
bool CreateLogicalPartitions(const std::string& block_device) {
uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
auto metadata = ReadMetadata(block_device.c_str(), slot);
if (!metadata) {
LOG(ERROR) << "Could not read partition table.";
return true;
}
for (const auto& partition : metadata->partitions) {
if (!partition.num_extents) {
LINFO << "Skipping zero-length logical partition: " << GetPartitionName(partition);
continue;
}
std::string path;
if (!CreateLogicalPartition(block_device, *metadata.get(), partition, false, {}, &path)) {
LERROR << "Could not create logical partition: " << GetPartitionName(partition);
return false;
}
}
return true;
}
bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
const std::string& partition_name, bool force_writable,
const std::chrono::milliseconds& timeout_ms, std::string* path) {
auto metadata = ReadMetadata(block_device.c_str(), metadata_slot);
if (!metadata) {
LOG(ERROR) << "Could not read partition table.";
return true;
}
for (const auto& partition : metadata->partitions) {
if (GetPartitionName(partition) == partition_name) {
return CreateLogicalPartition(block_device, *metadata.get(), partition, force_writable,
timeout_ms, path);
}
}
LERROR << "Could not find any partition with name: " << partition_name;
return false;
}
bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
DeviceMapper& dm = DeviceMapper::Instance();
std::string path;
if (timeout_ms > std::chrono::milliseconds::zero()) {
dm.GetDmDevicePathByName(name, &path);
}
if (!dm.DeleteDevice(name)) {
return false;
}
if (!path.empty() && !fs_mgr_wait_for_file(path, timeout_ms, FileWaitMode::DoesNotExist)) {
LERROR << "Timed out waiting for device path to unlink: " << path;
return false;
}
LINFO << "Unmapped logical partition " << name;
return true;
}
} // namespace fs_mgr
} // namespace android