Convert SnapshotStatus to proto
Also, add a "name" field to SnapshotStatus, and delete the "name" arg from CreateSnapshot / WriteSnapshotStatus. ReadSnapshotStatus will warn if the name mismatches from the file name, and auto-correct it. Test: libsnapshot_test Change-Id: I725cf39c07684b100b140a8a21ea9d23ab9d2241
This commit is contained in:
parent
58ae8d4780
commit
5fcc2b5d71
|
@ -49,11 +49,17 @@ cc_defaults {
|
|||
"libfiemap_headers",
|
||||
],
|
||||
export_include_dirs: ["include"],
|
||||
proto: {
|
||||
type: "lite",
|
||||
export_proto_headers: true,
|
||||
canonical_path_from_root: false,
|
||||
},
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "libsnapshot_sources",
|
||||
srcs: [
|
||||
"android/snapshot/snapshot.proto",
|
||||
"snapshot.cpp",
|
||||
"snapshot_metadata_updater.cpp",
|
||||
"partition_cow_creator.cpp",
|
||||
|
@ -132,9 +138,10 @@ cc_binary {
|
|||
"libbinder",
|
||||
"libext4_utils",
|
||||
"libfs_mgr",
|
||||
"libutils",
|
||||
"liblog",
|
||||
"liblp",
|
||||
"libprotobuf-cpp-lite",
|
||||
"libutils",
|
||||
],
|
||||
init_rc: [
|
||||
"snapshotctl.rc",
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright (C) 2019 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto3";
|
||||
package android.snapshot;
|
||||
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
// Next: 4
|
||||
enum SnapshotState {
|
||||
// No snapshot is found.
|
||||
NONE = 0;
|
||||
|
||||
// The snapshot has been created and possibly written to. Rollbacks are
|
||||
// possible by destroying the snapshot.
|
||||
CREATED = 1;
|
||||
|
||||
// Changes are being merged. No rollbacks are possible beyond this point.
|
||||
MERGING = 2;
|
||||
|
||||
// Changes have been merged, Future reboots may map the base device
|
||||
// directly.
|
||||
MERGE_COMPLETED = 3;
|
||||
}
|
||||
|
||||
// Next: 9
|
||||
message SnapshotStatus {
|
||||
// Name of the snapshot. This is usually the name of the snapshotted
|
||||
// logical partition; for example, "system_b".
|
||||
string name = 1;
|
||||
|
||||
SnapshotState state = 2;
|
||||
|
||||
// Size of the full (base) device.
|
||||
uint64 device_size = 3;
|
||||
|
||||
// Size of the snapshot. This is the sum of lengths of ranges in the base
|
||||
// device that needs to be snapshotted during the update.
|
||||
// This must be less than or equal to |device_size|.
|
||||
// This value is 0 if no snapshot is needed for this device because
|
||||
// no changes
|
||||
uint64 snapshot_size = 4;
|
||||
|
||||
// Size of the "COW partition". A COW partition is a special logical
|
||||
// partition represented in the super partition metadata. This partition and
|
||||
// the "COW image" form the "COW device" that supports the snapshot device.
|
||||
//
|
||||
// When SnapshotManager creates a COW device, it first searches for unused
|
||||
// blocks in the super partition, and use those before creating the COW
|
||||
// image if the COW partition is not big enough.
|
||||
//
|
||||
// This value is 0 if no space in super is left for the COW partition.
|
||||
// |cow_partition_size + cow_file_size| must not be zero if |snapshot_size|
|
||||
// is non-zero.
|
||||
uint64 cow_partition_size = 5;
|
||||
|
||||
// Size of the "COW file", or "COW image". A COW file / image is created
|
||||
// when the "COW partition" is not big enough to store changes to the
|
||||
// snapshot device.
|
||||
//
|
||||
// This value is 0 if |cow_partition_size| is big enough to hold all changes
|
||||
// to the snapshot device.
|
||||
uint64 cow_file_size = 6;
|
||||
|
||||
// Sectors allocated for the COW device. Recording this value right after
|
||||
// the update and before the merge allows us to infer the progress of the
|
||||
// merge process.
|
||||
// This is non-zero when |state| == MERGING or MERGE_COMPLETED.
|
||||
uint64 sectors_allocated = 7;
|
||||
|
||||
// Metadata sectors allocated for the COW device. Recording this value right
|
||||
// before the update and before the merge allows us to infer the progress of
|
||||
// the merge process.
|
||||
// This is non-zero when |state| == MERGING or MERGE_COMPLETED.
|
||||
uint64 metadata_sectors = 8;
|
||||
}
|
|
@ -53,8 +53,9 @@ namespace snapshot {
|
|||
|
||||
struct AutoDeleteCowImage;
|
||||
struct AutoDeleteSnapshot;
|
||||
struct PartitionCowCreator;
|
||||
struct AutoDeviceList;
|
||||
struct PartitionCowCreator;
|
||||
class SnapshotStatus;
|
||||
|
||||
static constexpr const std::string_view kCowGroupName = "cow";
|
||||
|
||||
|
@ -250,22 +251,6 @@ class SnapshotManager final {
|
|||
std::unique_ptr<LockedFile> OpenFile(const std::string& file, int open_flags, int lock_flags);
|
||||
bool Truncate(LockedFile* file);
|
||||
|
||||
enum class SnapshotState : int { None, Created, Merging, MergeCompleted };
|
||||
static std::string to_string(SnapshotState state);
|
||||
|
||||
// This state is persisted per-snapshot in /metadata/ota/snapshots/.
|
||||
struct SnapshotStatus {
|
||||
SnapshotState state = SnapshotState::None;
|
||||
uint64_t device_size = 0;
|
||||
uint64_t snapshot_size = 0;
|
||||
uint64_t cow_partition_size = 0;
|
||||
uint64_t cow_file_size = 0;
|
||||
|
||||
// These are non-zero when merging.
|
||||
uint64_t sectors_allocated = 0;
|
||||
uint64_t metadata_sectors = 0;
|
||||
};
|
||||
|
||||
// Create a new snapshot record. This creates the backing COW store and
|
||||
// persists information needed to map the device. The device can be mapped
|
||||
// with MapSnapshot().
|
||||
|
@ -282,7 +267,7 @@ class SnapshotManager final {
|
|||
//
|
||||
// All sizes are specified in bytes, and the device, snapshot, COW partition and COW file sizes
|
||||
// must be a multiple of the sector size (512 bytes).
|
||||
bool CreateSnapshot(LockedFile* lock, const std::string& name, SnapshotStatus status);
|
||||
bool CreateSnapshot(LockedFile* lock, SnapshotStatus* status);
|
||||
|
||||
// |name| should be the base partition name (e.g. "system_a"). Create the
|
||||
// backing COW image using the size previously passed to CreateSnapshot().
|
||||
|
@ -363,8 +348,7 @@ class SnapshotManager final {
|
|||
UpdateState CheckTargetMergeState(LockedFile* lock, const std::string& name);
|
||||
|
||||
// Interact with status files under /metadata/ota/snapshots.
|
||||
bool WriteSnapshotStatus(LockedFile* lock, const std::string& name,
|
||||
const SnapshotStatus& status);
|
||||
bool WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status);
|
||||
bool ReadSnapshotStatus(LockedFile* lock, const std::string& name, SnapshotStatus* status);
|
||||
std::string GetSnapshotStatusFilePath(const std::string& name);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <android/snapshot/snapshot.pb.h>
|
||||
#include "utility.h"
|
||||
|
||||
using android::dm::kSectorSize;
|
||||
|
@ -84,13 +85,14 @@ std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() {
|
|||
<< "logical_block_size is not power of 2";
|
||||
|
||||
Return ret;
|
||||
ret.snapshot_status.device_size = target_partition->size();
|
||||
ret.snapshot_status.set_name(target_partition->name());
|
||||
ret.snapshot_status.set_device_size(target_partition->size());
|
||||
|
||||
// TODO(b/141889746): Optimize by using a smaller snapshot. Some ranges in target_partition
|
||||
// may be written directly.
|
||||
ret.snapshot_status.snapshot_size = target_partition->size();
|
||||
ret.snapshot_status.set_snapshot_size(target_partition->size());
|
||||
|
||||
auto cow_size = GetCowSize(ret.snapshot_status.snapshot_size);
|
||||
auto cow_size = GetCowSize(ret.snapshot_status.snapshot_size());
|
||||
if (!cow_size.has_value()) return std::nullopt;
|
||||
|
||||
// Compute regions that are free in both current and target metadata. These are the regions
|
||||
|
@ -106,18 +108,20 @@ std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() {
|
|||
LOG(INFO) << "Remaining free space for COW: " << free_region_length << " bytes";
|
||||
|
||||
// Compute the COW partition size.
|
||||
ret.snapshot_status.cow_partition_size = std::min(*cow_size, free_region_length);
|
||||
uint64_t cow_partition_size = std::min(*cow_size, free_region_length);
|
||||
// Round it down to the nearest logical block. Logical partitions must be a multiple
|
||||
// of logical blocks.
|
||||
ret.snapshot_status.cow_partition_size &= ~(logical_block_size - 1);
|
||||
cow_partition_size &= ~(logical_block_size - 1);
|
||||
ret.snapshot_status.set_cow_partition_size(cow_partition_size);
|
||||
// Assign cow_partition_usable_regions to indicate what regions should the COW partition uses.
|
||||
ret.cow_partition_usable_regions = std::move(free_regions);
|
||||
|
||||
// The rest of the COW space is allocated on ImageManager.
|
||||
ret.snapshot_status.cow_file_size = (*cow_size) - ret.snapshot_status.cow_partition_size;
|
||||
uint64_t cow_file_size = (*cow_size) - ret.snapshot_status.cow_partition_size();
|
||||
// Round it up to the nearest sector.
|
||||
ret.snapshot_status.cow_file_size += kSectorSize - 1;
|
||||
ret.snapshot_status.cow_file_size &= ~(kSectorSize - 1);
|
||||
cow_file_size += kSectorSize - 1;
|
||||
cow_file_size &= ~(kSectorSize - 1);
|
||||
ret.snapshot_status.set_cow_file_size(cow_file_size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -20,8 +20,9 @@
|
|||
#include <string>
|
||||
|
||||
#include <liblp/builder.h>
|
||||
#include <update_engine/update_metadata.pb.h>
|
||||
|
||||
#include <libsnapshot/snapshot.h>
|
||||
#include <android/snapshot/snapshot.pb.h>
|
||||
|
||||
namespace android {
|
||||
namespace snapshot {
|
||||
|
@ -51,7 +52,7 @@ struct PartitionCowCreator {
|
|||
const RepeatedPtrField<InstallOperation>* operations = nullptr;
|
||||
|
||||
struct Return {
|
||||
SnapshotManager::SnapshotStatus snapshot_status;
|
||||
SnapshotStatus snapshot_status;
|
||||
std::vector<Interval> cow_partition_usable_regions;
|
||||
};
|
||||
|
||||
|
|
|
@ -51,8 +51,8 @@ TEST_F(PartitionCowCreatorTest, IntersectSelf) {
|
|||
.current_suffix = "_a"};
|
||||
auto ret = creator.Run();
|
||||
ASSERT_TRUE(ret.has_value());
|
||||
ASSERT_EQ(40 * 1024, ret->snapshot_status.device_size);
|
||||
ASSERT_EQ(40 * 1024, ret->snapshot_status.snapshot_size);
|
||||
ASSERT_EQ(40 * 1024, ret->snapshot_status.device_size());
|
||||
ASSERT_EQ(40 * 1024, ret->snapshot_status.snapshot_size());
|
||||
}
|
||||
|
||||
TEST_F(PartitionCowCreatorTest, Holes) {
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <libfiemap/image_manager.h>
|
||||
#include <liblp/liblp.h>
|
||||
|
||||
#include <android/snapshot/snapshot.pb.h>
|
||||
#include "partition_cow_creator.h"
|
||||
#include "snapshot_metadata_updater.h"
|
||||
#include "utility.h"
|
||||
|
@ -234,42 +235,50 @@ bool SnapshotManager::FinishedSnapshotWrites() {
|
|||
return WriteUpdateState(lock.get(), UpdateState::Unverified);
|
||||
}
|
||||
|
||||
bool SnapshotManager::CreateSnapshot(LockedFile* lock, const std::string& name,
|
||||
SnapshotManager::SnapshotStatus status) {
|
||||
bool SnapshotManager::CreateSnapshot(LockedFile* lock, SnapshotStatus* status) {
|
||||
CHECK(lock);
|
||||
CHECK(lock->lock_mode() == LOCK_EX);
|
||||
CHECK(status);
|
||||
|
||||
if (status->name().empty()) {
|
||||
LOG(ERROR) << "SnapshotStatus has no name.";
|
||||
return false;
|
||||
}
|
||||
// Sanity check these sizes. Like liblp, we guarantee the partition size
|
||||
// is respected, which means it has to be sector-aligned. (This guarantee
|
||||
// is useful for locating avb footers correctly). The COW file size, however,
|
||||
// can be arbitrarily larger than specified, so we can safely round it up.
|
||||
if (status.device_size % kSectorSize != 0) {
|
||||
LOG(ERROR) << "Snapshot " << name
|
||||
<< " device size is not a multiple of the sector size: " << status.device_size;
|
||||
if (status->device_size() % kSectorSize != 0) {
|
||||
LOG(ERROR) << "Snapshot " << status->name()
|
||||
<< " device size is not a multiple of the sector size: "
|
||||
<< status->device_size();
|
||||
return false;
|
||||
}
|
||||
if (status.snapshot_size % kSectorSize != 0) {
|
||||
LOG(ERROR) << "Snapshot " << name << " snapshot size is not a multiple of the sector size: "
|
||||
<< status.snapshot_size;
|
||||
if (status->snapshot_size() % kSectorSize != 0) {
|
||||
LOG(ERROR) << "Snapshot " << status->name()
|
||||
<< " snapshot size is not a multiple of the sector size: "
|
||||
<< status->snapshot_size();
|
||||
return false;
|
||||
}
|
||||
if (status.cow_partition_size % kSectorSize != 0) {
|
||||
LOG(ERROR) << "Snapshot " << name
|
||||
if (status->cow_partition_size() % kSectorSize != 0) {
|
||||
LOG(ERROR) << "Snapshot " << status->name()
|
||||
<< " cow partition size is not a multiple of the sector size: "
|
||||
<< status.cow_partition_size;
|
||||
<< status->cow_partition_size();
|
||||
return false;
|
||||
}
|
||||
if (status.cow_file_size % kSectorSize != 0) {
|
||||
LOG(ERROR) << "Snapshot " << name << " cow file size is not a multiple of the sector size: "
|
||||
<< status.cow_partition_size;
|
||||
if (status->cow_file_size() % kSectorSize != 0) {
|
||||
LOG(ERROR) << "Snapshot " << status->name()
|
||||
<< " cow file size is not a multiple of the sector size: "
|
||||
<< status->cow_file_size();
|
||||
return false;
|
||||
}
|
||||
|
||||
status.state = SnapshotState::Created;
|
||||
status.sectors_allocated = 0;
|
||||
status.metadata_sectors = 0;
|
||||
status->set_state(SnapshotState::CREATED);
|
||||
status->set_sectors_allocated(0);
|
||||
status->set_metadata_sectors(0);
|
||||
|
||||
if (!WriteSnapshotStatus(lock, name, status)) {
|
||||
PLOG(ERROR) << "Could not write snapshot status: " << name;
|
||||
if (!WriteSnapshotStatus(lock, *status)) {
|
||||
PLOG(ERROR) << "Could not write snapshot status: " << status->name();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -287,15 +296,15 @@ bool SnapshotManager::CreateCowImage(LockedFile* lock, const std::string& name)
|
|||
|
||||
// The COW file size should have been rounded up to the nearest sector in CreateSnapshot.
|
||||
// Sanity check this.
|
||||
if (status.cow_file_size % kSectorSize != 0) {
|
||||
if (status.cow_file_size() % kSectorSize != 0) {
|
||||
LOG(ERROR) << "Snapshot " << name << " COW file size is not a multiple of the sector size: "
|
||||
<< status.cow_file_size;
|
||||
<< status.cow_file_size();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string cow_image_name = GetCowImageDeviceName(name);
|
||||
int cow_flags = IImageManager::CREATE_IMAGE_DEFAULT;
|
||||
return images_->CreateBackingImage(cow_image_name, status.cow_file_size, cow_flags);
|
||||
return images_->CreateBackingImage(cow_image_name, status.cow_file_size(), cow_flags);
|
||||
}
|
||||
|
||||
bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name,
|
||||
|
@ -309,7 +318,7 @@ bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name,
|
|||
if (!ReadSnapshotStatus(lock, name, &status)) {
|
||||
return false;
|
||||
}
|
||||
if (status.state == SnapshotState::MergeCompleted) {
|
||||
if (status.state() == SnapshotState::MERGE_COMPLETED) {
|
||||
LOG(ERROR) << "Should not create a snapshot device for " << name
|
||||
<< " after merging has completed.";
|
||||
return false;
|
||||
|
@ -328,24 +337,23 @@ bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name,
|
|||
PLOG(ERROR) << "Could not determine block device size: " << base_device;
|
||||
return false;
|
||||
}
|
||||
if (status.device_size != dev_size) {
|
||||
if (status.device_size() != dev_size) {
|
||||
LOG(ERROR) << "Block device size for " << base_device << " does not match"
|
||||
<< "(expected " << status.device_size << ", got " << dev_size << ")";
|
||||
<< "(expected " << status.device_size() << ", got " << dev_size << ")";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (status.device_size % kSectorSize != 0) {
|
||||
LOG(ERROR) << "invalid blockdev size for " << base_device << ": " << status.device_size;
|
||||
if (status.device_size() % kSectorSize != 0) {
|
||||
LOG(ERROR) << "invalid blockdev size for " << base_device << ": " << status.device_size();
|
||||
return false;
|
||||
}
|
||||
if (status.snapshot_size % kSectorSize != 0 || status.snapshot_size > status.device_size) {
|
||||
LOG(ERROR) << "Invalid snapshot size for " << base_device << ": " << status.snapshot_size;
|
||||
if (status.snapshot_size() % kSectorSize != 0 ||
|
||||
status.snapshot_size() > status.device_size()) {
|
||||
LOG(ERROR) << "Invalid snapshot size for " << base_device << ": " << status.snapshot_size();
|
||||
return false;
|
||||
}
|
||||
uint64_t snapshot_sectors = status.snapshot_size / kSectorSize;
|
||||
uint64_t linear_sectors = (status.device_size - status.snapshot_size) / kSectorSize;
|
||||
|
||||
|
||||
uint64_t snapshot_sectors = status.snapshot_size() / kSectorSize;
|
||||
uint64_t linear_sectors = (status.device_size() - status.snapshot_size()) / kSectorSize;
|
||||
|
||||
auto& dm = DeviceMapper::Instance();
|
||||
|
||||
|
@ -557,8 +565,9 @@ bool SnapshotManager::SwitchSnapshotToMerge(LockedFile* lock, const std::string&
|
|||
if (!ReadSnapshotStatus(lock, name, &status)) {
|
||||
return false;
|
||||
}
|
||||
if (status.state != SnapshotState::Created) {
|
||||
LOG(WARNING) << "Snapshot " << name << " has unexpected state: " << to_string(status.state);
|
||||
if (status.state() != SnapshotState::CREATED) {
|
||||
LOG(WARNING) << "Snapshot " << name
|
||||
<< " has unexpected state: " << SnapshotState_Name(status.state());
|
||||
}
|
||||
|
||||
// After this, we return true because we technically did switch to a merge
|
||||
|
@ -568,15 +577,15 @@ bool SnapshotManager::SwitchSnapshotToMerge(LockedFile* lock, const std::string&
|
|||
return false;
|
||||
}
|
||||
|
||||
status.state = SnapshotState::Merging;
|
||||
status.set_state(SnapshotState::MERGING);
|
||||
|
||||
DmTargetSnapshot::Status dm_status;
|
||||
if (!QuerySnapshotStatus(dm_name, nullptr, &dm_status)) {
|
||||
LOG(ERROR) << "Could not query merge status for snapshot: " << dm_name;
|
||||
}
|
||||
status.sectors_allocated = dm_status.sectors_allocated;
|
||||
status.metadata_sectors = dm_status.metadata_sectors;
|
||||
if (!WriteSnapshotStatus(lock, name, status)) {
|
||||
status.set_sectors_allocated(dm_status.sectors_allocated);
|
||||
status.set_metadata_sectors(dm_status.metadata_sectors);
|
||||
if (!WriteSnapshotStatus(lock, status)) {
|
||||
LOG(ERROR) << "Could not update status file for snapshot: " << name;
|
||||
}
|
||||
return true;
|
||||
|
@ -821,7 +830,7 @@ UpdateState SnapshotManager::CheckTargetMergeState(LockedFile* lock, const std::
|
|||
// rebooted after this check, the device will still be a snapshot-merge
|
||||
// target. If the have rebooted, the device will now be a linear target,
|
||||
// and we can try cleanup again.
|
||||
if (snapshot_status.state == SnapshotState::MergeCompleted) {
|
||||
if (snapshot_status.state() == SnapshotState::MERGE_COMPLETED) {
|
||||
// NB: It's okay if this fails now, we gave cleanup our best effort.
|
||||
OnSnapshotMergeComplete(lock, name, snapshot_status);
|
||||
return UpdateState::MergeCompleted;
|
||||
|
@ -849,7 +858,7 @@ UpdateState SnapshotManager::CheckTargetMergeState(LockedFile* lock, const std::
|
|||
|
||||
// These two values are equal when merging is complete.
|
||||
if (status.sectors_allocated != status.metadata_sectors) {
|
||||
if (snapshot_status.state == SnapshotState::MergeCompleted) {
|
||||
if (snapshot_status.state() == SnapshotState::MERGE_COMPLETED) {
|
||||
LOG(ERROR) << "Snapshot " << name << " is merging after being marked merge-complete.";
|
||||
return UpdateState::MergeFailed;
|
||||
}
|
||||
|
@ -864,8 +873,8 @@ UpdateState SnapshotManager::CheckTargetMergeState(LockedFile* lock, const std::
|
|||
// This makes it simpler to reason about the next reboot: no matter what
|
||||
// part of cleanup failed, first-stage init won't try to create another
|
||||
// snapshot device for this partition.
|
||||
snapshot_status.state = SnapshotState::MergeCompleted;
|
||||
if (!WriteSnapshotStatus(lock, name, snapshot_status)) {
|
||||
snapshot_status.set_state(SnapshotState::MERGE_COMPLETED);
|
||||
if (!WriteSnapshotStatus(lock, snapshot_status)) {
|
||||
return UpdateState::MergeFailed;
|
||||
}
|
||||
if (!OnSnapshotMergeComplete(lock, name, snapshot_status)) {
|
||||
|
@ -969,10 +978,10 @@ bool SnapshotManager::CollapseSnapshotDevice(const std::string& name,
|
|||
return false;
|
||||
}
|
||||
|
||||
uint64_t snapshot_sectors = status.snapshot_size / kSectorSize;
|
||||
if (snapshot_sectors * kSectorSize != status.snapshot_size) {
|
||||
uint64_t snapshot_sectors = status.snapshot_size() / kSectorSize;
|
||||
if (snapshot_sectors * kSectorSize != status.snapshot_size()) {
|
||||
LOG(ERROR) << "Snapshot " << name
|
||||
<< " size is not sector aligned: " << status.snapshot_size;
|
||||
<< " size is not sector aligned: " << status.snapshot_size();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1003,7 +1012,7 @@ bool SnapshotManager::CollapseSnapshotDevice(const std::string& name,
|
|||
<< " sectors, got: " << outer_table[0].spec.length;
|
||||
return false;
|
||||
}
|
||||
uint64_t expected_device_sectors = status.device_size / kSectorSize;
|
||||
uint64_t expected_device_sectors = status.device_size() / kSectorSize;
|
||||
uint64_t actual_device_sectors = outer_table[0].spec.length + outer_table[1].spec.length;
|
||||
if (expected_device_sectors != actual_device_sectors) {
|
||||
LOG(ERROR) << "Outer device " << name << " should have " << expected_device_sectors
|
||||
|
@ -1289,7 +1298,7 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
|
|||
return false;
|
||||
}
|
||||
// No live snapshot if merge is completed.
|
||||
if (live_snapshot_status->state == SnapshotState::MergeCompleted) {
|
||||
if (live_snapshot_status->state() == SnapshotState::MERGE_COMPLETED) {
|
||||
live_snapshot_status.reset();
|
||||
}
|
||||
} while (0);
|
||||
|
@ -1390,7 +1399,7 @@ bool SnapshotManager::MapCowDevices(LockedFile* lock, const CreateLogicalPartiti
|
|||
AutoDeviceList* created_devices, std::string* cow_name) {
|
||||
CHECK(lock);
|
||||
if (!EnsureImageManager()) return false;
|
||||
CHECK(snapshot_status.cow_partition_size + snapshot_status.cow_file_size > 0);
|
||||
CHECK(snapshot_status.cow_partition_size() + snapshot_status.cow_file_size() > 0);
|
||||
auto begin = std::chrono::steady_clock::now();
|
||||
|
||||
std::string partition_name = params.GetPartitionName();
|
||||
|
@ -1400,7 +1409,7 @@ bool SnapshotManager::MapCowDevices(LockedFile* lock, const CreateLogicalPartiti
|
|||
auto& dm = DeviceMapper::Instance();
|
||||
|
||||
// Map COW image if necessary.
|
||||
if (snapshot_status.cow_file_size > 0) {
|
||||
if (snapshot_status.cow_file_size() > 0) {
|
||||
auto remaining_time = GetRemainingTime(params.timeout_ms, begin);
|
||||
if (remaining_time.count() < 0) return false;
|
||||
|
||||
|
@ -1411,7 +1420,7 @@ bool SnapshotManager::MapCowDevices(LockedFile* lock, const CreateLogicalPartiti
|
|||
created_devices->EmplaceBack<AutoUnmapImage>(images_.get(), cow_image_name);
|
||||
|
||||
// If no COW partition exists, just return the image alone.
|
||||
if (snapshot_status.cow_partition_size == 0) {
|
||||
if (snapshot_status.cow_partition_size() == 0) {
|
||||
*cow_name = std::move(cow_image_name);
|
||||
LOG(INFO) << "Mapped COW image for " << partition_name << " at " << *cow_name;
|
||||
return true;
|
||||
|
@ -1421,7 +1430,7 @@ bool SnapshotManager::MapCowDevices(LockedFile* lock, const CreateLogicalPartiti
|
|||
auto remaining_time = GetRemainingTime(params.timeout_ms, begin);
|
||||
if (remaining_time.count() < 0) return false;
|
||||
|
||||
CHECK(snapshot_status.cow_partition_size > 0);
|
||||
CHECK(snapshot_status.cow_partition_size() > 0);
|
||||
|
||||
// Create the DmTable for the COW device. It is the DmTable of the COW partition plus
|
||||
// COW image device as the last extent.
|
||||
|
@ -1434,14 +1443,14 @@ bool SnapshotManager::MapCowDevices(LockedFile* lock, const CreateLogicalPartiti
|
|||
return false;
|
||||
}
|
||||
// If the COW image exists, append it as the last extent.
|
||||
if (snapshot_status.cow_file_size > 0) {
|
||||
if (snapshot_status.cow_file_size() > 0) {
|
||||
std::string cow_image_device;
|
||||
if (!dm.GetDeviceString(cow_image_name, &cow_image_device)) {
|
||||
LOG(ERROR) << "Cannot determine major/minor for: " << cow_image_name;
|
||||
return false;
|
||||
}
|
||||
auto cow_partition_sectors = snapshot_status.cow_partition_size / kSectorSize;
|
||||
auto cow_image_sectors = snapshot_status.cow_file_size / kSectorSize;
|
||||
auto cow_partition_sectors = snapshot_status.cow_partition_size() / kSectorSize;
|
||||
auto cow_image_sectors = snapshot_status.cow_file_size() / kSectorSize;
|
||||
table.Emplace<DmTargetLinear>(cow_partition_sectors, cow_image_sectors, cow_image_device,
|
||||
0);
|
||||
}
|
||||
|
@ -1602,101 +1611,38 @@ bool SnapshotManager::ReadSnapshotStatus(LockedFile* lock, const std::string& na
|
|||
return false;
|
||||
}
|
||||
|
||||
std::string contents;
|
||||
if (!android::base::ReadFdToString(fd, &contents)) {
|
||||
PLOG(ERROR) << "read failed: " << path;
|
||||
return false;
|
||||
}
|
||||
auto pieces = android::base::Split(contents, " ");
|
||||
if (pieces.size() != 7) {
|
||||
LOG(ERROR) << "Invalid status line for snapshot: " << path;
|
||||
if (!status->ParseFromFileDescriptor(fd.get())) {
|
||||
PLOG(ERROR) << "Unable to parse " << path << " as SnapshotStatus";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pieces[0] == "none") {
|
||||
status->state = SnapshotState::None;
|
||||
} else if (pieces[0] == "created") {
|
||||
status->state = SnapshotState::Created;
|
||||
} else if (pieces[0] == "merging") {
|
||||
status->state = SnapshotState::Merging;
|
||||
} else if (pieces[0] == "merge-completed") {
|
||||
status->state = SnapshotState::MergeCompleted;
|
||||
} else {
|
||||
LOG(ERROR) << "Unrecognized state " << pieces[0] << " for snapshot: " << name;
|
||||
return false;
|
||||
if (status->name() != name) {
|
||||
LOG(WARNING) << "Found snapshot status named " << status->name() << " in " << path;
|
||||
status->set_name(name);
|
||||
}
|
||||
|
||||
if (!android::base::ParseUint(pieces[1], &status->device_size)) {
|
||||
LOG(ERROR) << "Invalid device size in status line for: " << path;
|
||||
return false;
|
||||
}
|
||||
if (!android::base::ParseUint(pieces[2], &status->snapshot_size)) {
|
||||
LOG(ERROR) << "Invalid snapshot size in status line for: " << path;
|
||||
return false;
|
||||
}
|
||||
if (!android::base::ParseUint(pieces[3], &status->cow_partition_size)) {
|
||||
LOG(ERROR) << "Invalid cow linear size in status line for: " << path;
|
||||
return false;
|
||||
}
|
||||
if (!android::base::ParseUint(pieces[4], &status->cow_file_size)) {
|
||||
LOG(ERROR) << "Invalid cow file size in status line for: " << path;
|
||||
return false;
|
||||
}
|
||||
if (!android::base::ParseUint(pieces[5], &status->sectors_allocated)) {
|
||||
LOG(ERROR) << "Invalid snapshot size in status line for: " << path;
|
||||
return false;
|
||||
}
|
||||
if (!android::base::ParseUint(pieces[6], &status->metadata_sectors)) {
|
||||
LOG(ERROR) << "Invalid snapshot size in status line for: " << path;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string SnapshotManager::to_string(SnapshotState state) {
|
||||
switch (state) {
|
||||
case SnapshotState::None:
|
||||
return "none";
|
||||
case SnapshotState::Created:
|
||||
return "created";
|
||||
case SnapshotState::Merging:
|
||||
return "merging";
|
||||
case SnapshotState::MergeCompleted:
|
||||
return "merge-completed";
|
||||
default:
|
||||
LOG(ERROR) << "Unknown snapshot state: " << (int)state;
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
bool SnapshotManager::WriteSnapshotStatus(LockedFile* lock, const std::string& name,
|
||||
const SnapshotStatus& status) {
|
||||
bool SnapshotManager::WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status) {
|
||||
// The caller must take an exclusive lock to modify snapshots.
|
||||
CHECK(lock);
|
||||
CHECK(lock->lock_mode() == LOCK_EX);
|
||||
CHECK(!status.name().empty());
|
||||
|
||||
auto path = GetSnapshotStatusFilePath(name);
|
||||
unique_fd fd(open(path.c_str(), O_RDWR | O_CLOEXEC | O_NOFOLLOW | O_CREAT | O_SYNC, 0660));
|
||||
auto path = GetSnapshotStatusFilePath(status.name());
|
||||
unique_fd fd(
|
||||
open(path.c_str(), O_RDWR | O_CLOEXEC | O_NOFOLLOW | O_CREAT | O_SYNC | O_TRUNC, 0660));
|
||||
if (fd < 0) {
|
||||
PLOG(ERROR) << "Open failed: " << path;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> pieces = {
|
||||
to_string(status.state),
|
||||
std::to_string(status.device_size),
|
||||
std::to_string(status.snapshot_size),
|
||||
std::to_string(status.cow_partition_size),
|
||||
std::to_string(status.cow_file_size),
|
||||
std::to_string(status.sectors_allocated),
|
||||
std::to_string(status.metadata_sectors),
|
||||
};
|
||||
auto contents = android::base::Join(pieces, " ");
|
||||
|
||||
if (!android::base::WriteStringToFd(contents, fd)) {
|
||||
PLOG(ERROR) << "write failed: " << path;
|
||||
if (!status.SerializeToFileDescriptor(fd.get())) {
|
||||
PLOG(ERROR) << "Unable to write SnapshotStatus to " << path;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1714,7 +1660,7 @@ bool SnapshotManager::Truncate(LockedFile* file) {
|
|||
|
||||
std::string SnapshotManager::GetSnapshotDeviceName(const std::string& snapshot_name,
|
||||
const SnapshotStatus& status) {
|
||||
if (status.device_size != status.snapshot_size) {
|
||||
if (status.device_size() != status.snapshot_size()) {
|
||||
return GetSnapshotExtraDeviceName(snapshot_name);
|
||||
}
|
||||
return snapshot_name;
|
||||
|
@ -1884,11 +1830,11 @@ bool SnapshotManager::CreateUpdateSnapshotsInternal(
|
|||
}
|
||||
|
||||
LOG(INFO) << "For partition " << target_partition->name()
|
||||
<< ", device size = " << cow_creator_ret->snapshot_status.device_size
|
||||
<< ", snapshot size = " << cow_creator_ret->snapshot_status.snapshot_size
|
||||
<< ", device size = " << cow_creator_ret->snapshot_status.device_size()
|
||||
<< ", snapshot size = " << cow_creator_ret->snapshot_status.snapshot_size()
|
||||
<< ", cow partition size = "
|
||||
<< cow_creator_ret->snapshot_status.cow_partition_size
|
||||
<< ", cow file size = " << cow_creator_ret->snapshot_status.cow_file_size;
|
||||
<< cow_creator_ret->snapshot_status.cow_partition_size()
|
||||
<< ", cow file size = " << cow_creator_ret->snapshot_status.cow_file_size();
|
||||
|
||||
// Delete any existing snapshot before re-creating one.
|
||||
if (!DeleteSnapshot(lock, target_partition->name())) {
|
||||
|
@ -1899,9 +1845,9 @@ bool SnapshotManager::CreateUpdateSnapshotsInternal(
|
|||
|
||||
// It is possible that the whole partition uses free space in super, and snapshot / COW
|
||||
// would not be needed. In this case, skip the partition.
|
||||
bool needs_snapshot = cow_creator_ret->snapshot_status.snapshot_size > 0;
|
||||
bool needs_cow = (cow_creator_ret->snapshot_status.cow_partition_size +
|
||||
cow_creator_ret->snapshot_status.cow_file_size) > 0;
|
||||
bool needs_snapshot = cow_creator_ret->snapshot_status.snapshot_size() > 0;
|
||||
bool needs_cow = (cow_creator_ret->snapshot_status.cow_partition_size() +
|
||||
cow_creator_ret->snapshot_status.cow_file_size()) > 0;
|
||||
CHECK(needs_snapshot == needs_cow);
|
||||
|
||||
if (!needs_snapshot) {
|
||||
|
@ -1911,17 +1857,17 @@ bool SnapshotManager::CreateUpdateSnapshotsInternal(
|
|||
}
|
||||
|
||||
// Store these device sizes to snapshot status file.
|
||||
if (!CreateSnapshot(lock, target_partition->name(), cow_creator_ret->snapshot_status)) {
|
||||
if (!CreateSnapshot(lock, &cow_creator_ret->snapshot_status)) {
|
||||
return false;
|
||||
}
|
||||
created_devices->EmplaceBack<AutoDeleteSnapshot>(this, lock, target_partition->name());
|
||||
|
||||
// Create the COW partition. That is, use any remaining free space in super partition before
|
||||
// creating the COW images.
|
||||
if (cow_creator_ret->snapshot_status.cow_partition_size > 0) {
|
||||
CHECK(cow_creator_ret->snapshot_status.cow_partition_size % kSectorSize == 0)
|
||||
if (cow_creator_ret->snapshot_status.cow_partition_size() > 0) {
|
||||
CHECK(cow_creator_ret->snapshot_status.cow_partition_size() % kSectorSize == 0)
|
||||
<< "cow_partition_size == "
|
||||
<< cow_creator_ret->snapshot_status.cow_partition_size
|
||||
<< cow_creator_ret->snapshot_status.cow_partition_size()
|
||||
<< " is not a multiple of sector size " << kSectorSize;
|
||||
auto cow_partition = target_metadata->AddPartition(GetCowName(target_partition->name()),
|
||||
kCowGroupName, 0 /* flags */);
|
||||
|
@ -1930,10 +1876,10 @@ bool SnapshotManager::CreateUpdateSnapshotsInternal(
|
|||
}
|
||||
|
||||
if (!target_metadata->ResizePartition(
|
||||
cow_partition, cow_creator_ret->snapshot_status.cow_partition_size,
|
||||
cow_partition, cow_creator_ret->snapshot_status.cow_partition_size(),
|
||||
cow_creator_ret->cow_partition_usable_regions)) {
|
||||
LOG(ERROR) << "Cannot create COW partition on metadata with size "
|
||||
<< cow_creator_ret->snapshot_status.cow_partition_size;
|
||||
<< cow_creator_ret->snapshot_status.cow_partition_size();
|
||||
return false;
|
||||
}
|
||||
// Only the in-memory target_metadata is modified; nothing to clean up if there is an
|
||||
|
@ -1941,7 +1887,7 @@ bool SnapshotManager::CreateUpdateSnapshotsInternal(
|
|||
}
|
||||
|
||||
// Create the backing COW image if necessary.
|
||||
if (cow_creator_ret->snapshot_status.cow_file_size > 0) {
|
||||
if (cow_creator_ret->snapshot_status.cow_file_size() > 0) {
|
||||
if (!CreateCowImage(lock, target_partition->name())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2049,13 +1995,13 @@ bool SnapshotManager::Dump(std::ostream& os) {
|
|||
ok = false;
|
||||
continue;
|
||||
}
|
||||
ss << " state: " << to_string(status.state) << std::endl;
|
||||
ss << " device size (bytes): " << status.device_size << std::endl;
|
||||
ss << " snapshot size (bytes): " << status.snapshot_size << std::endl;
|
||||
ss << " cow partition size (bytes): " << status.cow_partition_size << std::endl;
|
||||
ss << " cow file size (bytes): " << status.cow_file_size << std::endl;
|
||||
ss << " allocated sectors: " << status.sectors_allocated << std::endl;
|
||||
ss << " metadata sectors: " << status.metadata_sectors << std::endl;
|
||||
ss << " state: " << SnapshotState_Name(status.state()) << std::endl;
|
||||
ss << " device size (bytes): " << status.device_size() << std::endl;
|
||||
ss << " snapshot size (bytes): " << status.snapshot_size() << std::endl;
|
||||
ss << " cow partition size (bytes): " << status.cow_partition_size() << std::endl;
|
||||
ss << " cow file size (bytes): " << status.cow_file_size() << std::endl;
|
||||
ss << " allocated sectors: " << status.sectors_allocated() << std::endl;
|
||||
ss << " metadata sectors: " << status.metadata_sectors() << std::endl;
|
||||
}
|
||||
os << ss.rdbuf();
|
||||
return ok;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <liblp/builder.h>
|
||||
#include <storage_literals/storage_literals.h>
|
||||
|
||||
#include <android/snapshot/snapshot.pb.h>
|
||||
#include "test_helpers.h"
|
||||
#include "utility.h"
|
||||
|
||||
|
@ -272,10 +273,12 @@ TEST_F(SnapshotTest, CreateSnapshot) {
|
|||
ASSERT_TRUE(AcquireLock());
|
||||
|
||||
static const uint64_t kDeviceSize = 1024 * 1024;
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
|
||||
{.device_size = kDeviceSize,
|
||||
.snapshot_size = kDeviceSize,
|
||||
.cow_file_size = kDeviceSize}));
|
||||
SnapshotStatus status;
|
||||
status.set_name("test-snapshot");
|
||||
status.set_device_size(kDeviceSize);
|
||||
status.set_snapshot_size(kDeviceSize);
|
||||
status.set_cow_file_size(kDeviceSize);
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
|
||||
ASSERT_TRUE(CreateCowImage("test-snapshot"));
|
||||
|
||||
std::vector<std::string> snapshots;
|
||||
|
@ -285,11 +288,11 @@ TEST_F(SnapshotTest, CreateSnapshot) {
|
|||
|
||||
// Scope so delete can re-acquire the snapshot file lock.
|
||||
{
|
||||
SnapshotManager::SnapshotStatus status;
|
||||
SnapshotStatus status;
|
||||
ASSERT_TRUE(sm->ReadSnapshotStatus(lock_.get(), "test-snapshot", &status));
|
||||
ASSERT_EQ(status.state, SnapshotManager::SnapshotState::Created);
|
||||
ASSERT_EQ(status.device_size, kDeviceSize);
|
||||
ASSERT_EQ(status.snapshot_size, kDeviceSize);
|
||||
ASSERT_EQ(status.state(), SnapshotState::CREATED);
|
||||
ASSERT_EQ(status.device_size(), kDeviceSize);
|
||||
ASSERT_EQ(status.snapshot_size(), kDeviceSize);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(sm->UnmapSnapshot(lock_.get(), "test-snapshot"));
|
||||
|
@ -301,10 +304,12 @@ TEST_F(SnapshotTest, MapSnapshot) {
|
|||
ASSERT_TRUE(AcquireLock());
|
||||
|
||||
static const uint64_t kDeviceSize = 1024 * 1024;
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
|
||||
{.device_size = kDeviceSize,
|
||||
.snapshot_size = kDeviceSize,
|
||||
.cow_file_size = kDeviceSize}));
|
||||
SnapshotStatus status;
|
||||
status.set_name("test-snapshot");
|
||||
status.set_device_size(kDeviceSize);
|
||||
status.set_snapshot_size(kDeviceSize);
|
||||
status.set_cow_file_size(kDeviceSize);
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
|
||||
ASSERT_TRUE(CreateCowImage("test-snapshot"));
|
||||
|
||||
std::string base_device;
|
||||
|
@ -324,10 +329,12 @@ TEST_F(SnapshotTest, MapPartialSnapshot) {
|
|||
|
||||
static const uint64_t kSnapshotSize = 1024 * 1024;
|
||||
static const uint64_t kDeviceSize = 1024 * 1024 * 2;
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
|
||||
{.device_size = kDeviceSize,
|
||||
.snapshot_size = kSnapshotSize,
|
||||
.cow_file_size = kSnapshotSize}));
|
||||
SnapshotStatus status;
|
||||
status.set_name("test-snapshot");
|
||||
status.set_device_size(kDeviceSize);
|
||||
status.set_snapshot_size(kSnapshotSize);
|
||||
status.set_cow_file_size(kSnapshotSize);
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
|
||||
ASSERT_TRUE(CreateCowImage("test-snapshot"));
|
||||
|
||||
std::string base_device;
|
||||
|
@ -377,10 +384,12 @@ TEST_F(SnapshotTest, Merge) {
|
|||
ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
|
||||
ASSERT_TRUE(MapUpdatePartitions());
|
||||
ASSERT_TRUE(dm_.GetDmDevicePathByName("test_partition_b-base", &base_device));
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
|
||||
{.device_size = kDeviceSize,
|
||||
.snapshot_size = kDeviceSize,
|
||||
.cow_file_size = kDeviceSize}));
|
||||
SnapshotStatus status;
|
||||
status.set_name("test_partition_b");
|
||||
status.set_device_size(kDeviceSize);
|
||||
status.set_snapshot_size(kDeviceSize);
|
||||
status.set_cow_file_size(kDeviceSize);
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
|
||||
ASSERT_TRUE(CreateCowImage("test_partition_b"));
|
||||
ASSERT_TRUE(MapCowImage("test_partition_b", 10s, &cow_device));
|
||||
ASSERT_TRUE(sm->MapSnapshot(lock_.get(), "test_partition_b", base_device, cow_device, 10s,
|
||||
|
@ -436,10 +445,12 @@ TEST_F(SnapshotTest, MergeCannotRemoveCow) {
|
|||
ASSERT_TRUE(AcquireLock());
|
||||
|
||||
static const uint64_t kDeviceSize = 1024 * 1024;
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test-snapshot",
|
||||
{.device_size = kDeviceSize,
|
||||
.snapshot_size = kDeviceSize,
|
||||
.cow_file_size = kDeviceSize}));
|
||||
SnapshotStatus status;
|
||||
status.set_name("test-snapshot");
|
||||
status.set_device_size(kDeviceSize);
|
||||
status.set_snapshot_size(kDeviceSize);
|
||||
status.set_cow_file_size(kDeviceSize);
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
|
||||
ASSERT_TRUE(CreateCowImage("test-snapshot"));
|
||||
|
||||
std::string base_device, cow_device, snap_device;
|
||||
|
@ -492,10 +503,12 @@ TEST_F(SnapshotTest, FirstStageMountAndMerge) {
|
|||
|
||||
ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
|
||||
ASSERT_TRUE(MapUpdatePartitions());
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
|
||||
{.device_size = kDeviceSize,
|
||||
.snapshot_size = kDeviceSize,
|
||||
.cow_file_size = kDeviceSize}));
|
||||
SnapshotStatus status;
|
||||
status.set_name("test_partition_b");
|
||||
status.set_device_size(kDeviceSize);
|
||||
status.set_snapshot_size(kDeviceSize);
|
||||
status.set_cow_file_size(kDeviceSize);
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
|
||||
ASSERT_TRUE(CreateCowImage("test_partition_b"));
|
||||
|
||||
// Simulate a reboot into the new slot.
|
||||
|
@ -511,9 +524,8 @@ TEST_F(SnapshotTest, FirstStageMountAndMerge) {
|
|||
ASSERT_TRUE(AcquireLock());
|
||||
|
||||
// Validate that we have a snapshot device.
|
||||
SnapshotManager::SnapshotStatus status;
|
||||
ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
|
||||
ASSERT_EQ(status.state, SnapshotManager::SnapshotState::Created);
|
||||
ASSERT_EQ(status.state(), SnapshotState::CREATED);
|
||||
|
||||
DeviceMapper::TargetInfo target;
|
||||
auto dm_name = init->GetSnapshotDeviceName("test_partition_b", status);
|
||||
|
@ -528,10 +540,12 @@ TEST_F(SnapshotTest, FlashSuperDuringUpdate) {
|
|||
|
||||
ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
|
||||
ASSERT_TRUE(MapUpdatePartitions());
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
|
||||
{.device_size = kDeviceSize,
|
||||
.snapshot_size = kDeviceSize,
|
||||
.cow_file_size = kDeviceSize}));
|
||||
SnapshotStatus status;
|
||||
status.set_name("test_partition_b");
|
||||
status.set_device_size(kDeviceSize);
|
||||
status.set_snapshot_size(kDeviceSize);
|
||||
status.set_cow_file_size(kDeviceSize);
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
|
||||
ASSERT_TRUE(CreateCowImage("test_partition_b"));
|
||||
|
||||
// Simulate a reboot into the new slot.
|
||||
|
@ -550,7 +564,6 @@ TEST_F(SnapshotTest, FlashSuperDuringUpdate) {
|
|||
|
||||
ASSERT_TRUE(AcquireLock());
|
||||
|
||||
SnapshotManager::SnapshotStatus status;
|
||||
ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
|
||||
|
||||
// We should not get a snapshot device now.
|
||||
|
@ -570,10 +583,12 @@ TEST_F(SnapshotTest, FlashSuperDuringMerge) {
|
|||
|
||||
ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
|
||||
ASSERT_TRUE(MapUpdatePartitions());
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b",
|
||||
{.device_size = kDeviceSize,
|
||||
.snapshot_size = kDeviceSize,
|
||||
.cow_file_size = kDeviceSize}));
|
||||
SnapshotStatus status;
|
||||
status.set_name("test_partition_b");
|
||||
status.set_device_size(kDeviceSize);
|
||||
status.set_snapshot_size(kDeviceSize);
|
||||
status.set_cow_file_size(kDeviceSize);
|
||||
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
|
||||
ASSERT_TRUE(CreateCowImage("test_partition_b"));
|
||||
|
||||
// Simulate a reboot into the new slot.
|
||||
|
@ -699,11 +714,11 @@ class SnapshotUpdateTest : public SnapshotTest {
|
|||
}
|
||||
auto local_lock = std::move(lock_);
|
||||
|
||||
SnapshotManager::SnapshotStatus status;
|
||||
SnapshotStatus status;
|
||||
if (!sm->ReadSnapshotStatus(local_lock.get(), name, &status)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return status.snapshot_size;
|
||||
return status.snapshot_size();
|
||||
}
|
||||
|
||||
AssertionResult UnmapAll() {
|
||||
|
@ -869,8 +884,9 @@ TEST_F(SnapshotUpdateTest, SnapshotStatusFileWithoutCow) {
|
|||
{
|
||||
ASSERT_TRUE(AcquireLock());
|
||||
auto local_lock = std::move(lock_);
|
||||
ASSERT_TRUE(sm->WriteSnapshotStatus(local_lock.get(), "sys_b",
|
||||
SnapshotManager::SnapshotStatus{}));
|
||||
SnapshotStatus status;
|
||||
status.set_name("sys_b");
|
||||
ASSERT_TRUE(sm->WriteSnapshotStatus(local_lock.get(), status));
|
||||
ASSERT_TRUE(image_manager_->CreateBackingImage("sys_b-cow-img", 1_MiB,
|
||||
IImageManager::CREATE_IMAGE_DEFAULT));
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ LOCAL_STATIC_LIBRARIES := \
|
|||
libbacktrace \
|
||||
libmodprobe \
|
||||
libext2_uuid \
|
||||
libprotobuf-cpp-lite \
|
||||
libsnapshot_nobinder \
|
||||
|
||||
LOCAL_SANITIZE := signed-integer-overflow
|
||||
|
|
Loading…
Reference in New Issue