blob: b2f3a6887f7909bf67180a490465f731db968d44 [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 "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