From d0c3a04cb0d4546d621cd6dd88fe0da83d7f1e59 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Mon, 13 Nov 2023 15:56:00 -0800 Subject: [PATCH] libsnapshot: add CowSizeInfo struct Adding a cow size info struct as writer will now need to know the op buffer size at the time of initialization. The sequence of events is as follows (same as estimate_cow_size but putting down here for clarity) 1. ota_from_target_files does dry run to determine cow size + ops buffer size 2. data is passed through delta archive manifest 3. snapshot.cpp parses these fields and confgiures cowoptions struct to pass to writer initialization 4. cow is initialized with correct sizing. Data is incrementally added at the ends of the cow ops buffer (which is why we need to know the sizing ahead of time) Test: ota Change-Id: I950e5ef82c9bd7e9bd9603b0599c930767ee3f0d --- .../include/libsnapshot/cow_writer.h | 10 +++++++--- .../include/libsnapshot/mock_cow_writer.h | 3 +-- fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp | 18 +++++++++--------- fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp | 4 ++-- .../libsnapshot/libsnapshot_cow/writer_v2.cpp | 8 +++++--- fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h | 2 +- .../libsnapshot/libsnapshot_cow/writer_v3.cpp | 7 +++++-- fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h | 2 +- 8 files changed, 31 insertions(+), 23 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h index 5b1e56c44..ca0ebe182 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h @@ -33,7 +33,10 @@ namespace android { namespace snapshot { - +struct CowSizeInfo { + uint64_t cow_size; + uint64_t op_count_max; +}; struct CowOptions { uint32_t block_size = 4096; std::string compression; @@ -92,8 +95,9 @@ class ICowWriter { // to ensure that the correct headers and footers are written. virtual bool Finalize() = 0; - // Return number of bytes the cow image occupies on disk. - virtual uint64_t GetCowSize() = 0; + // Return number of bytes the cow image occupies on disk + the size of sequence && ops buffer + // The latter two fields are used in v3 cow format and left as 0 for v2 cow format + virtual CowSizeInfo GetCowSizeInfo() const = 0; virtual uint32_t GetBlockSize() const = 0; virtual std::optional GetMaxBlocks() const = 0; diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h index c58c6542a..8491fb00d 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h @@ -24,8 +24,7 @@ class MockCowWriter : public ICowWriter { using FileDescriptor = chromeos_update_engine::FileDescriptor; MOCK_METHOD(bool, Finalize, (), (override)); - - MOCK_METHOD(uint64_t, GetCowSize, (), (override)); + MOCK_METHOD(CowSizeInfo, GetCowSizeInfo, (), (const, override)); MOCK_METHOD(bool, AddCopy, (uint64_t, uint64_t, uint64_t), (override)); MOCK_METHOD(bool, AddRawBlocks, (uint64_t, const void*, size_t), (override)); diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp index 49d86d81c..1d1d24c99 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp @@ -601,14 +601,14 @@ TEST_F(CowTest, GetSize) { ASSERT_TRUE(writer.AddCopy(10, 20)); ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size())); ASSERT_TRUE(writer.AddZeroBlocks(51, 2)); - auto size_before = writer.GetCowSize(); + auto size_before = writer.GetCowSizeInfo().cow_size; ASSERT_TRUE(writer.Finalize()); - auto size_after = writer.GetCowSize(); + auto size_after = writer.GetCowSizeInfo().cow_size; ASSERT_EQ(size_before, size_after); struct stat buf; ASSERT_GE(fstat(cow_->fd, &buf), 0) << strerror(errno); - ASSERT_EQ(buf.st_size, writer.GetCowSize()); + ASSERT_EQ(buf.st_size, writer.GetCowSizeInfo().cow_size); } TEST_F(CowTest, AppendLabelSmall) { @@ -637,7 +637,7 @@ TEST_F(CowTest, AppendLabelSmall) { struct stat buf; ASSERT_EQ(fstat(cow_->fd, &buf), 0); - ASSERT_EQ(buf.st_size, writer->GetCowSize()); + ASSERT_EQ(buf.st_size, writer->GetCowSizeInfo().cow_size); // Read back both operations, and label. CowReader reader; @@ -690,7 +690,7 @@ TEST_F(CowTest, AppendLabelMissing) { ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size())); ASSERT_TRUE(writer->AddLabel(1)); // Drop the tail end of the last op header, corrupting it. - ftruncate(cow_->fd, writer->GetCowSize() - sizeof(CowFooter) - 3); + ftruncate(cow_->fd, writer->GetCowSizeInfo().cow_size - sizeof(CowFooter) - 3); ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0); @@ -705,7 +705,7 @@ TEST_F(CowTest, AppendLabelMissing) { struct stat buf; ASSERT_EQ(fstat(cow_->fd, &buf), 0); - ASSERT_EQ(buf.st_size, writer->GetCowSize()); + ASSERT_EQ(buf.st_size, writer->GetCowSizeInfo().cow_size); // Read back both operations. CowReader reader; @@ -763,7 +763,7 @@ TEST_F(CowTest, AppendExtendedCorrupted) { struct stat buf; ASSERT_EQ(fstat(cow_->fd, &buf), 0); - ASSERT_EQ(buf.st_size, writer->GetCowSize()); + ASSERT_EQ(buf.st_size, writer->GetCowSizeInfo().cow_size); // Read back all valid operations CowReader reader; @@ -812,7 +812,7 @@ TEST_F(CowTest, AppendbyLabel) { struct stat buf; ASSERT_EQ(fstat(cow_->fd, &buf), 0); - ASSERT_EQ(buf.st_size, writer->GetCowSize()); + ASSERT_EQ(buf.st_size, writer->GetCowSizeInfo().cow_size); // Read back all ops CowReader reader; @@ -989,7 +989,7 @@ TEST_F(CowTest, ClusterAppendTest) { struct stat buf; ASSERT_EQ(fstat(cow_->fd, &buf), 0); - ASSERT_EQ(buf.st_size, writer->GetCowSize()); + ASSERT_EQ(buf.st_size, writer->GetCowSizeInfo().cow_size); // Read back both operations, plus cluster op at end CowReader reader; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp index 3383a5862..8cf46f42e 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp @@ -658,14 +658,14 @@ TEST_F(CowTestV3, CowSizeEstimate) { options.compression = "none"; auto estimator = android::snapshot::CreateCowEstimator(3, options); ASSERT_TRUE(estimator->AddZeroBlocks(0, 1024 * 1024)); - const auto cow_size = estimator->GetCowSize(); + const auto cow_size = estimator->GetCowSizeInfo().cow_size; options.op_count_max = 1024 * 1024; options.max_blocks = 1024 * 1024; CowWriterV3 writer(options, GetCowFd()); ASSERT_TRUE(writer.Initialize()); ASSERT_TRUE(writer.AddZeroBlocks(0, 1024 * 1024)); - ASSERT_LE(writer.GetCowSize(), cow_size); + ASSERT_LE(writer.GetCowSizeInfo().cow_size, cow_size); } TEST_F(CowTestV3, CopyOpMany) { diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp index f9a4e479e..75cd1114d 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp @@ -576,12 +576,14 @@ bool CowWriterV2::Finalize() { return Sync(); } -uint64_t CowWriterV2::GetCowSize() { +CowSizeInfo CowWriterV2::GetCowSizeInfo() const { + CowSizeInfo info; if (current_data_size_ > 0) { - return next_data_pos_ + sizeof(footer_); + info.cow_size = next_data_pos_ + sizeof(footer_); } else { - return next_op_pos_ + sizeof(footer_); + info.cow_size = next_op_pos_ + sizeof(footer_); } + return info; } bool CowWriterV2::GetDataPos(uint64_t* pos) { diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h index 50e635ffd..05de2ade2 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.h @@ -27,7 +27,7 @@ class CowWriterV2 : public CowWriterBase { bool Initialize(std::optional label = {}) override; bool Finalize() override; - uint64_t GetCowSize() override; + CowSizeInfo GetCowSizeInfo() const override; protected: virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override; diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp index d99e6e6d6..824fa39c7 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp @@ -491,8 +491,11 @@ bool CowWriterV3::Finalize() { return Sync(); } -uint64_t CowWriterV3::GetCowSize() { - return next_data_pos_; +CowSizeInfo CowWriterV3::GetCowSizeInfo() const { + CowSizeInfo info; + info.cow_size = next_data_pos_; + info.op_count_max = header_.op_count_max; + return info; } } // namespace snapshot diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h index 3a7b87789..73ac52011 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h @@ -30,7 +30,7 @@ class CowWriterV3 : public CowWriterBase { bool Initialize(std::optional label = {}) override; bool Finalize() override; - uint64_t GetCowSize() override; + CowSizeInfo GetCowSizeInfo() const override; protected: virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;