Loading fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp +106 −4 Original line number Diff line number Diff line Loading @@ -54,16 +54,118 @@ static_assert(sizeof(off_t) == sizeof(uint64_t)); using android::base::unique_fd; CowWriterV3::CowWriterV3(const CowOptions& options, unique_fd&& fd) : CowWriterBase(options, std::move(fd)) {} : CowWriterBase(options, std::move(fd)) { SetupHeaders(); } void CowWriterV3::SetupHeaders() { header_ = {}; header_.prefix.magic = kCowMagicNumber; header_.prefix.major_version = 3; header_.prefix.minor_version = 0; header_.prefix.header_size = sizeof(CowHeaderV3); header_.footer_size = 0; header_.op_size = sizeof(CowOperationV3); header_.block_size = options_.block_size; header_.num_merge_ops = options_.num_merge_ops; header_.cluster_ops = 0; if (options_.scratch_space) { header_.buffer_size = BUFFER_REGION_DEFAULT_SIZE; } // v3 specific fields // WIP: not quite sure how some of these are calculated yet, assuming buffer_size is determined // during COW size estimation header_.sequence_buffer_offset = 0; header_.resume_buffer_size = 0; header_.op_buffer_size = 0; header_.compression_algorithm = kCowCompressNone; return; } bool CowWriterV3::ParseOptions() { num_compress_threads_ = std::max(options_.num_compress_threads, 1); auto parts = android::base::Split(options_.compression, ","); if (parts.size() > 2) { LOG(ERROR) << "failed to parse compression parameters: invalid argument count: " << parts.size() << " " << options_.compression; return false; } auto algorithm = CompressionAlgorithmFromString(parts[0]); if (!algorithm) { LOG(ERROR) << "unrecognized compression: " << options_.compression; return false; } if (parts.size() > 1) { if (!android::base::ParseUint(parts[1], &compression_.compression_level)) { LOG(ERROR) << "failed to parse compression level invalid type: " << parts[1]; return false; } } else { compression_.compression_level = CompressWorker::GetDefaultCompressionLevel(algorithm.value()); } compression_.algorithm = *algorithm; return true; } CowWriterV3::~CowWriterV3() {} bool CowWriterV3::Initialize(std::optional<uint64_t> label) { LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; if (label) return false; if (!InitFd() || !ParseOptions()) { return false; } CHECK(!label.has_value()); if (!OpenForWrite()) { return false; } return true; } bool CowWriterV3::OpenForWrite() { // This limitation is tied to the data field size in CowOperationV2. // Keeping this for V3 writer <- although we if (header_.block_size > std::numeric_limits<uint16_t>::max()) { LOG(ERROR) << "Block size is too large"; return false; } if (lseek(fd_.get(), 0, SEEK_SET) < 0) { PLOG(ERROR) << "lseek failed"; return false; } // Headers are not complete, but this ensures the file is at the right // position. if (!android::base::WriteFully(fd_, &header_, sizeof(header_))) { PLOG(ERROR) << "write failed"; return false; } if (options_.scratch_space) { // Initialize the scratch space std::string data(header_.buffer_size, 0); if (!android::base::WriteFully(fd_, data.data(), header_.buffer_size)) { PLOG(ERROR) << "writing scratch space failed"; return false; } } if (!Sync()) { LOG(ERROR) << "Header sync failed"; return false; } next_op_pos_ = 0; next_data_pos_ = 0; return true; } bool CowWriterV3::EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) { LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; if (new_block || old_block || num_blocks) return false; Loading fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h +16 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,22 @@ class CowWriterV3 : public CowWriterBase { virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override; virtual bool EmitLabel(uint64_t label) override; virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) override; private: void SetupHeaders(); bool ParseOptions(); bool OpenForWrite(); private: CowHeaderV3 header_{}; CowCompression compression_; // in the case that we are using one thread for compression, we can store and re-use the same // compressor uint64_t next_op_pos_ = 0; uint64_t next_data_pos_ = 0; int num_compress_threads_ = 1; }; } // namespace snapshot Loading Loading
fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp +106 −4 Original line number Diff line number Diff line Loading @@ -54,16 +54,118 @@ static_assert(sizeof(off_t) == sizeof(uint64_t)); using android::base::unique_fd; CowWriterV3::CowWriterV3(const CowOptions& options, unique_fd&& fd) : CowWriterBase(options, std::move(fd)) {} : CowWriterBase(options, std::move(fd)) { SetupHeaders(); } void CowWriterV3::SetupHeaders() { header_ = {}; header_.prefix.magic = kCowMagicNumber; header_.prefix.major_version = 3; header_.prefix.minor_version = 0; header_.prefix.header_size = sizeof(CowHeaderV3); header_.footer_size = 0; header_.op_size = sizeof(CowOperationV3); header_.block_size = options_.block_size; header_.num_merge_ops = options_.num_merge_ops; header_.cluster_ops = 0; if (options_.scratch_space) { header_.buffer_size = BUFFER_REGION_DEFAULT_SIZE; } // v3 specific fields // WIP: not quite sure how some of these are calculated yet, assuming buffer_size is determined // during COW size estimation header_.sequence_buffer_offset = 0; header_.resume_buffer_size = 0; header_.op_buffer_size = 0; header_.compression_algorithm = kCowCompressNone; return; } bool CowWriterV3::ParseOptions() { num_compress_threads_ = std::max(options_.num_compress_threads, 1); auto parts = android::base::Split(options_.compression, ","); if (parts.size() > 2) { LOG(ERROR) << "failed to parse compression parameters: invalid argument count: " << parts.size() << " " << options_.compression; return false; } auto algorithm = CompressionAlgorithmFromString(parts[0]); if (!algorithm) { LOG(ERROR) << "unrecognized compression: " << options_.compression; return false; } if (parts.size() > 1) { if (!android::base::ParseUint(parts[1], &compression_.compression_level)) { LOG(ERROR) << "failed to parse compression level invalid type: " << parts[1]; return false; } } else { compression_.compression_level = CompressWorker::GetDefaultCompressionLevel(algorithm.value()); } compression_.algorithm = *algorithm; return true; } CowWriterV3::~CowWriterV3() {} bool CowWriterV3::Initialize(std::optional<uint64_t> label) { LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; if (label) return false; if (!InitFd() || !ParseOptions()) { return false; } CHECK(!label.has_value()); if (!OpenForWrite()) { return false; } return true; } bool CowWriterV3::OpenForWrite() { // This limitation is tied to the data field size in CowOperationV2. // Keeping this for V3 writer <- although we if (header_.block_size > std::numeric_limits<uint16_t>::max()) { LOG(ERROR) << "Block size is too large"; return false; } if (lseek(fd_.get(), 0, SEEK_SET) < 0) { PLOG(ERROR) << "lseek failed"; return false; } // Headers are not complete, but this ensures the file is at the right // position. if (!android::base::WriteFully(fd_, &header_, sizeof(header_))) { PLOG(ERROR) << "write failed"; return false; } if (options_.scratch_space) { // Initialize the scratch space std::string data(header_.buffer_size, 0); if (!android::base::WriteFully(fd_, data.data(), header_.buffer_size)) { PLOG(ERROR) << "writing scratch space failed"; return false; } } if (!Sync()) { LOG(ERROR) << "Header sync failed"; return false; } next_op_pos_ = 0; next_data_pos_ = 0; return true; } bool CowWriterV3::EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) { LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; if (new_block || old_block || num_blocks) return false; Loading
fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.h +16 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,22 @@ class CowWriterV3 : public CowWriterBase { virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override; virtual bool EmitLabel(uint64_t label) override; virtual bool EmitSequenceData(size_t num_ops, const uint32_t* data) override; private: void SetupHeaders(); bool ParseOptions(); bool OpenForWrite(); private: CowHeaderV3 header_{}; CowCompression compression_; // in the case that we are using one thread for compression, we can store and re-use the same // compressor uint64_t next_op_pos_ = 0; uint64_t next_data_pos_ = 0; int num_compress_threads_ = 1; }; } // namespace snapshot Loading