Loading fs_mgr/libsnapshot/cow_reader.cpp +36 −0 Original line number Diff line number Diff line Loading @@ -246,10 +246,46 @@ const CowOperation& CowOpIter::Get() { return (*op_iter_); } class CowOpReverseIter final : public ICowOpReverseIter { public: explicit CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops); bool Done() override; const CowOperation& Get() override; void Next() override; private: std::shared_ptr<std::vector<CowOperation>> ops_; std::vector<CowOperation>::reverse_iterator op_riter_; }; CowOpReverseIter::CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops) { ops_ = ops; op_riter_ = ops_.get()->rbegin(); } bool CowOpReverseIter::Done() { return op_riter_ == ops_.get()->rend(); } void CowOpReverseIter::Next() { CHECK(!Done()); op_riter_++; } const CowOperation& CowOpReverseIter::Get() { CHECK(!Done()); return (*op_riter_); } std::unique_ptr<ICowOpIter> CowReader::GetOpIter() { return std::make_unique<CowOpIter>(ops_); } std::unique_ptr<ICowOpReverseIter> CowReader::GetRevOpIter() { return std::make_unique<CowOpReverseIter>(ops_); } bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) { // Validate the offset, taking care to acknowledge possible overflow of offset+len. if (offset < sizeof(header_) || offset >= fd_size_ - sizeof(footer_) || len >= fd_size_ || Loading fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +23 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ namespace android { namespace snapshot { class ICowOpIter; class ICowOpReverseIter; // A ByteSink object handles requests for a buffer of a specific size. It // always owns the underlying buffer. It's designed to minimize potential Loading Loading @@ -73,6 +74,9 @@ class ICowReader { // Return an iterator for retrieving CowOperation entries. virtual std::unique_ptr<ICowOpIter> GetOpIter() = 0; // Return an reverse iterator for retrieving CowOperation entries. virtual std::unique_ptr<ICowOpReverseIter> GetRevOpIter() = 0; // Get decoded bytes from the data section, handling any decompression. // All retrieved data is passed to the sink. virtual bool ReadData(const CowOperation& op, IByteSink* sink) = 0; Loading @@ -93,6 +97,21 @@ class ICowOpIter { virtual void Next() = 0; }; // Reverse Iterate over a sequence of COW operations. class ICowOpReverseIter { public: virtual ~ICowOpReverseIter() {} // True if there are more items to read, false otherwise. virtual bool Done() = 0; // Read the current operation. virtual const CowOperation& Get() = 0; // Advance to the next item. virtual void Next() = 0; }; class CowReader : public ICowReader { public: CowReader(); Loading @@ -107,8 +126,11 @@ class CowReader : public ICowReader { // Create a CowOpIter object which contains footer_.num_ops // CowOperation objects. Get() returns a unique CowOperation object // whose lifetime depends on the CowOpIter object // whose lifetime depends on the CowOpIter object; the return // value of these will never be null. std::unique_ptr<ICowOpIter> GetOpIter() override; std::unique_ptr<ICowOpReverseIter> GetRevOpIter() override; bool ReadData(const CowOperation& op, IByteSink* sink) override; bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read); Loading fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h +9 −5 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <limits> #include <string> #include <thread> #include <unordered_map> #include <vector> #include <android-base/file.h> Loading Loading @@ -69,6 +70,9 @@ class Snapuserd final { bool Init(); int Run(); const std::string& GetControlDevicePath() { return control_device_; } private: int ReadDmUserHeader(); int WriteDmUserPayload(size_t size); int ConstructKernelCowHeader(); Loading @@ -76,10 +80,9 @@ class Snapuserd final { int ZerofillDiskExceptions(size_t read_size); int ReadDiskExceptions(chunk_t chunk, size_t size); int ReadData(chunk_t chunk, size_t size); bool IsChunkIdMetadata(chunk_t chunk); chunk_t GetNextAllocatableChunkId(chunk_t chunk); const std::string& GetControlDevicePath() { return control_device_; } private: int ProcessReplaceOp(const CowOperation* cow_op); int ProcessCopyOp(const CowOperation* cow_op); int ProcessZeroOp(); Loading @@ -95,15 +98,16 @@ class Snapuserd final { uint32_t exceptions_per_area_; std::unique_ptr<ICowOpIter> cowop_iter_; std::unique_ptr<ICowOpReverseIter> cowop_riter_; std::unique_ptr<CowReader> reader_; // Vector of disk exception which is a // mapping of old-chunk to new-chunk std::vector<std::unique_ptr<uint8_t[]>> vec_; // Index - Chunk ID // Key - Chunk ID // Value - cow operation std::vector<const CowOperation*> chunk_vec_; std::unordered_map<chunk_t, const CowOperation*> chunk_map_; bool metadata_read_done_; BufferSink bufsink_; Loading fs_mgr/libsnapshot/snapuserd.cpp +65 −58 Original line number Diff line number Diff line Loading @@ -159,7 +159,7 @@ int Snapuserd::ReadData(chunk_t chunk, size_t size) { CHECK((read_size & (BLOCK_SIZE - 1)) == 0); while (read_size > 0) { const CowOperation* cow_op = chunk_vec_[chunk_key]; const CowOperation* cow_op = chunk_map_[chunk_key]; CHECK(cow_op != nullptr); int result; Loading Loading @@ -202,6 +202,8 @@ int Snapuserd::ReadData(chunk_t chunk, size_t size) { // are contiguous chunk_key += 1; if (cow_op->type == kCowCopyOp) CHECK(read_size == 0); // This is similar to the way when chunk IDs were assigned // in ReadMetadata(). // Loading Loading @@ -287,6 +289,24 @@ int Snapuserd::ReadDiskExceptions(chunk_t chunk, size_t read_size) { return size; } bool Snapuserd::IsChunkIdMetadata(chunk_t chunk) { uint32_t stride = exceptions_per_area_ + 1; lldiv_t divresult = lldiv(chunk, stride); return divresult.rem == NUM_SNAPSHOT_HDR_CHUNKS; } // Find the next free chunk-id to be assigned. Check if the next free // chunk-id represents a metadata page. If so, skip it. chunk_t Snapuserd::GetNextAllocatableChunkId(chunk_t chunk) { chunk_t next_chunk = chunk + 1; if (IsChunkIdMetadata(next_chunk)) { next_chunk += 1; } return next_chunk; } /* * Read the metadata from COW device and * construct the metadata as required by the kernel. Loading @@ -304,12 +324,26 @@ int Snapuserd::ReadDiskExceptions(chunk_t chunk, size_t read_size) { * This represents the old_chunk in the kernel COW format * 4: We need to assign new_chunk for a corresponding old_chunk * 5: The algorithm is similar to how kernel assigns chunk number * while creating exceptions. * while creating exceptions. However, there are few cases * which needs to be addressed here: * a: During merge process, kernel scans the metadata page * from backwards when merge is initiated. Since, we need * to make sure that the merge ordering follows our COW format, * we read the COW operation from backwards and populate the * metadata so that when kernel starts the merging from backwards, * those ops correspond to the beginning of our COW format. * b: Kernel can merge successive operations if the two chunk IDs * are contiguous. This can be problematic when there is a crash * during merge; specifically when the merge operation has dependency. * These dependencies can only happen during copy operations. * * To avoid this problem, we make sure that no two copy-operations * do not have contiguous chunk IDs. Additionally, we make sure * that each copy operation is merged individually. * 6: Use a monotonically increasing chunk number to assign the * new_chunk * 7: Each chunk-id represents either a: Metadata page or b: Data page * 8: Chunk-id representing a data page is stored in a vector. Index is the * chunk-id and value is the pointer to the CowOperation * 8: Chunk-id representing a data page is stored in a map. * 9: Chunk-id representing a metadata page is converted into a vector * index. We store this in vector as kernel requests metadata during * two stage: Loading @@ -327,7 +361,10 @@ int Snapuserd::ReadDiskExceptions(chunk_t chunk, size_t read_size) { int Snapuserd::ReadMetadata() { reader_ = std::make_unique<CowReader>(); CowHeader header; CowFooter footer; CowOptions options; bool prev_copy_op = false; LOG(DEBUG) << "ReadMetadata Start..."; if (!reader_->Parse(cow_fd_)) { LOG(ERROR) << "Failed to parse"; Loading @@ -339,48 +376,33 @@ int Snapuserd::ReadMetadata() { return 1; } if (!reader_->GetFooter(&footer)) { LOG(ERROR) << "Failed to get footer"; return 1; } CHECK(header.block_size == BLOCK_SIZE); LOG(DEBUG) << "Num-ops: " << std::hex << footer.op.num_ops; LOG(DEBUG) << "ops-size: " << std::hex << footer.op.ops_size; cowop_iter_ = reader_->GetOpIter(); if (cowop_iter_ == nullptr) { LOG(ERROR) << "Failed to get cowop_iter"; return 1; } cowop_riter_ = reader_->GetRevOpIter(); exceptions_per_area_ = (CHUNK_SIZE << SECTOR_SHIFT) / sizeof(struct disk_exception); // Start from chunk number 2. Chunk 0 represents header and chunk 1 // represents first metadata page. chunk_t next_free = NUM_SNAPSHOT_HDR_CHUNKS + 1; chunk_vec_.push_back(nullptr); chunk_vec_.push_back(nullptr); loff_t offset = 0; std::unique_ptr<uint8_t[]> de_ptr = std::make_unique<uint8_t[]>(exceptions_per_area_ * sizeof(struct disk_exception)); // This memset is important. Kernel will stop issuing IO when new-chunk ID // is 0. When Area is not filled completely will all 256 exceptions, // is 0. When Area is not filled completely with all 256 exceptions, // this memset will ensure that metadata read is completed. memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception))); size_t num_ops = 0; while (!cowop_iter_->Done()) { const CowOperation* cow_op = &cowop_iter_->Get(); while (!cowop_riter_->Done()) { const CowOperation* cow_op = &cowop_riter_->Get(); struct disk_exception* de = reinterpret_cast<struct disk_exception*>((char*)de_ptr.get() + offset); if (cow_op->type == kCowFooterOp || cow_op->type == kCowLabelOp) { cowop_iter_->Next(); cowop_riter_->Next(); continue; } Loading @@ -390,61 +412,52 @@ int Snapuserd::ReadMetadata() { return 1; } if ((cow_op->type == kCowCopyOp || prev_copy_op)) { next_free = GetNextAllocatableChunkId(next_free); } prev_copy_op = (cow_op->type == kCowCopyOp); // Construct the disk-exception de->old_chunk = cow_op->new_block; de->new_chunk = next_free; LOG(DEBUG) << "Old-chunk: " << de->old_chunk << "New-chunk: " << de->new_chunk; // Store operation pointer. Note, new-chunk ID is the index chunk_vec_.push_back(cow_op); CHECK(next_free == (chunk_vec_.size() - 1)); // Store operation pointer. chunk_map_[next_free] = cow_op; num_ops += 1; offset += sizeof(struct disk_exception); cowop_iter_->Next(); cowop_riter_->Next(); // Find the next free chunk-id to be assigned. Check if the next free // chunk-id represents a metadata page. If so, skip it. next_free += 1; uint32_t stride = exceptions_per_area_ + 1; lldiv_t divresult = lldiv(next_free, stride); num_ops += 1; if (divresult.rem == NUM_SNAPSHOT_HDR_CHUNKS) { CHECK(num_ops == exceptions_per_area_); if (num_ops == exceptions_per_area_) { // Store it in vector at the right index. This maps the chunk-id to // vector index. vec_.push_back(std::move(de_ptr)); offset = 0; num_ops = 0; chunk_t metadata_chunk = (next_free - exceptions_per_area_ - NUM_SNAPSHOT_HDR_CHUNKS); LOG(DEBUG) << "Area: " << vec_.size() - 1; LOG(DEBUG) << "Metadata-chunk: " << metadata_chunk; LOG(DEBUG) << "Sector number of Metadata-chunk: " << (metadata_chunk << CHUNK_SHIFT); // Create buffer for next area de_ptr = std::make_unique<uint8_t[]>(exceptions_per_area_ * sizeof(struct disk_exception)); memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception))); // Since this is a metadata, store at this index chunk_vec_.push_back(nullptr); // Find the next free chunk-id next_free += 1; if (cowop_iter_->Done()) { if (cowop_riter_->Done()) { vec_.push_back(std::move(de_ptr)); LOG(DEBUG) << "ReadMetadata() completed; Number of Areas: " << vec_.size(); } } next_free = GetNextAllocatableChunkId(next_free); } // Partially filled area if (num_ops) { LOG(DEBUG) << "Partially filled area num_ops: " << num_ops; vec_.push_back(std::move(de_ptr)); LOG(DEBUG) << "ReadMetadata() completed. Partially filled area num_ops: " << num_ops << "Areas : " << vec_.size(); } return 0; Loading Loading @@ -569,13 +582,7 @@ int Snapuserd::Run() { // vector, then it points to a metadata page. chunk_t chunk = (header->sector >> CHUNK_SHIFT); if (chunk >= chunk_vec_.size()) { ret = ZerofillDiskExceptions(read_size); if (ret < 0) { LOG(ERROR) << "ZerofillDiskExceptions failed"; return ret; } } else if (chunk_vec_[chunk] == nullptr) { if (chunk_map_.find(chunk) == chunk_map_.end()) { ret = ReadDiskExceptions(chunk, read_size); if (ret < 0) { LOG(ERROR) << "ReadDiskExceptions failed"; Loading Loading
fs_mgr/libsnapshot/cow_reader.cpp +36 −0 Original line number Diff line number Diff line Loading @@ -246,10 +246,46 @@ const CowOperation& CowOpIter::Get() { return (*op_iter_); } class CowOpReverseIter final : public ICowOpReverseIter { public: explicit CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops); bool Done() override; const CowOperation& Get() override; void Next() override; private: std::shared_ptr<std::vector<CowOperation>> ops_; std::vector<CowOperation>::reverse_iterator op_riter_; }; CowOpReverseIter::CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops) { ops_ = ops; op_riter_ = ops_.get()->rbegin(); } bool CowOpReverseIter::Done() { return op_riter_ == ops_.get()->rend(); } void CowOpReverseIter::Next() { CHECK(!Done()); op_riter_++; } const CowOperation& CowOpReverseIter::Get() { CHECK(!Done()); return (*op_riter_); } std::unique_ptr<ICowOpIter> CowReader::GetOpIter() { return std::make_unique<CowOpIter>(ops_); } std::unique_ptr<ICowOpReverseIter> CowReader::GetRevOpIter() { return std::make_unique<CowOpReverseIter>(ops_); } bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) { // Validate the offset, taking care to acknowledge possible overflow of offset+len. if (offset < sizeof(header_) || offset >= fd_size_ - sizeof(footer_) || len >= fd_size_ || Loading
fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +23 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ namespace android { namespace snapshot { class ICowOpIter; class ICowOpReverseIter; // A ByteSink object handles requests for a buffer of a specific size. It // always owns the underlying buffer. It's designed to minimize potential Loading Loading @@ -73,6 +74,9 @@ class ICowReader { // Return an iterator for retrieving CowOperation entries. virtual std::unique_ptr<ICowOpIter> GetOpIter() = 0; // Return an reverse iterator for retrieving CowOperation entries. virtual std::unique_ptr<ICowOpReverseIter> GetRevOpIter() = 0; // Get decoded bytes from the data section, handling any decompression. // All retrieved data is passed to the sink. virtual bool ReadData(const CowOperation& op, IByteSink* sink) = 0; Loading @@ -93,6 +97,21 @@ class ICowOpIter { virtual void Next() = 0; }; // Reverse Iterate over a sequence of COW operations. class ICowOpReverseIter { public: virtual ~ICowOpReverseIter() {} // True if there are more items to read, false otherwise. virtual bool Done() = 0; // Read the current operation. virtual const CowOperation& Get() = 0; // Advance to the next item. virtual void Next() = 0; }; class CowReader : public ICowReader { public: CowReader(); Loading @@ -107,8 +126,11 @@ class CowReader : public ICowReader { // Create a CowOpIter object which contains footer_.num_ops // CowOperation objects. Get() returns a unique CowOperation object // whose lifetime depends on the CowOpIter object // whose lifetime depends on the CowOpIter object; the return // value of these will never be null. std::unique_ptr<ICowOpIter> GetOpIter() override; std::unique_ptr<ICowOpReverseIter> GetRevOpIter() override; bool ReadData(const CowOperation& op, IByteSink* sink) override; bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read); Loading
fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h +9 −5 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <limits> #include <string> #include <thread> #include <unordered_map> #include <vector> #include <android-base/file.h> Loading Loading @@ -69,6 +70,9 @@ class Snapuserd final { bool Init(); int Run(); const std::string& GetControlDevicePath() { return control_device_; } private: int ReadDmUserHeader(); int WriteDmUserPayload(size_t size); int ConstructKernelCowHeader(); Loading @@ -76,10 +80,9 @@ class Snapuserd final { int ZerofillDiskExceptions(size_t read_size); int ReadDiskExceptions(chunk_t chunk, size_t size); int ReadData(chunk_t chunk, size_t size); bool IsChunkIdMetadata(chunk_t chunk); chunk_t GetNextAllocatableChunkId(chunk_t chunk); const std::string& GetControlDevicePath() { return control_device_; } private: int ProcessReplaceOp(const CowOperation* cow_op); int ProcessCopyOp(const CowOperation* cow_op); int ProcessZeroOp(); Loading @@ -95,15 +98,16 @@ class Snapuserd final { uint32_t exceptions_per_area_; std::unique_ptr<ICowOpIter> cowop_iter_; std::unique_ptr<ICowOpReverseIter> cowop_riter_; std::unique_ptr<CowReader> reader_; // Vector of disk exception which is a // mapping of old-chunk to new-chunk std::vector<std::unique_ptr<uint8_t[]>> vec_; // Index - Chunk ID // Key - Chunk ID // Value - cow operation std::vector<const CowOperation*> chunk_vec_; std::unordered_map<chunk_t, const CowOperation*> chunk_map_; bool metadata_read_done_; BufferSink bufsink_; Loading
fs_mgr/libsnapshot/snapuserd.cpp +65 −58 Original line number Diff line number Diff line Loading @@ -159,7 +159,7 @@ int Snapuserd::ReadData(chunk_t chunk, size_t size) { CHECK((read_size & (BLOCK_SIZE - 1)) == 0); while (read_size > 0) { const CowOperation* cow_op = chunk_vec_[chunk_key]; const CowOperation* cow_op = chunk_map_[chunk_key]; CHECK(cow_op != nullptr); int result; Loading Loading @@ -202,6 +202,8 @@ int Snapuserd::ReadData(chunk_t chunk, size_t size) { // are contiguous chunk_key += 1; if (cow_op->type == kCowCopyOp) CHECK(read_size == 0); // This is similar to the way when chunk IDs were assigned // in ReadMetadata(). // Loading Loading @@ -287,6 +289,24 @@ int Snapuserd::ReadDiskExceptions(chunk_t chunk, size_t read_size) { return size; } bool Snapuserd::IsChunkIdMetadata(chunk_t chunk) { uint32_t stride = exceptions_per_area_ + 1; lldiv_t divresult = lldiv(chunk, stride); return divresult.rem == NUM_SNAPSHOT_HDR_CHUNKS; } // Find the next free chunk-id to be assigned. Check if the next free // chunk-id represents a metadata page. If so, skip it. chunk_t Snapuserd::GetNextAllocatableChunkId(chunk_t chunk) { chunk_t next_chunk = chunk + 1; if (IsChunkIdMetadata(next_chunk)) { next_chunk += 1; } return next_chunk; } /* * Read the metadata from COW device and * construct the metadata as required by the kernel. Loading @@ -304,12 +324,26 @@ int Snapuserd::ReadDiskExceptions(chunk_t chunk, size_t read_size) { * This represents the old_chunk in the kernel COW format * 4: We need to assign new_chunk for a corresponding old_chunk * 5: The algorithm is similar to how kernel assigns chunk number * while creating exceptions. * while creating exceptions. However, there are few cases * which needs to be addressed here: * a: During merge process, kernel scans the metadata page * from backwards when merge is initiated. Since, we need * to make sure that the merge ordering follows our COW format, * we read the COW operation from backwards and populate the * metadata so that when kernel starts the merging from backwards, * those ops correspond to the beginning of our COW format. * b: Kernel can merge successive operations if the two chunk IDs * are contiguous. This can be problematic when there is a crash * during merge; specifically when the merge operation has dependency. * These dependencies can only happen during copy operations. * * To avoid this problem, we make sure that no two copy-operations * do not have contiguous chunk IDs. Additionally, we make sure * that each copy operation is merged individually. * 6: Use a monotonically increasing chunk number to assign the * new_chunk * 7: Each chunk-id represents either a: Metadata page or b: Data page * 8: Chunk-id representing a data page is stored in a vector. Index is the * chunk-id and value is the pointer to the CowOperation * 8: Chunk-id representing a data page is stored in a map. * 9: Chunk-id representing a metadata page is converted into a vector * index. We store this in vector as kernel requests metadata during * two stage: Loading @@ -327,7 +361,10 @@ int Snapuserd::ReadDiskExceptions(chunk_t chunk, size_t read_size) { int Snapuserd::ReadMetadata() { reader_ = std::make_unique<CowReader>(); CowHeader header; CowFooter footer; CowOptions options; bool prev_copy_op = false; LOG(DEBUG) << "ReadMetadata Start..."; if (!reader_->Parse(cow_fd_)) { LOG(ERROR) << "Failed to parse"; Loading @@ -339,48 +376,33 @@ int Snapuserd::ReadMetadata() { return 1; } if (!reader_->GetFooter(&footer)) { LOG(ERROR) << "Failed to get footer"; return 1; } CHECK(header.block_size == BLOCK_SIZE); LOG(DEBUG) << "Num-ops: " << std::hex << footer.op.num_ops; LOG(DEBUG) << "ops-size: " << std::hex << footer.op.ops_size; cowop_iter_ = reader_->GetOpIter(); if (cowop_iter_ == nullptr) { LOG(ERROR) << "Failed to get cowop_iter"; return 1; } cowop_riter_ = reader_->GetRevOpIter(); exceptions_per_area_ = (CHUNK_SIZE << SECTOR_SHIFT) / sizeof(struct disk_exception); // Start from chunk number 2. Chunk 0 represents header and chunk 1 // represents first metadata page. chunk_t next_free = NUM_SNAPSHOT_HDR_CHUNKS + 1; chunk_vec_.push_back(nullptr); chunk_vec_.push_back(nullptr); loff_t offset = 0; std::unique_ptr<uint8_t[]> de_ptr = std::make_unique<uint8_t[]>(exceptions_per_area_ * sizeof(struct disk_exception)); // This memset is important. Kernel will stop issuing IO when new-chunk ID // is 0. When Area is not filled completely will all 256 exceptions, // is 0. When Area is not filled completely with all 256 exceptions, // this memset will ensure that metadata read is completed. memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception))); size_t num_ops = 0; while (!cowop_iter_->Done()) { const CowOperation* cow_op = &cowop_iter_->Get(); while (!cowop_riter_->Done()) { const CowOperation* cow_op = &cowop_riter_->Get(); struct disk_exception* de = reinterpret_cast<struct disk_exception*>((char*)de_ptr.get() + offset); if (cow_op->type == kCowFooterOp || cow_op->type == kCowLabelOp) { cowop_iter_->Next(); cowop_riter_->Next(); continue; } Loading @@ -390,61 +412,52 @@ int Snapuserd::ReadMetadata() { return 1; } if ((cow_op->type == kCowCopyOp || prev_copy_op)) { next_free = GetNextAllocatableChunkId(next_free); } prev_copy_op = (cow_op->type == kCowCopyOp); // Construct the disk-exception de->old_chunk = cow_op->new_block; de->new_chunk = next_free; LOG(DEBUG) << "Old-chunk: " << de->old_chunk << "New-chunk: " << de->new_chunk; // Store operation pointer. Note, new-chunk ID is the index chunk_vec_.push_back(cow_op); CHECK(next_free == (chunk_vec_.size() - 1)); // Store operation pointer. chunk_map_[next_free] = cow_op; num_ops += 1; offset += sizeof(struct disk_exception); cowop_iter_->Next(); cowop_riter_->Next(); // Find the next free chunk-id to be assigned. Check if the next free // chunk-id represents a metadata page. If so, skip it. next_free += 1; uint32_t stride = exceptions_per_area_ + 1; lldiv_t divresult = lldiv(next_free, stride); num_ops += 1; if (divresult.rem == NUM_SNAPSHOT_HDR_CHUNKS) { CHECK(num_ops == exceptions_per_area_); if (num_ops == exceptions_per_area_) { // Store it in vector at the right index. This maps the chunk-id to // vector index. vec_.push_back(std::move(de_ptr)); offset = 0; num_ops = 0; chunk_t metadata_chunk = (next_free - exceptions_per_area_ - NUM_SNAPSHOT_HDR_CHUNKS); LOG(DEBUG) << "Area: " << vec_.size() - 1; LOG(DEBUG) << "Metadata-chunk: " << metadata_chunk; LOG(DEBUG) << "Sector number of Metadata-chunk: " << (metadata_chunk << CHUNK_SHIFT); // Create buffer for next area de_ptr = std::make_unique<uint8_t[]>(exceptions_per_area_ * sizeof(struct disk_exception)); memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception))); // Since this is a metadata, store at this index chunk_vec_.push_back(nullptr); // Find the next free chunk-id next_free += 1; if (cowop_iter_->Done()) { if (cowop_riter_->Done()) { vec_.push_back(std::move(de_ptr)); LOG(DEBUG) << "ReadMetadata() completed; Number of Areas: " << vec_.size(); } } next_free = GetNextAllocatableChunkId(next_free); } // Partially filled area if (num_ops) { LOG(DEBUG) << "Partially filled area num_ops: " << num_ops; vec_.push_back(std::move(de_ptr)); LOG(DEBUG) << "ReadMetadata() completed. Partially filled area num_ops: " << num_ops << "Areas : " << vec_.size(); } return 0; Loading Loading @@ -569,13 +582,7 @@ int Snapuserd::Run() { // vector, then it points to a metadata page. chunk_t chunk = (header->sector >> CHUNK_SHIFT); if (chunk >= chunk_vec_.size()) { ret = ZerofillDiskExceptions(read_size); if (ret < 0) { LOG(ERROR) << "ZerofillDiskExceptions failed"; return ret; } } else if (chunk_vec_[chunk] == nullptr) { if (chunk_map_.find(chunk) == chunk_map_.end()) { ret = ReadDiskExceptions(chunk, read_size); if (ret < 0) { LOG(ERROR) << "ReadDiskExceptions failed"; Loading