Loading fs_mgr/libsnapshot/Android.bp +34 −12 Original line number Diff line number Diff line Loading @@ -108,7 +108,7 @@ cc_library_static { ], srcs: [":libsnapshot_sources"], static_libs: [ "libfs_mgr_binder" "libfs_mgr_binder", ], } Loading @@ -128,7 +128,7 @@ cc_library { static_libs: [ "libc++fs", "libsnapshot_cow", ] ], } cc_library_static { Loading Loading @@ -204,6 +204,10 @@ cc_library_static { "libsnapshot_cow/writer_v2.cpp", "libsnapshot_cow/writer_v3.cpp", ], header_libs: [ "libstorage_literals_headers", ], export_include_dirs: ["include"], host_supported: true, recovery_available: true, Loading Loading @@ -243,7 +247,10 @@ cc_library_static { cc_defaults { name: "libsnapshot_test_defaults", defaults: ["libsnapshot_defaults", "libsnapshot_cow_defaults"], defaults: [ "libsnapshot_defaults", "libsnapshot_cow_defaults", ], srcs: [ "partition_cow_creator_test.cpp", "snapshot_metadata_updater_test.cpp", Loading Loading @@ -283,10 +290,13 @@ cc_defaults { cc_test { name: "vts_libsnapshot_test", defaults: ["libsnapshot_test_defaults", "libsnapshot_hal_deps"], defaults: [ "libsnapshot_test_defaults", "libsnapshot_hal_deps", ], test_suites: [ "vts", "device-tests" "device-tests", ], test_options: { min_shipping_api_level: 30, Loading @@ -295,12 +305,15 @@ cc_test { cc_test { name: "vab_legacy_tests", defaults: ["libsnapshot_test_defaults", "libsnapshot_hal_deps"], defaults: [ "libsnapshot_test_defaults", "libsnapshot_hal_deps", ], cppflags: [ "-DLIBSNAPSHOT_TEST_VAB_LEGACY", ], test_suites: [ "device-tests" "device-tests", ], test_options: { // Legacy VAB launched in Android R. Loading @@ -310,12 +323,15 @@ cc_test { cc_test { name: "vabc_legacy_tests", defaults: ["libsnapshot_test_defaults", "libsnapshot_hal_deps"], defaults: [ "libsnapshot_test_defaults", "libsnapshot_hal_deps", ], cppflags: [ "-DLIBSNAPSHOT_TEST_VABC_LEGACY", ], test_suites: [ "device-tests" "device-tests", ], test_options: { // Legacy VABC launched in Android S. Loading Loading @@ -343,7 +359,10 @@ cc_test { cc_binary { name: "snapshotctl", defaults: ["libsnapshot_cow_defaults", "libsnapshot_hal_deps"], defaults: [ "libsnapshot_cow_defaults", "libsnapshot_hal_deps", ], srcs: [ "snapshotctl.cpp", ], Loading Loading @@ -412,8 +431,11 @@ cc_test { "libgtest", "libsnapshot_cow", ], header_libs: [ "libstorage_literals_headers", ], test_suites: [ "device-tests" "device-tests", ], test_options: { min_shipping_api_level: 30, Loading fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +39 −2 Original line number Diff line number Diff line Loading @@ -201,6 +201,12 @@ static constexpr uint64_t kCowOpSourceInfoDataMask = (1ULL << 48) - 1; static constexpr uint64_t kCowOpSourceInfoTypeBit = 60; static constexpr uint64_t kCowOpSourceInfoTypeNumBits = 4; static constexpr uint64_t kCowOpSourceInfoTypeMask = (1ULL << kCowOpSourceInfoTypeNumBits) - 1; static constexpr uint64_t kCowOpSourceInfoCompressionBit = 57; static constexpr uint64_t kCowOpSourceInfoCompressionNumBits = 3; static constexpr uint64_t kCowOpSourceInfoCompressionMask = ((1ULL << kCowOpSourceInfoCompressionNumBits) - 1); // The on disk format of cow (currently == CowOperation) struct CowOperationV3 { // If this operation reads from the data section of the COW, this contains Loading @@ -211,8 +217,8 @@ struct CowOperationV3 { uint32_t new_block; // source_info with have the following layout // |---4 bits ---| ---12 bits---| --- 48 bits ---| // |--- type --- | -- unused -- | --- source --- | // |--- 4 bits -- | --------- 3 bits ------ | --- 9 bits --- | --- 48 bits ---| // |--- type --- | -- compression factor --| --- unused --- | --- source --- | // // The value of |source| depends on the operation code. // Loading @@ -225,6 +231,17 @@ struct CowOperationV3 { // For ops other than Label: // Bits 47-62 are reserved and must be zero. // A block is compressed if it’s data is < block_sz // // Bits [57-59] represents the compression factor. // // Compression - factor // ========================== // 000 - 4k // 001 - 8k // 010 - 16k // ... // 110 - 256k // uint64_t source_info_; constexpr uint64_t source() const { return source_info_ & kCowOpSourceInfoDataMask; } constexpr void set_source(uint64_t source) { Loading @@ -245,6 +262,20 @@ struct CowOperationV3 { source_info_ |= (static_cast<uint64_t>(type) & kCowOpSourceInfoTypeMask) << kCowOpSourceInfoTypeBit; } constexpr void set_compression_bits(uint8_t compression_factor) { // Clear the 3 bits from bit 57 - [57-59] source_info_ &= ~(kCowOpSourceInfoCompressionMask << kCowOpSourceInfoCompressionBit); // Set the actual compression factor source_info_ |= (static_cast<uint64_t>(compression_factor) & kCowOpSourceInfoCompressionMask) << kCowOpSourceInfoCompressionBit; } constexpr uint8_t compression_bits() const { // Grab the 3 bits from [57-59] const auto compression_factor = (source_info_ >> kCowOpSourceInfoCompressionBit) & kCowOpSourceInfoCompressionMask; return static_cast<uint8_t>(compression_factor); } } __attribute__((packed)); // Ensure that getters/setters added to CowOperationV3 does not increases size Loading Loading @@ -326,5 +357,11 @@ bool IsOrderedOp(const CowOperation& op); // Convert compression name to internal value. std::optional<CowCompressionAlgorithm> CompressionAlgorithmFromString(std::string_view name); // Return block size used for compression size_t CowOpCompressionSize(const CowOperation* op, size_t block_size); // Return the relative offset of the I/O block which the CowOperation // multi-block compression bool GetBlockOffset(const CowOperation* op, uint64_t io_block, size_t block_size, off_t* offset); } // namespace snapshot } // namespace android fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +3 −0 Original line number Diff line number Diff line Loading @@ -162,6 +162,9 @@ class CowReader final : public ICowReader { // Creates a clone of the current CowReader without the file handlers std::unique_ptr<CowReader> CloneCowReader(); // Get the max compression size uint32_t GetMaxCompressionSize(); void UpdateMergeOpsCompleted(int num_merge_ops) { header_.num_merge_ops += num_merge_ops; } private: Loading fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +6 −4 Original line number Diff line number Diff line Loading @@ -119,9 +119,9 @@ class ICowWriter { class CompressWorker { public: CompressWorker(std::unique_ptr<ICompressor>&& compressor, uint32_t block_size); CompressWorker(std::unique_ptr<ICompressor>&& compressor); bool RunThread(); void EnqueueCompressBlocks(const void* buffer, size_t num_blocks); void EnqueueCompressBlocks(const void* buffer, size_t block_size, size_t num_blocks); bool GetCompressedBuffers(std::vector<std::basic_string<uint8_t>>* compressed_buf); void Finalize(); static uint32_t GetDefaultCompressionLevel(CowCompressionAlgorithm compression); Loading @@ -134,20 +134,22 @@ class CompressWorker { struct CompressWork { const void* buffer; size_t num_blocks; size_t block_size; bool compression_status = false; std::vector<std::basic_string<uint8_t>> compressed_data; }; std::unique_ptr<ICompressor> compressor_; uint32_t block_size_; std::queue<CompressWork> work_queue_; std::queue<CompressWork> compressed_queue_; std::mutex lock_; std::condition_variable cv_; bool stopped_ = false; size_t total_submitted_ = 0; size_t total_processed_ = 0; bool CompressBlocks(const void* buffer, size_t num_blocks, bool CompressBlocks(const void* buffer, size_t num_blocks, size_t block_size, std::vector<std::basic_string<uint8_t>>* compressed_data); }; Loading fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp +19 −19 Original line number Diff line number Diff line Loading @@ -208,9 +208,9 @@ class ZstdCompressor final : public ICompressor { std::unique_ptr<ZSTD_CCtx, decltype(&ZSTD_freeCCtx)> zstd_context_; }; bool CompressWorker::CompressBlocks(const void* buffer, size_t num_blocks, bool CompressWorker::CompressBlocks(const void* buffer, size_t num_blocks, size_t block_size, std::vector<std::basic_string<uint8_t>>* compressed_data) { return CompressBlocks(compressor_.get(), block_size_, buffer, num_blocks, compressed_data); return CompressBlocks(compressor_.get(), block_size, buffer, num_blocks, compressed_data); } bool CompressWorker::CompressBlocks(ICompressor* compressor, size_t block_size, const void* buffer, Loading @@ -223,7 +223,7 @@ bool CompressWorker::CompressBlocks(ICompressor* compressor, size_t block_size, PLOG(ERROR) << "CompressBlocks: Compression failed"; return false; } if (data.size() > std::numeric_limits<uint16_t>::max()) { if (data.size() > std::numeric_limits<uint32_t>::max()) { LOG(ERROR) << "Compressed block is too large: " << data.size(); return false; } Loading Loading @@ -254,7 +254,8 @@ bool CompressWorker::RunThread() { } // Compress blocks bool ret = CompressBlocks(blocks.buffer, blocks.num_blocks, &blocks.compressed_data); bool ret = CompressBlocks(blocks.buffer, blocks.num_blocks, blocks.block_size, &blocks.compressed_data); blocks.compression_status = ret; { std::lock_guard<std::mutex> lock(lock_); Loading @@ -273,35 +274,31 @@ bool CompressWorker::RunThread() { return true; } void CompressWorker::EnqueueCompressBlocks(const void* buffer, size_t num_blocks) { void CompressWorker::EnqueueCompressBlocks(const void* buffer, size_t block_size, size_t num_blocks) { { std::lock_guard<std::mutex> lock(lock_); CompressWork blocks = {}; blocks.buffer = buffer; blocks.block_size = block_size; blocks.num_blocks = num_blocks; work_queue_.push(std::move(blocks)); total_submitted_ += 1; } cv_.notify_all(); } bool CompressWorker::GetCompressedBuffers(std::vector<std::basic_string<uint8_t>>* compressed_buf) { { while (true) { std::unique_lock<std::mutex> lock(lock_); while (compressed_queue_.empty() && !stopped_) { while ((total_submitted_ != total_processed_) && compressed_queue_.empty() && !stopped_) { cv_.wait(lock); } if (stopped_) { return true; } } { std::lock_guard<std::mutex> lock(lock_); while (compressed_queue_.size() > 0) { CompressWork blocks = std::move(compressed_queue_.front()); compressed_queue_.pop(); total_processed_ += 1; if (blocks.compression_status) { compressed_buf->insert(compressed_buf->end(), Loading @@ -312,10 +309,13 @@ bool CompressWorker::GetCompressedBuffers(std::vector<std::basic_string<uint8_t> return false; } } } if ((total_submitted_ == total_processed_) || stopped_) { total_submitted_ = 0; total_processed_ = 0; return true; } } } std::unique_ptr<ICompressor> ICompressor::Brotli(uint32_t compression_level, const int32_t block_size) { Loading Loading @@ -344,8 +344,8 @@ void CompressWorker::Finalize() { cv_.notify_all(); } CompressWorker::CompressWorker(std::unique_ptr<ICompressor>&& compressor, uint32_t block_size) : compressor_(std::move(compressor)), block_size_(block_size) {} CompressWorker::CompressWorker(std::unique_ptr<ICompressor>&& compressor) : compressor_(std::move(compressor)) {} } // namespace snapshot } // namespace android Loading
fs_mgr/libsnapshot/Android.bp +34 −12 Original line number Diff line number Diff line Loading @@ -108,7 +108,7 @@ cc_library_static { ], srcs: [":libsnapshot_sources"], static_libs: [ "libfs_mgr_binder" "libfs_mgr_binder", ], } Loading @@ -128,7 +128,7 @@ cc_library { static_libs: [ "libc++fs", "libsnapshot_cow", ] ], } cc_library_static { Loading Loading @@ -204,6 +204,10 @@ cc_library_static { "libsnapshot_cow/writer_v2.cpp", "libsnapshot_cow/writer_v3.cpp", ], header_libs: [ "libstorage_literals_headers", ], export_include_dirs: ["include"], host_supported: true, recovery_available: true, Loading Loading @@ -243,7 +247,10 @@ cc_library_static { cc_defaults { name: "libsnapshot_test_defaults", defaults: ["libsnapshot_defaults", "libsnapshot_cow_defaults"], defaults: [ "libsnapshot_defaults", "libsnapshot_cow_defaults", ], srcs: [ "partition_cow_creator_test.cpp", "snapshot_metadata_updater_test.cpp", Loading Loading @@ -283,10 +290,13 @@ cc_defaults { cc_test { name: "vts_libsnapshot_test", defaults: ["libsnapshot_test_defaults", "libsnapshot_hal_deps"], defaults: [ "libsnapshot_test_defaults", "libsnapshot_hal_deps", ], test_suites: [ "vts", "device-tests" "device-tests", ], test_options: { min_shipping_api_level: 30, Loading @@ -295,12 +305,15 @@ cc_test { cc_test { name: "vab_legacy_tests", defaults: ["libsnapshot_test_defaults", "libsnapshot_hal_deps"], defaults: [ "libsnapshot_test_defaults", "libsnapshot_hal_deps", ], cppflags: [ "-DLIBSNAPSHOT_TEST_VAB_LEGACY", ], test_suites: [ "device-tests" "device-tests", ], test_options: { // Legacy VAB launched in Android R. Loading @@ -310,12 +323,15 @@ cc_test { cc_test { name: "vabc_legacy_tests", defaults: ["libsnapshot_test_defaults", "libsnapshot_hal_deps"], defaults: [ "libsnapshot_test_defaults", "libsnapshot_hal_deps", ], cppflags: [ "-DLIBSNAPSHOT_TEST_VABC_LEGACY", ], test_suites: [ "device-tests" "device-tests", ], test_options: { // Legacy VABC launched in Android S. Loading Loading @@ -343,7 +359,10 @@ cc_test { cc_binary { name: "snapshotctl", defaults: ["libsnapshot_cow_defaults", "libsnapshot_hal_deps"], defaults: [ "libsnapshot_cow_defaults", "libsnapshot_hal_deps", ], srcs: [ "snapshotctl.cpp", ], Loading Loading @@ -412,8 +431,11 @@ cc_test { "libgtest", "libsnapshot_cow", ], header_libs: [ "libstorage_literals_headers", ], test_suites: [ "device-tests" "device-tests", ], test_options: { min_shipping_api_level: 30, Loading
fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +39 −2 Original line number Diff line number Diff line Loading @@ -201,6 +201,12 @@ static constexpr uint64_t kCowOpSourceInfoDataMask = (1ULL << 48) - 1; static constexpr uint64_t kCowOpSourceInfoTypeBit = 60; static constexpr uint64_t kCowOpSourceInfoTypeNumBits = 4; static constexpr uint64_t kCowOpSourceInfoTypeMask = (1ULL << kCowOpSourceInfoTypeNumBits) - 1; static constexpr uint64_t kCowOpSourceInfoCompressionBit = 57; static constexpr uint64_t kCowOpSourceInfoCompressionNumBits = 3; static constexpr uint64_t kCowOpSourceInfoCompressionMask = ((1ULL << kCowOpSourceInfoCompressionNumBits) - 1); // The on disk format of cow (currently == CowOperation) struct CowOperationV3 { // If this operation reads from the data section of the COW, this contains Loading @@ -211,8 +217,8 @@ struct CowOperationV3 { uint32_t new_block; // source_info with have the following layout // |---4 bits ---| ---12 bits---| --- 48 bits ---| // |--- type --- | -- unused -- | --- source --- | // |--- 4 bits -- | --------- 3 bits ------ | --- 9 bits --- | --- 48 bits ---| // |--- type --- | -- compression factor --| --- unused --- | --- source --- | // // The value of |source| depends on the operation code. // Loading @@ -225,6 +231,17 @@ struct CowOperationV3 { // For ops other than Label: // Bits 47-62 are reserved and must be zero. // A block is compressed if it’s data is < block_sz // // Bits [57-59] represents the compression factor. // // Compression - factor // ========================== // 000 - 4k // 001 - 8k // 010 - 16k // ... // 110 - 256k // uint64_t source_info_; constexpr uint64_t source() const { return source_info_ & kCowOpSourceInfoDataMask; } constexpr void set_source(uint64_t source) { Loading @@ -245,6 +262,20 @@ struct CowOperationV3 { source_info_ |= (static_cast<uint64_t>(type) & kCowOpSourceInfoTypeMask) << kCowOpSourceInfoTypeBit; } constexpr void set_compression_bits(uint8_t compression_factor) { // Clear the 3 bits from bit 57 - [57-59] source_info_ &= ~(kCowOpSourceInfoCompressionMask << kCowOpSourceInfoCompressionBit); // Set the actual compression factor source_info_ |= (static_cast<uint64_t>(compression_factor) & kCowOpSourceInfoCompressionMask) << kCowOpSourceInfoCompressionBit; } constexpr uint8_t compression_bits() const { // Grab the 3 bits from [57-59] const auto compression_factor = (source_info_ >> kCowOpSourceInfoCompressionBit) & kCowOpSourceInfoCompressionMask; return static_cast<uint8_t>(compression_factor); } } __attribute__((packed)); // Ensure that getters/setters added to CowOperationV3 does not increases size Loading Loading @@ -326,5 +357,11 @@ bool IsOrderedOp(const CowOperation& op); // Convert compression name to internal value. std::optional<CowCompressionAlgorithm> CompressionAlgorithmFromString(std::string_view name); // Return block size used for compression size_t CowOpCompressionSize(const CowOperation* op, size_t block_size); // Return the relative offset of the I/O block which the CowOperation // multi-block compression bool GetBlockOffset(const CowOperation* op, uint64_t io_block, size_t block_size, off_t* offset); } // namespace snapshot } // namespace android
fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +3 −0 Original line number Diff line number Diff line Loading @@ -162,6 +162,9 @@ class CowReader final : public ICowReader { // Creates a clone of the current CowReader without the file handlers std::unique_ptr<CowReader> CloneCowReader(); // Get the max compression size uint32_t GetMaxCompressionSize(); void UpdateMergeOpsCompleted(int num_merge_ops) { header_.num_merge_ops += num_merge_ops; } private: Loading
fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +6 −4 Original line number Diff line number Diff line Loading @@ -119,9 +119,9 @@ class ICowWriter { class CompressWorker { public: CompressWorker(std::unique_ptr<ICompressor>&& compressor, uint32_t block_size); CompressWorker(std::unique_ptr<ICompressor>&& compressor); bool RunThread(); void EnqueueCompressBlocks(const void* buffer, size_t num_blocks); void EnqueueCompressBlocks(const void* buffer, size_t block_size, size_t num_blocks); bool GetCompressedBuffers(std::vector<std::basic_string<uint8_t>>* compressed_buf); void Finalize(); static uint32_t GetDefaultCompressionLevel(CowCompressionAlgorithm compression); Loading @@ -134,20 +134,22 @@ class CompressWorker { struct CompressWork { const void* buffer; size_t num_blocks; size_t block_size; bool compression_status = false; std::vector<std::basic_string<uint8_t>> compressed_data; }; std::unique_ptr<ICompressor> compressor_; uint32_t block_size_; std::queue<CompressWork> work_queue_; std::queue<CompressWork> compressed_queue_; std::mutex lock_; std::condition_variable cv_; bool stopped_ = false; size_t total_submitted_ = 0; size_t total_processed_ = 0; bool CompressBlocks(const void* buffer, size_t num_blocks, bool CompressBlocks(const void* buffer, size_t num_blocks, size_t block_size, std::vector<std::basic_string<uint8_t>>* compressed_data); }; Loading
fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp +19 −19 Original line number Diff line number Diff line Loading @@ -208,9 +208,9 @@ class ZstdCompressor final : public ICompressor { std::unique_ptr<ZSTD_CCtx, decltype(&ZSTD_freeCCtx)> zstd_context_; }; bool CompressWorker::CompressBlocks(const void* buffer, size_t num_blocks, bool CompressWorker::CompressBlocks(const void* buffer, size_t num_blocks, size_t block_size, std::vector<std::basic_string<uint8_t>>* compressed_data) { return CompressBlocks(compressor_.get(), block_size_, buffer, num_blocks, compressed_data); return CompressBlocks(compressor_.get(), block_size, buffer, num_blocks, compressed_data); } bool CompressWorker::CompressBlocks(ICompressor* compressor, size_t block_size, const void* buffer, Loading @@ -223,7 +223,7 @@ bool CompressWorker::CompressBlocks(ICompressor* compressor, size_t block_size, PLOG(ERROR) << "CompressBlocks: Compression failed"; return false; } if (data.size() > std::numeric_limits<uint16_t>::max()) { if (data.size() > std::numeric_limits<uint32_t>::max()) { LOG(ERROR) << "Compressed block is too large: " << data.size(); return false; } Loading Loading @@ -254,7 +254,8 @@ bool CompressWorker::RunThread() { } // Compress blocks bool ret = CompressBlocks(blocks.buffer, blocks.num_blocks, &blocks.compressed_data); bool ret = CompressBlocks(blocks.buffer, blocks.num_blocks, blocks.block_size, &blocks.compressed_data); blocks.compression_status = ret; { std::lock_guard<std::mutex> lock(lock_); Loading @@ -273,35 +274,31 @@ bool CompressWorker::RunThread() { return true; } void CompressWorker::EnqueueCompressBlocks(const void* buffer, size_t num_blocks) { void CompressWorker::EnqueueCompressBlocks(const void* buffer, size_t block_size, size_t num_blocks) { { std::lock_guard<std::mutex> lock(lock_); CompressWork blocks = {}; blocks.buffer = buffer; blocks.block_size = block_size; blocks.num_blocks = num_blocks; work_queue_.push(std::move(blocks)); total_submitted_ += 1; } cv_.notify_all(); } bool CompressWorker::GetCompressedBuffers(std::vector<std::basic_string<uint8_t>>* compressed_buf) { { while (true) { std::unique_lock<std::mutex> lock(lock_); while (compressed_queue_.empty() && !stopped_) { while ((total_submitted_ != total_processed_) && compressed_queue_.empty() && !stopped_) { cv_.wait(lock); } if (stopped_) { return true; } } { std::lock_guard<std::mutex> lock(lock_); while (compressed_queue_.size() > 0) { CompressWork blocks = std::move(compressed_queue_.front()); compressed_queue_.pop(); total_processed_ += 1; if (blocks.compression_status) { compressed_buf->insert(compressed_buf->end(), Loading @@ -312,10 +309,13 @@ bool CompressWorker::GetCompressedBuffers(std::vector<std::basic_string<uint8_t> return false; } } } if ((total_submitted_ == total_processed_) || stopped_) { total_submitted_ = 0; total_processed_ = 0; return true; } } } std::unique_ptr<ICompressor> ICompressor::Brotli(uint32_t compression_level, const int32_t block_size) { Loading Loading @@ -344,8 +344,8 @@ void CompressWorker::Finalize() { cv_.notify_all(); } CompressWorker::CompressWorker(std::unique_ptr<ICompressor>&& compressor, uint32_t block_size) : compressor_(std::move(compressor)), block_size_(block_size) {} CompressWorker::CompressWorker(std::unique_ptr<ICompressor>&& compressor) : compressor_(std::move(compressor)) {} } // namespace snapshot } // namespace android