Loading fs_mgr/libsnapshot/snapuserd/Android.bp +7 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ cc_library_static { "libbase", "liblog", ], export_include_dirs: ["include"], ramdisk_available: true, } Loading @@ -68,6 +69,7 @@ cc_defaults { "user-space-merge/snapuserd_readahead.cpp", "user-space-merge/snapuserd_transitions.cpp", "user-space-merge/snapuserd_server.cpp", "user-space-merge/snapuserd_verify.cpp", ], cflags: [ Loading @@ -88,6 +90,11 @@ cc_defaults { "libext4_utils", "liburing", ], header_libs: [ "libstorage_literals_headers", ], include_dirs: ["bionic/libc/kernel"], system_shared_libs: [], Loading fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h +4 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,10 @@ class SnapuserdClient { // Return the status of the snapshot std::string QuerySnapshotStatus(const std::string& misc_name); // Check the update verification status - invoked by update_verifier during // boot bool QueryUpdateVerification(); }; } // namespace snapshot Loading fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp +10 −0 Original line number Diff line number Diff line Loading @@ -269,5 +269,15 @@ std::string SnapuserdClient::QuerySnapshotStatus(const std::string& misc_name) { return Receivemsg(); } bool SnapuserdClient::QueryUpdateVerification() { std::string msg = "update-verify"; if (!Sendmsg(msg)) { LOG(ERROR) << "Failed to send message " << msg << " to snapuserd"; return false; } std::string response = Receivemsg(); return response == "success"; } } // namespace snapshot } // namespace android fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +13 −229 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <sys/utsname.h> #include <android-base/chrono_utils.h> #include <android-base/properties.h> #include <android-base/scopeguard.h> #include <android-base/strings.h> Loading Loading @@ -70,6 +71,9 @@ bool SnapshotHandler::InitializeWorkers() { read_ahead_thread_ = std::make_unique<ReadAhead>(cow_device_, backing_store_device_, misc_name_, GetSharedPtr()); update_verify_ = std::make_unique<UpdateVerify>(misc_name_); return true; } Loading Loading @@ -306,206 +310,6 @@ bool SnapshotHandler::InitCowDevice() { return ReadMetadata(); } void SnapshotHandler::FinalizeIouring() { io_uring_queue_exit(ring_.get()); } bool SnapshotHandler::InitializeIouring(int io_depth) { ring_ = std::make_unique<struct io_uring>(); int ret = io_uring_queue_init(io_depth, ring_.get(), 0); if (ret) { LOG(ERROR) << "io_uring_queue_init failed with ret: " << ret; return false; } LOG(INFO) << "io_uring_queue_init success with io_depth: " << io_depth; return true; } bool SnapshotHandler::ReadBlocksAsync(const std::string& dm_block_device, const std::string& partition_name, size_t size) { // 64k block size with io_depth of 64 is optimal // for a single thread. We just need a single thread // to read all the blocks from all dynamic partitions. size_t io_depth = 64; size_t bs = (64 * 1024); if (!InitializeIouring(io_depth)) { return false; } LOG(INFO) << "ReadBlockAsync start " << " Block-device: " << dm_block_device << " Partition-name: " << partition_name << " Size: " << size; auto scope_guard = android::base::make_scope_guard([this]() -> void { FinalizeIouring(); }); std::vector<std::unique_ptr<struct iovec>> vecs; using AlignedBuf = std::unique_ptr<void, decltype(free)*>; std::vector<AlignedBuf> alignedBufVector; /* * TODO: We need aligned memory for DIRECT-IO. However, if we do * a DIRECT-IO and verify the blocks then we need to inform * update-verifier that block verification has been done and * there is no need to repeat the same. We are not there yet * as we need to see if there are any boot time improvements doing * a DIRECT-IO. * * Also, we could you the same function post merge for block verification; * again, we can do a DIRECT-IO instead of thrashing page-cache and * hurting other applications. * * For now, we will just create aligned buffers but rely on buffered * I/O until we have perf numbers to justify DIRECT-IO. */ for (int i = 0; i < io_depth; i++) { auto iovec = std::make_unique<struct iovec>(); vecs.push_back(std::move(iovec)); struct iovec* iovec_ptr = vecs[i].get(); if (posix_memalign(&iovec_ptr->iov_base, BLOCK_SZ, bs)) { LOG(ERROR) << "posix_memalign failed"; return false; } iovec_ptr->iov_len = bs; alignedBufVector.push_back( std::unique_ptr<void, decltype(free)*>(iovec_ptr->iov_base, free)); } android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY))); if (fd.get() == -1) { SNAP_PLOG(ERROR) << "File open failed - block-device " << dm_block_device << " partition-name: " << partition_name; return false; } loff_t offset = 0; size_t remain = size; size_t read_sz = io_depth * bs; while (remain > 0) { size_t to_read = std::min(remain, read_sz); size_t queue_size = to_read / bs; for (int i = 0; i < queue_size; i++) { struct io_uring_sqe* sqe = io_uring_get_sqe(ring_.get()); if (!sqe) { SNAP_LOG(ERROR) << "io_uring_get_sqe() failed"; return false; } struct iovec* iovec_ptr = vecs[i].get(); io_uring_prep_read(sqe, fd.get(), iovec_ptr->iov_base, iovec_ptr->iov_len, offset); sqe->flags |= IOSQE_ASYNC; offset += bs; } int ret = io_uring_submit(ring_.get()); if (ret != queue_size) { SNAP_LOG(ERROR) << "submit got: " << ret << " wanted: " << queue_size; return false; } for (int i = 0; i < queue_size; i++) { struct io_uring_cqe* cqe; int ret = io_uring_wait_cqe(ring_.get(), &cqe); if (ret) { SNAP_PLOG(ERROR) << "wait_cqe failed" << ret; return false; } if (cqe->res < 0) { SNAP_LOG(ERROR) << "io failed with res: " << cqe->res; return false; } io_uring_cqe_seen(ring_.get(), cqe); } remain -= to_read; } LOG(INFO) << "ReadBlockAsync complete: " << " Block-device: " << dm_block_device << " Partition-name: " << partition_name << " Size: " << size; return true; } void SnapshotHandler::ReadBlocksToCache(const std::string& dm_block_device, const std::string& partition_name, off_t offset, size_t size) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY))); if (fd.get() == -1) { SNAP_PLOG(ERROR) << "Error reading " << dm_block_device << " partition-name: " << partition_name; return; } size_t remain = size; off_t file_offset = offset; // We pick 4M I/O size based on the fact that the current // update_verifier has a similar I/O size. size_t read_sz = 1024 * BLOCK_SZ; std::vector<uint8_t> buf(read_sz); while (remain > 0) { size_t to_read = std::min(remain, read_sz); if (!android::base::ReadFullyAtOffset(fd.get(), buf.data(), to_read, file_offset)) { SNAP_PLOG(ERROR) << "Failed to read block from block device: " << dm_block_device << " at offset: " << file_offset << " partition-name: " << partition_name << " total-size: " << size << " remain_size: " << remain; return; } file_offset += to_read; remain -= to_read; } SNAP_LOG(INFO) << "Finished reading block-device: " << dm_block_device << " partition: " << partition_name << " size: " << size << " offset: " << offset; } void SnapshotHandler::ReadBlocks(const std::string partition_name, const std::string& dm_block_device) { SNAP_LOG(DEBUG) << "Reading partition: " << partition_name << " Block-Device: " << dm_block_device; uint64_t dev_sz = 0; unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_CLOEXEC))); if (fd < 0) { SNAP_LOG(ERROR) << "Cannot open block device"; return; } dev_sz = get_block_device_size(fd.get()); if (!dev_sz) { SNAP_PLOG(ERROR) << "Could not determine block device size: " << dm_block_device; return; } int num_threads = 2; size_t num_blocks = dev_sz >> BLOCK_SHIFT; size_t num_blocks_per_thread = num_blocks / num_threads; size_t read_sz_per_thread = num_blocks_per_thread << BLOCK_SHIFT; off_t offset = 0; for (int i = 0; i < num_threads; i++) { std::async(std::launch::async, &SnapshotHandler::ReadBlocksToCache, this, dm_block_device, partition_name, offset, read_sz_per_thread); offset += read_sz_per_thread; } } /* * Entry point to launch threads */ Loading @@ -526,42 +330,22 @@ bool SnapshotHandler::Start() { std::async(std::launch::async, &Worker::RunThread, worker_threads_[i].get())); } bool second_stage_init = true; bool partition_verification = true; // We don't want to read the blocks during first stage init. // We don't want to read the blocks during first stage init or // during post-install phase. if (android::base::EndsWith(misc_name_, "-init") || is_socket_present_) { second_stage_init = false; } if (second_stage_init) { SNAP_LOG(INFO) << "Reading blocks to cache...."; auto& dm = DeviceMapper::Instance(); auto dm_block_devices = dm.FindDmPartitions(); if (dm_block_devices.empty()) { SNAP_LOG(ERROR) << "No dm-enabled block device is found."; } else { auto parts = android::base::Split(misc_name_, "-"); std::string partition_name = parts[0]; const char* suffix_b = "_b"; const char* suffix_a = "_a"; partition_name.erase(partition_name.find_last_not_of(suffix_b) + 1); partition_name.erase(partition_name.find_last_not_of(suffix_a) + 1); if (dm_block_devices.find(partition_name) == dm_block_devices.end()) { SNAP_LOG(ERROR) << "Failed to find dm block device for " << partition_name; } else { ReadBlocks(partition_name, dm_block_devices.at(partition_name)); } } } else { SNAP_LOG(INFO) << "Not reading block device into cache"; partition_verification = false; } std::future<bool> merge_thread = std::async(std::launch::async, &Worker::RunMergeThread, merge_thread_.get()); // Now that the worker threads are up, scan the partitions. if (partition_verification) { update_verify_->VerifyUpdatePartition(); } bool ret = true; for (auto& t : threads) { ret = t.get() && ret; Loading fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +35 −10 Original line number Diff line number Diff line Loading @@ -42,12 +42,14 @@ #include <liburing.h> #include <snapuserd/snapuserd_buffer.h> #include <snapuserd/snapuserd_kernel.h> #include <storage_literals/storage_literals.h> namespace android { namespace snapshot { using android::base::unique_fd; using namespace std::chrono_literals; using namespace android::storage_literals; static constexpr size_t PAYLOAD_BUFFER_SZ = (1UL << 20); static_assert(PAYLOAD_BUFFER_SZ >= BLOCK_SZ); Loading Loading @@ -165,6 +167,36 @@ class ReadAhead { std::unique_ptr<struct io_uring> ring_; }; class UpdateVerify { public: UpdateVerify(const std::string& misc_name); void VerifyUpdatePartition(); bool CheckPartitionVerification(); private: enum class UpdateVerifyState { VERIFY_UNKNOWN, VERIFY_FAILED, VERIFY_SUCCESS, }; std::string misc_name_; UpdateVerifyState state_; std::mutex m_lock_; std::condition_variable m_cv_; int kMinThreadsToVerify = 1; int kMaxThreadsToVerify = 4; uint64_t kThresholdSize = 512_MiB; uint64_t kBlockSizeVerify = 1_MiB; bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } void UpdatePartitionVerificationState(UpdateVerifyState state); bool VerifyPartition(const std::string& partition_name, const std::string& dm_block_device); bool VerifyBlocks(const std::string& partition_name, const std::string& dm_block_device, off_t offset, int skip_blocks, uint64_t dev_sz); }; class Worker { public: Worker(const std::string& cow_device, const std::string& backing_device, Loading Loading @@ -344,24 +376,16 @@ class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> { MERGE_GROUP_STATE ProcessMergingBlock(uint64_t new_block, void* buffer); bool IsIouringSupported(); bool CheckPartitionVerification() { return update_verify_->CheckPartitionVerification(); } private: bool ReadMetadata(); sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; } bool IsBlockAligned(int read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } struct BufferState* GetBufferState(); void UpdateMergeCompletionPercentage(); void ReadBlocks(const std::string partition_name, const std::string& dm_block_device); void ReadBlocksToCache(const std::string& dm_block_device, const std::string& partition_name, off_t offset, size_t size); bool InitializeIouring(int io_depth); void FinalizeIouring(); bool ReadBlocksAsync(const std::string& dm_block_device, const std::string& partition_name, size_t size); // COW device std::string cow_device_; // Source device Loading Loading @@ -413,6 +437,7 @@ class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> { bool scratch_space_ = false; std::unique_ptr<struct io_uring> ring_; std::unique_ptr<UpdateVerify> update_verify_; }; } // namespace snapshot Loading Loading
fs_mgr/libsnapshot/snapuserd/Android.bp +7 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ cc_library_static { "libbase", "liblog", ], export_include_dirs: ["include"], ramdisk_available: true, } Loading @@ -68,6 +69,7 @@ cc_defaults { "user-space-merge/snapuserd_readahead.cpp", "user-space-merge/snapuserd_transitions.cpp", "user-space-merge/snapuserd_server.cpp", "user-space-merge/snapuserd_verify.cpp", ], cflags: [ Loading @@ -88,6 +90,11 @@ cc_defaults { "libext4_utils", "liburing", ], header_libs: [ "libstorage_literals_headers", ], include_dirs: ["bionic/libc/kernel"], system_shared_libs: [], Loading
fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h +4 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,10 @@ class SnapuserdClient { // Return the status of the snapshot std::string QuerySnapshotStatus(const std::string& misc_name); // Check the update verification status - invoked by update_verifier during // boot bool QueryUpdateVerification(); }; } // namespace snapshot Loading
fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp +10 −0 Original line number Diff line number Diff line Loading @@ -269,5 +269,15 @@ std::string SnapuserdClient::QuerySnapshotStatus(const std::string& misc_name) { return Receivemsg(); } bool SnapuserdClient::QueryUpdateVerification() { std::string msg = "update-verify"; if (!Sendmsg(msg)) { LOG(ERROR) << "Failed to send message " << msg << " to snapuserd"; return false; } std::string response = Receivemsg(); return response == "success"; } } // namespace snapshot } // namespace android
fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp +13 −229 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <sys/utsname.h> #include <android-base/chrono_utils.h> #include <android-base/properties.h> #include <android-base/scopeguard.h> #include <android-base/strings.h> Loading Loading @@ -70,6 +71,9 @@ bool SnapshotHandler::InitializeWorkers() { read_ahead_thread_ = std::make_unique<ReadAhead>(cow_device_, backing_store_device_, misc_name_, GetSharedPtr()); update_verify_ = std::make_unique<UpdateVerify>(misc_name_); return true; } Loading Loading @@ -306,206 +310,6 @@ bool SnapshotHandler::InitCowDevice() { return ReadMetadata(); } void SnapshotHandler::FinalizeIouring() { io_uring_queue_exit(ring_.get()); } bool SnapshotHandler::InitializeIouring(int io_depth) { ring_ = std::make_unique<struct io_uring>(); int ret = io_uring_queue_init(io_depth, ring_.get(), 0); if (ret) { LOG(ERROR) << "io_uring_queue_init failed with ret: " << ret; return false; } LOG(INFO) << "io_uring_queue_init success with io_depth: " << io_depth; return true; } bool SnapshotHandler::ReadBlocksAsync(const std::string& dm_block_device, const std::string& partition_name, size_t size) { // 64k block size with io_depth of 64 is optimal // for a single thread. We just need a single thread // to read all the blocks from all dynamic partitions. size_t io_depth = 64; size_t bs = (64 * 1024); if (!InitializeIouring(io_depth)) { return false; } LOG(INFO) << "ReadBlockAsync start " << " Block-device: " << dm_block_device << " Partition-name: " << partition_name << " Size: " << size; auto scope_guard = android::base::make_scope_guard([this]() -> void { FinalizeIouring(); }); std::vector<std::unique_ptr<struct iovec>> vecs; using AlignedBuf = std::unique_ptr<void, decltype(free)*>; std::vector<AlignedBuf> alignedBufVector; /* * TODO: We need aligned memory for DIRECT-IO. However, if we do * a DIRECT-IO and verify the blocks then we need to inform * update-verifier that block verification has been done and * there is no need to repeat the same. We are not there yet * as we need to see if there are any boot time improvements doing * a DIRECT-IO. * * Also, we could you the same function post merge for block verification; * again, we can do a DIRECT-IO instead of thrashing page-cache and * hurting other applications. * * For now, we will just create aligned buffers but rely on buffered * I/O until we have perf numbers to justify DIRECT-IO. */ for (int i = 0; i < io_depth; i++) { auto iovec = std::make_unique<struct iovec>(); vecs.push_back(std::move(iovec)); struct iovec* iovec_ptr = vecs[i].get(); if (posix_memalign(&iovec_ptr->iov_base, BLOCK_SZ, bs)) { LOG(ERROR) << "posix_memalign failed"; return false; } iovec_ptr->iov_len = bs; alignedBufVector.push_back( std::unique_ptr<void, decltype(free)*>(iovec_ptr->iov_base, free)); } android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY))); if (fd.get() == -1) { SNAP_PLOG(ERROR) << "File open failed - block-device " << dm_block_device << " partition-name: " << partition_name; return false; } loff_t offset = 0; size_t remain = size; size_t read_sz = io_depth * bs; while (remain > 0) { size_t to_read = std::min(remain, read_sz); size_t queue_size = to_read / bs; for (int i = 0; i < queue_size; i++) { struct io_uring_sqe* sqe = io_uring_get_sqe(ring_.get()); if (!sqe) { SNAP_LOG(ERROR) << "io_uring_get_sqe() failed"; return false; } struct iovec* iovec_ptr = vecs[i].get(); io_uring_prep_read(sqe, fd.get(), iovec_ptr->iov_base, iovec_ptr->iov_len, offset); sqe->flags |= IOSQE_ASYNC; offset += bs; } int ret = io_uring_submit(ring_.get()); if (ret != queue_size) { SNAP_LOG(ERROR) << "submit got: " << ret << " wanted: " << queue_size; return false; } for (int i = 0; i < queue_size; i++) { struct io_uring_cqe* cqe; int ret = io_uring_wait_cqe(ring_.get(), &cqe); if (ret) { SNAP_PLOG(ERROR) << "wait_cqe failed" << ret; return false; } if (cqe->res < 0) { SNAP_LOG(ERROR) << "io failed with res: " << cqe->res; return false; } io_uring_cqe_seen(ring_.get(), cqe); } remain -= to_read; } LOG(INFO) << "ReadBlockAsync complete: " << " Block-device: " << dm_block_device << " Partition-name: " << partition_name << " Size: " << size; return true; } void SnapshotHandler::ReadBlocksToCache(const std::string& dm_block_device, const std::string& partition_name, off_t offset, size_t size) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY))); if (fd.get() == -1) { SNAP_PLOG(ERROR) << "Error reading " << dm_block_device << " partition-name: " << partition_name; return; } size_t remain = size; off_t file_offset = offset; // We pick 4M I/O size based on the fact that the current // update_verifier has a similar I/O size. size_t read_sz = 1024 * BLOCK_SZ; std::vector<uint8_t> buf(read_sz); while (remain > 0) { size_t to_read = std::min(remain, read_sz); if (!android::base::ReadFullyAtOffset(fd.get(), buf.data(), to_read, file_offset)) { SNAP_PLOG(ERROR) << "Failed to read block from block device: " << dm_block_device << " at offset: " << file_offset << " partition-name: " << partition_name << " total-size: " << size << " remain_size: " << remain; return; } file_offset += to_read; remain -= to_read; } SNAP_LOG(INFO) << "Finished reading block-device: " << dm_block_device << " partition: " << partition_name << " size: " << size << " offset: " << offset; } void SnapshotHandler::ReadBlocks(const std::string partition_name, const std::string& dm_block_device) { SNAP_LOG(DEBUG) << "Reading partition: " << partition_name << " Block-Device: " << dm_block_device; uint64_t dev_sz = 0; unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_CLOEXEC))); if (fd < 0) { SNAP_LOG(ERROR) << "Cannot open block device"; return; } dev_sz = get_block_device_size(fd.get()); if (!dev_sz) { SNAP_PLOG(ERROR) << "Could not determine block device size: " << dm_block_device; return; } int num_threads = 2; size_t num_blocks = dev_sz >> BLOCK_SHIFT; size_t num_blocks_per_thread = num_blocks / num_threads; size_t read_sz_per_thread = num_blocks_per_thread << BLOCK_SHIFT; off_t offset = 0; for (int i = 0; i < num_threads; i++) { std::async(std::launch::async, &SnapshotHandler::ReadBlocksToCache, this, dm_block_device, partition_name, offset, read_sz_per_thread); offset += read_sz_per_thread; } } /* * Entry point to launch threads */ Loading @@ -526,42 +330,22 @@ bool SnapshotHandler::Start() { std::async(std::launch::async, &Worker::RunThread, worker_threads_[i].get())); } bool second_stage_init = true; bool partition_verification = true; // We don't want to read the blocks during first stage init. // We don't want to read the blocks during first stage init or // during post-install phase. if (android::base::EndsWith(misc_name_, "-init") || is_socket_present_) { second_stage_init = false; } if (second_stage_init) { SNAP_LOG(INFO) << "Reading blocks to cache...."; auto& dm = DeviceMapper::Instance(); auto dm_block_devices = dm.FindDmPartitions(); if (dm_block_devices.empty()) { SNAP_LOG(ERROR) << "No dm-enabled block device is found."; } else { auto parts = android::base::Split(misc_name_, "-"); std::string partition_name = parts[0]; const char* suffix_b = "_b"; const char* suffix_a = "_a"; partition_name.erase(partition_name.find_last_not_of(suffix_b) + 1); partition_name.erase(partition_name.find_last_not_of(suffix_a) + 1); if (dm_block_devices.find(partition_name) == dm_block_devices.end()) { SNAP_LOG(ERROR) << "Failed to find dm block device for " << partition_name; } else { ReadBlocks(partition_name, dm_block_devices.at(partition_name)); } } } else { SNAP_LOG(INFO) << "Not reading block device into cache"; partition_verification = false; } std::future<bool> merge_thread = std::async(std::launch::async, &Worker::RunMergeThread, merge_thread_.get()); // Now that the worker threads are up, scan the partitions. if (partition_verification) { update_verify_->VerifyUpdatePartition(); } bool ret = true; for (auto& t : threads) { ret = t.get() && ret; Loading
fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +35 −10 Original line number Diff line number Diff line Loading @@ -42,12 +42,14 @@ #include <liburing.h> #include <snapuserd/snapuserd_buffer.h> #include <snapuserd/snapuserd_kernel.h> #include <storage_literals/storage_literals.h> namespace android { namespace snapshot { using android::base::unique_fd; using namespace std::chrono_literals; using namespace android::storage_literals; static constexpr size_t PAYLOAD_BUFFER_SZ = (1UL << 20); static_assert(PAYLOAD_BUFFER_SZ >= BLOCK_SZ); Loading Loading @@ -165,6 +167,36 @@ class ReadAhead { std::unique_ptr<struct io_uring> ring_; }; class UpdateVerify { public: UpdateVerify(const std::string& misc_name); void VerifyUpdatePartition(); bool CheckPartitionVerification(); private: enum class UpdateVerifyState { VERIFY_UNKNOWN, VERIFY_FAILED, VERIFY_SUCCESS, }; std::string misc_name_; UpdateVerifyState state_; std::mutex m_lock_; std::condition_variable m_cv_; int kMinThreadsToVerify = 1; int kMaxThreadsToVerify = 4; uint64_t kThresholdSize = 512_MiB; uint64_t kBlockSizeVerify = 1_MiB; bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } void UpdatePartitionVerificationState(UpdateVerifyState state); bool VerifyPartition(const std::string& partition_name, const std::string& dm_block_device); bool VerifyBlocks(const std::string& partition_name, const std::string& dm_block_device, off_t offset, int skip_blocks, uint64_t dev_sz); }; class Worker { public: Worker(const std::string& cow_device, const std::string& backing_device, Loading Loading @@ -344,24 +376,16 @@ class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> { MERGE_GROUP_STATE ProcessMergingBlock(uint64_t new_block, void* buffer); bool IsIouringSupported(); bool CheckPartitionVerification() { return update_verify_->CheckPartitionVerification(); } private: bool ReadMetadata(); sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; } chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; } bool IsBlockAligned(int read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); } struct BufferState* GetBufferState(); void UpdateMergeCompletionPercentage(); void ReadBlocks(const std::string partition_name, const std::string& dm_block_device); void ReadBlocksToCache(const std::string& dm_block_device, const std::string& partition_name, off_t offset, size_t size); bool InitializeIouring(int io_depth); void FinalizeIouring(); bool ReadBlocksAsync(const std::string& dm_block_device, const std::string& partition_name, size_t size); // COW device std::string cow_device_; // Source device Loading Loading @@ -413,6 +437,7 @@ class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> { bool scratch_space_ = false; std::unique_ptr<struct io_uring> ring_; std::unique_ptr<UpdateVerify> update_verify_; }; } // namespace snapshot Loading