Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 942b2136 authored by Akilesh Kailash's avatar Akilesh Kailash Committed by Gerrit Code Review
Browse files

Merge changes from topic "ota-block-size-compression" into main

* changes:
  snapuserd: Add I/O path support for variable block size
  libsnapshot_cow: Support multi-block compression
parents 13cb6f7b 3ea911bc
Loading
Loading
Loading
Loading
+34 −12
Original line number Diff line number Diff line
@@ -108,7 +108,7 @@ cc_library_static {
    ],
    srcs: [":libsnapshot_sources"],
    static_libs: [
        "libfs_mgr_binder"
        "libfs_mgr_binder",
    ],
}

@@ -128,7 +128,7 @@ cc_library {
    static_libs: [
        "libc++fs",
        "libsnapshot_cow",
    ]
    ],
}

cc_library_static {
@@ -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,
@@ -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",
@@ -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,
@@ -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.
@@ -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.
@@ -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",
    ],
@@ -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,
+39 −2
Original line number Diff line number Diff line
@@ -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
@@ -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.
    //
@@ -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) {
@@ -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
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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:
+6 −4
Original line number Diff line number Diff line
@@ -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);
@@ -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);
};

+19 −19
Original line number Diff line number Diff line
@@ -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,
@@ -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;
        }
@@ -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_);
@@ -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(),
@@ -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) {
@@ -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