Merge "libsnapshot: Refactor CreateLogicalAndSnapshotPartitions"
am: dccd6b3389
Change-Id: I6222327558d2fc9f0bad1056ef4d53e4e8a5fa48
This commit is contained in:
commit
362853af1a
2 changed files with 90 additions and 58 deletions
|
|
@ -329,6 +329,10 @@ class SnapshotManager final {
|
||||||
std::string GetSnapshotDeviceName(const std::string& snapshot_name,
|
std::string GetSnapshotDeviceName(const std::string& snapshot_name,
|
||||||
const SnapshotStatus& status);
|
const SnapshotStatus& status);
|
||||||
|
|
||||||
|
// Map the base device, COW devices, and snapshot device.
|
||||||
|
bool MapPartitionWithSnapshot(LockedFile* lock, CreateLogicalPartitionParams params,
|
||||||
|
std::string* path);
|
||||||
|
|
||||||
std::string gsid_dir_;
|
std::string gsid_dir_;
|
||||||
std::string metadata_dir_;
|
std::string metadata_dir_;
|
||||||
std::unique_ptr<IDeviceInfo> device_;
|
std::unique_ptr<IDeviceInfo> device_;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/unistd.h>
|
#include <sys/unistd.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
|
@ -1127,22 +1128,6 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions(const std::string& supe
|
||||||
auto lock = LockExclusive();
|
auto lock = LockExclusive();
|
||||||
if (!lock) return false;
|
if (!lock) return false;
|
||||||
|
|
||||||
std::vector<std::string> snapshot_list;
|
|
||||||
if (!ListSnapshots(lock.get(), &snapshot_list)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unordered_set<std::string> live_snapshots;
|
|
||||||
for (const auto& snapshot : snapshot_list) {
|
|
||||||
SnapshotStatus status;
|
|
||||||
if (!ReadSnapshotStatus(lock.get(), snapshot, &status)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (status.state != SnapshotState::MergeCompleted) {
|
|
||||||
live_snapshots.emplace(snapshot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& opener = device_->GetPartitionOpener();
|
const auto& opener = device_->GetPartitionOpener();
|
||||||
uint32_t slot = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
|
uint32_t slot = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
|
||||||
auto metadata = android::fs_mgr::ReadMetadata(opener, super_device, slot);
|
auto metadata = android::fs_mgr::ReadMetadata(opener, super_device, slot);
|
||||||
|
|
@ -1151,59 +1136,102 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions(const std::string& supe
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map logical partitions.
|
|
||||||
auto& dm = DeviceMapper::Instance();
|
|
||||||
for (const auto& partition : metadata->partitions) {
|
for (const auto& partition : metadata->partitions) {
|
||||||
auto partition_name = GetPartitionName(partition);
|
|
||||||
if (!partition.num_extents) {
|
|
||||||
LOG(INFO) << "Skipping zero-length logical partition: " << partition_name;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(partition.attributes & LP_PARTITION_ATTR_UPDATED)) {
|
|
||||||
LOG(INFO) << "Detected re-flashing of partition, will skip snapshot: "
|
|
||||||
<< partition_name;
|
|
||||||
live_snapshots.erase(partition_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateLogicalPartitionParams params = {
|
CreateLogicalPartitionParams params = {
|
||||||
.block_device = super_device,
|
.block_device = super_device,
|
||||||
.metadata = metadata.get(),
|
.metadata = metadata.get(),
|
||||||
.partition = &partition,
|
.partition = &partition,
|
||||||
.partition_opener = &opener,
|
.partition_opener = &opener,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto iter = live_snapshots.find(partition_name); iter != live_snapshots.end()) {
|
|
||||||
// If the device has a snapshot, it'll need to be writable, and
|
|
||||||
// we'll need to create the logical partition with a marked-up name
|
|
||||||
// (since the snapshot will use the partition name).
|
|
||||||
params.force_writable = true;
|
|
||||||
params.device_name = GetBaseDeviceName(partition_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ignore_path;
|
std::string ignore_path;
|
||||||
if (!CreateLogicalPartition(params, &ignore_path)) {
|
if (!MapPartitionWithSnapshot(lock.get(), std::move(params), &ignore_path)) {
|
||||||
LOG(ERROR) << "Could not create logical partition " << partition_name << " as device "
|
|
||||||
<< params.GetDeviceName();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!params.force_writable) {
|
|
||||||
// No snapshot.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't have ueventd in first-stage init, so use device major:minor
|
|
||||||
// strings instead.
|
|
||||||
std::string base_device;
|
|
||||||
if (!dm.GetDeviceString(params.GetDeviceName(), &base_device)) {
|
|
||||||
LOG(ERROR) << "Could not determine major/minor for: " << params.GetDeviceName();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!MapSnapshot(lock.get(), partition_name, base_device, {}, &ignore_path)) {
|
|
||||||
LOG(ERROR) << "Could not map snapshot for partition: " << partition_name;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG(INFO) << "Created logical partitions with snapshot.";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
|
||||||
|
CreateLogicalPartitionParams params,
|
||||||
|
std::string* path) {
|
||||||
|
CHECK(lock);
|
||||||
|
path->clear();
|
||||||
|
|
||||||
|
// Fill out fields in CreateLogicalPartitionParams so that we have more information (e.g. by
|
||||||
|
// reading super partition metadata).
|
||||||
|
CreateLogicalPartitionParams::OwnedData params_owned_data;
|
||||||
|
if (!params.InitDefaults(¶ms_owned_data)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params.partition->num_extents) {
|
||||||
|
LOG(INFO) << "Skipping zero-length logical partition: " << params.GetPartitionName();
|
||||||
|
return true; // leave path empty to indicate that nothing is mapped.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if there is a live snapshot for the SnapshotStatus of the partition; i.e. if the
|
||||||
|
// partition still has a snapshot that needs to be mapped. If no live snapshot or merge
|
||||||
|
// completed, live_snapshot_status is set to nullopt.
|
||||||
|
std::optional<SnapshotStatus> live_snapshot_status;
|
||||||
|
do {
|
||||||
|
if (!(params.partition->attributes & LP_PARTITION_ATTR_UPDATED)) {
|
||||||
|
LOG(INFO) << "Detected re-flashing of partition, will skip snapshot: "
|
||||||
|
<< params.GetPartitionName();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto file_path = GetSnapshotStatusFilePath(params.GetPartitionName());
|
||||||
|
if (access(file_path.c_str(), F_OK) != 0) {
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
PLOG(INFO) << "Can't map snapshot for " << params.GetPartitionName()
|
||||||
|
<< ": Can't access " << file_path;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
live_snapshot_status = std::make_optional<SnapshotStatus>();
|
||||||
|
if (!ReadSnapshotStatus(lock, params.GetPartitionName(), &*live_snapshot_status)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// No live snapshot if merge is completed.
|
||||||
|
if (live_snapshot_status->state == SnapshotState::MergeCompleted) {
|
||||||
|
live_snapshot_status.reset();
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
if (live_snapshot_status.has_value()) {
|
||||||
|
// dm-snapshot requires the base device to be writable.
|
||||||
|
params.force_writable = true;
|
||||||
|
// Map the base device with a different name to avoid collision.
|
||||||
|
params.device_name = GetBaseDeviceName(params.GetPartitionName());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& dm = DeviceMapper::Instance();
|
||||||
|
std::string ignore_path;
|
||||||
|
if (!CreateLogicalPartition(params, &ignore_path)) {
|
||||||
|
LOG(ERROR) << "Could not create logical partition " << params.GetPartitionName()
|
||||||
|
<< " as device " << params.GetDeviceName();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!live_snapshot_status.has_value()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't have ueventd in first-stage init, so use device major:minor
|
||||||
|
// strings instead.
|
||||||
|
std::string base_device;
|
||||||
|
if (!dm.GetDeviceString(params.GetDeviceName(), &base_device)) {
|
||||||
|
LOG(ERROR) << "Could not determine major/minor for: " << params.GetDeviceName();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!MapSnapshot(lock, params.GetPartitionName(), base_device, {}, path)) {
|
||||||
|
LOG(ERROR) << "Could not map snapshot for partition: " << params.GetPartitionName();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << *path;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue