Loading fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +4 −0 Original line number Original line Diff line number Diff line Loading @@ -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_; Loading fs_mgr/libsnapshot/snapshot.cpp +82 −54 Original line number Original line Diff line number Diff line Loading @@ -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> Loading Loading @@ -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); Loading @@ -1151,45 +1136,86 @@ 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, }; }; std::string ignore_path; if (!MapPartitionWithSnapshot(lock.get(), std::move(params), &ignore_path)) { return false; } } if (auto iter = live_snapshots.find(partition_name); iter != live_snapshots.end()) { LOG(INFO) << "Created logical partitions with snapshot."; // If the device has a snapshot, it'll need to be writable, and return true; // we'll need to create the logical partition with a marked-up name } // (since the snapshot will use the partition name). 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; params.force_writable = true; params.device_name = GetBaseDeviceName(partition_name); // 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; std::string ignore_path; if (!CreateLogicalPartition(params, &ignore_path)) { if (!CreateLogicalPartition(params, &ignore_path)) { LOG(ERROR) << "Could not create logical partition " << partition_name << " as device " LOG(ERROR) << "Could not create logical partition " << params.GetPartitionName() << params.GetDeviceName(); << " as device " << params.GetDeviceName(); return false; return false; } } if (!params.force_writable) { if (!live_snapshot_status.has_value()) { // No snapshot. return true; continue; } } // We don't have ueventd in first-stage init, so use device major:minor // We don't have ueventd in first-stage init, so use device major:minor Loading @@ -1199,11 +1225,13 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions(const std::string& supe LOG(ERROR) << "Could not determine major/minor for: " << params.GetDeviceName(); LOG(ERROR) << "Could not determine major/minor for: " << params.GetDeviceName(); return false; return false; } } if (!MapSnapshot(lock.get(), partition_name, base_device, {}, &ignore_path)) { if (!MapSnapshot(lock, params.GetPartitionName(), base_device, {}, path)) { LOG(ERROR) << "Could not map snapshot for partition: " << partition_name; LOG(ERROR) << "Could not map snapshot for partition: " << params.GetPartitionName(); return false; return false; } } } LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << *path; return true; return true; } } Loading Loading
fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +4 −0 Original line number Original line Diff line number Diff line Loading @@ -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_; Loading
fs_mgr/libsnapshot/snapshot.cpp +82 −54 Original line number Original line Diff line number Diff line Loading @@ -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> Loading Loading @@ -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); Loading @@ -1151,45 +1136,86 @@ 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, }; }; std::string ignore_path; if (!MapPartitionWithSnapshot(lock.get(), std::move(params), &ignore_path)) { return false; } } if (auto iter = live_snapshots.find(partition_name); iter != live_snapshots.end()) { LOG(INFO) << "Created logical partitions with snapshot."; // If the device has a snapshot, it'll need to be writable, and return true; // we'll need to create the logical partition with a marked-up name } // (since the snapshot will use the partition name). 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; params.force_writable = true; params.device_name = GetBaseDeviceName(partition_name); // 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; std::string ignore_path; if (!CreateLogicalPartition(params, &ignore_path)) { if (!CreateLogicalPartition(params, &ignore_path)) { LOG(ERROR) << "Could not create logical partition " << partition_name << " as device " LOG(ERROR) << "Could not create logical partition " << params.GetPartitionName() << params.GetDeviceName(); << " as device " << params.GetDeviceName(); return false; return false; } } if (!params.force_writable) { if (!live_snapshot_status.has_value()) { // No snapshot. return true; continue; } } // We don't have ueventd in first-stage init, so use device major:minor // We don't have ueventd in first-stage init, so use device major:minor Loading @@ -1199,11 +1225,13 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions(const std::string& supe LOG(ERROR) << "Could not determine major/minor for: " << params.GetDeviceName(); LOG(ERROR) << "Could not determine major/minor for: " << params.GetDeviceName(); return false; return false; } } if (!MapSnapshot(lock.get(), partition_name, base_device, {}, &ignore_path)) { if (!MapSnapshot(lock, params.GetPartitionName(), base_device, {}, path)) { LOG(ERROR) << "Could not map snapshot for partition: " << partition_name; LOG(ERROR) << "Could not map snapshot for partition: " << params.GetPartitionName(); return false; return false; } } } LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << *path; return true; return true; } } Loading