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 Original line Diff line number Diff line
@@ -108,7 +108,7 @@ cc_library_static {
    ],
    ],
    srcs: [":libsnapshot_sources"],
    srcs: [":libsnapshot_sources"],
    static_libs: [
    static_libs: [
        "libfs_mgr_binder"
        "libfs_mgr_binder",
    ],
    ],
}
}


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


cc_library_static {
cc_library_static {
@@ -204,6 +204,10 @@ cc_library_static {
        "libsnapshot_cow/writer_v2.cpp",
        "libsnapshot_cow/writer_v2.cpp",
        "libsnapshot_cow/writer_v3.cpp",
        "libsnapshot_cow/writer_v3.cpp",
    ],
    ],

    header_libs: [
        "libstorage_literals_headers",
    ],
    export_include_dirs: ["include"],
    export_include_dirs: ["include"],
    host_supported: true,
    host_supported: true,
    recovery_available: true,
    recovery_available: true,
@@ -243,7 +247,10 @@ cc_library_static {


cc_defaults {
cc_defaults {
    name: "libsnapshot_test_defaults",
    name: "libsnapshot_test_defaults",
    defaults: ["libsnapshot_defaults", "libsnapshot_cow_defaults"],
    defaults: [
        "libsnapshot_defaults",
        "libsnapshot_cow_defaults",
    ],
    srcs: [
    srcs: [
        "partition_cow_creator_test.cpp",
        "partition_cow_creator_test.cpp",
        "snapshot_metadata_updater_test.cpp",
        "snapshot_metadata_updater_test.cpp",
@@ -283,10 +290,13 @@ cc_defaults {


cc_test {
cc_test {
    name: "vts_libsnapshot_test",
    name: "vts_libsnapshot_test",
    defaults: ["libsnapshot_test_defaults", "libsnapshot_hal_deps"],
    defaults: [
        "libsnapshot_test_defaults",
        "libsnapshot_hal_deps",
    ],
    test_suites: [
    test_suites: [
        "vts",
        "vts",
        "device-tests"
        "device-tests",
    ],
    ],
    test_options: {
    test_options: {
        min_shipping_api_level: 30,
        min_shipping_api_level: 30,
@@ -295,12 +305,15 @@ cc_test {


cc_test {
cc_test {
    name: "vab_legacy_tests",
    name: "vab_legacy_tests",
    defaults: ["libsnapshot_test_defaults", "libsnapshot_hal_deps"],
    defaults: [
        "libsnapshot_test_defaults",
        "libsnapshot_hal_deps",
    ],
    cppflags: [
    cppflags: [
        "-DLIBSNAPSHOT_TEST_VAB_LEGACY",
        "-DLIBSNAPSHOT_TEST_VAB_LEGACY",
    ],
    ],
    test_suites: [
    test_suites: [
        "device-tests"
        "device-tests",
    ],
    ],
    test_options: {
    test_options: {
        // Legacy VAB launched in Android R.
        // Legacy VAB launched in Android R.
@@ -310,12 +323,15 @@ cc_test {


cc_test {
cc_test {
    name: "vabc_legacy_tests",
    name: "vabc_legacy_tests",
    defaults: ["libsnapshot_test_defaults", "libsnapshot_hal_deps"],
    defaults: [
        "libsnapshot_test_defaults",
        "libsnapshot_hal_deps",
    ],
    cppflags: [
    cppflags: [
        "-DLIBSNAPSHOT_TEST_VABC_LEGACY",
        "-DLIBSNAPSHOT_TEST_VABC_LEGACY",
    ],
    ],
    test_suites: [
    test_suites: [
        "device-tests"
        "device-tests",
    ],
    ],
    test_options: {
    test_options: {
        // Legacy VABC launched in Android S.
        // Legacy VABC launched in Android S.
@@ -343,7 +359,10 @@ cc_test {


cc_binary {
cc_binary {
    name: "snapshotctl",
    name: "snapshotctl",
    defaults: ["libsnapshot_cow_defaults", "libsnapshot_hal_deps"],
    defaults: [
        "libsnapshot_cow_defaults",
        "libsnapshot_hal_deps",
    ],
    srcs: [
    srcs: [
        "snapshotctl.cpp",
        "snapshotctl.cpp",
    ],
    ],
@@ -412,8 +431,11 @@ cc_test {
        "libgtest",
        "libgtest",
        "libsnapshot_cow",
        "libsnapshot_cow",
    ],
    ],
    header_libs: [
        "libstorage_literals_headers",
    ],
    test_suites: [
    test_suites: [
        "device-tests"
        "device-tests",
    ],
    ],
    test_options: {
    test_options: {
        min_shipping_api_level: 30,
        min_shipping_api_level: 30,
+39 −2
Original line number Original line 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 kCowOpSourceInfoTypeBit = 60;
static constexpr uint64_t kCowOpSourceInfoTypeNumBits = 4;
static constexpr uint64_t kCowOpSourceInfoTypeNumBits = 4;
static constexpr uint64_t kCowOpSourceInfoTypeMask = (1ULL << kCowOpSourceInfoTypeNumBits) - 1;
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)
// The on disk format of cow (currently ==  CowOperation)
struct CowOperationV3 {
struct CowOperationV3 {
    // If this operation reads from the data section of the COW, this contains
    // If this operation reads from the data section of the COW, this contains
@@ -211,8 +217,8 @@ struct CowOperationV3 {
    uint32_t new_block;
    uint32_t new_block;


    // source_info with have the following layout
    // source_info with have the following layout
    // |---4 bits ---| ---12 bits---| --- 48 bits ---|
    // |--- 4 bits -- | --------- 3 bits ------ | --- 9 bits --- | --- 48 bits ---|
    // |--- type --- | -- unused -- | --- source --- |
    // |--- type ---  | -- compression factor --| --- unused --- | --- source --- |
    //
    //
    // The value of |source| depends on the operation code.
    // The value of |source| depends on the operation code.
    //
    //
@@ -225,6 +231,17 @@ struct CowOperationV3 {
    // For ops other than Label:
    // For ops other than Label:
    //  Bits 47-62 are reserved and must be zero.
    //  Bits 47-62 are reserved and must be zero.
    // A block is compressed if it’s data is < block_sz
    // 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_;
    uint64_t source_info_;
    constexpr uint64_t source() const { return source_info_ & kCowOpSourceInfoDataMask; }
    constexpr uint64_t source() const { return source_info_ & kCowOpSourceInfoDataMask; }
    constexpr void set_source(uint64_t source) {
    constexpr void set_source(uint64_t source) {
@@ -245,6 +262,20 @@ struct CowOperationV3 {
        source_info_ |= (static_cast<uint64_t>(type) & kCowOpSourceInfoTypeMask)
        source_info_ |= (static_cast<uint64_t>(type) & kCowOpSourceInfoTypeMask)
                        << kCowOpSourceInfoTypeBit;
                        << 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));
} __attribute__((packed));


// Ensure that getters/setters added to CowOperationV3 does not increases size
// 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.
// Convert compression name to internal value.
std::optional<CowCompressionAlgorithm> CompressionAlgorithmFromString(std::string_view name);
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 snapshot
}  // namespace android
}  // namespace android
+3 −0
Original line number Original line 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
    // Creates a clone of the current CowReader without the file handlers
    std::unique_ptr<CowReader> CloneCowReader();
    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; }
    void UpdateMergeOpsCompleted(int num_merge_ops) { header_.num_merge_ops += num_merge_ops; }


  private:
  private:
+6 −4
Original line number Original line Diff line number Diff line
@@ -119,9 +119,9 @@ class ICowWriter {


class CompressWorker {
class CompressWorker {
  public:
  public:
    CompressWorker(std::unique_ptr<ICompressor>&& compressor, uint32_t block_size);
    CompressWorker(std::unique_ptr<ICompressor>&& compressor);
    bool RunThread();
    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);
    bool GetCompressedBuffers(std::vector<std::basic_string<uint8_t>>* compressed_buf);
    void Finalize();
    void Finalize();
    static uint32_t GetDefaultCompressionLevel(CowCompressionAlgorithm compression);
    static uint32_t GetDefaultCompressionLevel(CowCompressionAlgorithm compression);
@@ -134,20 +134,22 @@ class CompressWorker {
    struct CompressWork {
    struct CompressWork {
        const void* buffer;
        const void* buffer;
        size_t num_blocks;
        size_t num_blocks;
        size_t block_size;
        bool compression_status = false;
        bool compression_status = false;
        std::vector<std::basic_string<uint8_t>> compressed_data;
        std::vector<std::basic_string<uint8_t>> compressed_data;
    };
    };


    std::unique_ptr<ICompressor> compressor_;
    std::unique_ptr<ICompressor> compressor_;
    uint32_t block_size_;


    std::queue<CompressWork> work_queue_;
    std::queue<CompressWork> work_queue_;
    std::queue<CompressWork> compressed_queue_;
    std::queue<CompressWork> compressed_queue_;
    std::mutex lock_;
    std::mutex lock_;
    std::condition_variable cv_;
    std::condition_variable cv_;
    bool stopped_ = false;
    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);
                        std::vector<std::basic_string<uint8_t>>* compressed_data);
};
};


+19 −19
Original line number Original line Diff line number Diff line
@@ -208,9 +208,9 @@ class ZstdCompressor final : public ICompressor {
    std::unique_ptr<ZSTD_CCtx, decltype(&ZSTD_freeCCtx)> zstd_context_;
    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) {
                                    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,
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";
            PLOG(ERROR) << "CompressBlocks: Compression failed";
            return false;
            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();
            LOG(ERROR) << "Compressed block is too large: " << data.size();
            return false;
            return false;
        }
        }
@@ -254,7 +254,8 @@ bool CompressWorker::RunThread() {
        }
        }


        // Compress blocks
        // 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;
        blocks.compression_status = ret;
        {
        {
            std::lock_guard<std::mutex> lock(lock_);
            std::lock_guard<std::mutex> lock(lock_);
@@ -273,35 +274,31 @@ bool CompressWorker::RunThread() {
    return true;
    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_);
        std::lock_guard<std::mutex> lock(lock_);


        CompressWork blocks = {};
        CompressWork blocks = {};
        blocks.buffer = buffer;
        blocks.buffer = buffer;
        blocks.block_size = block_size;
        blocks.num_blocks = num_blocks;
        blocks.num_blocks = num_blocks;
        work_queue_.push(std::move(blocks));
        work_queue_.push(std::move(blocks));
        total_submitted_ += 1;
    }
    }
    cv_.notify_all();
    cv_.notify_all();
}
}


bool CompressWorker::GetCompressedBuffers(std::vector<std::basic_string<uint8_t>>* compressed_buf) {
bool CompressWorker::GetCompressedBuffers(std::vector<std::basic_string<uint8_t>>* compressed_buf) {
    {
    while (true) {
        std::unique_lock<std::mutex> lock(lock_);
        std::unique_lock<std::mutex> lock(lock_);
        while (compressed_queue_.empty() && !stopped_) {
        while ((total_submitted_ != total_processed_) && compressed_queue_.empty() && !stopped_) {
            cv_.wait(lock);
            cv_.wait(lock);
        }
        }

        if (stopped_) {
            return true;
        }
    }

    {
        std::lock_guard<std::mutex> lock(lock_);
        while (compressed_queue_.size() > 0) {
        while (compressed_queue_.size() > 0) {
            CompressWork blocks = std::move(compressed_queue_.front());
            CompressWork blocks = std::move(compressed_queue_.front());
            compressed_queue_.pop();
            compressed_queue_.pop();
            total_processed_ += 1;


            if (blocks.compression_status) {
            if (blocks.compression_status) {
                compressed_buf->insert(compressed_buf->end(),
                compressed_buf->insert(compressed_buf->end(),
@@ -312,10 +309,13 @@ bool CompressWorker::GetCompressedBuffers(std::vector<std::basic_string<uint8_t>
                return false;
                return false;
            }
            }
        }
        }
    }
        if ((total_submitted_ == total_processed_) || stopped_) {

            total_submitted_ = 0;
            total_processed_ = 0;
            return true;
            return true;
        }
        }
    }
}


std::unique_ptr<ICompressor> ICompressor::Brotli(uint32_t compression_level,
std::unique_ptr<ICompressor> ICompressor::Brotli(uint32_t compression_level,
                                                 const int32_t block_size) {
                                                 const int32_t block_size) {
@@ -344,8 +344,8 @@ void CompressWorker::Finalize() {
    cv_.notify_all();
    cv_.notify_all();
}
}


CompressWorker::CompressWorker(std::unique_ptr<ICompressor>&& compressor, uint32_t block_size)
CompressWorker::CompressWorker(std::unique_ptr<ICompressor>&& compressor)
    : compressor_(std::move(compressor)), block_size_(block_size) {}
    : compressor_(std::move(compressor)) {}


}  // namespace snapshot
}  // namespace snapshot
}  // namespace android
}  // namespace android
Loading