Loading fs_mgr/libdm/dm.cpp +56 −0 Original line number Diff line number Diff line Loading @@ -651,5 +651,61 @@ bool DeviceMapper::TargetInfo::IsOverflowSnapshot() const { return spec.target_type == "snapshot"s && data == "Overflow"s; } // Find directories in format of "/sys/block/dm-X". static int DmNameFilter(const dirent* de) { if (android::base::StartsWith(de->d_name, "dm-")) { return 1; } return 0; } std::map<std::string, std::string> DeviceMapper::FindDmPartitions() { static constexpr auto DM_PATH_PREFIX = "/sys/block/"; dirent** namelist; int n = scandir(DM_PATH_PREFIX, &namelist, DmNameFilter, alphasort); if (n == -1) { PLOG(ERROR) << "Failed to scan dir " << DM_PATH_PREFIX; return {}; } if (n == 0) { LOG(ERROR) << "No dm block device found."; free(namelist); return {}; } static constexpr auto DM_PATH_SUFFIX = "/dm/name"; static constexpr auto DEV_PATH = "/dev/block/"; std::map<std::string, std::string> dm_block_devices; while (n--) { std::string path = DM_PATH_PREFIX + std::string(namelist[n]->d_name) + DM_PATH_SUFFIX; std::string content; if (!android::base::ReadFileToString(path, &content)) { PLOG(WARNING) << "Failed to read " << path; } else { std::string dm_block_name = android::base::Trim(content); // AVB is using 'vroot' for the root block device but we're expecting 'system'. if (dm_block_name == "vroot") { dm_block_name = "system"; } else if (android::base::EndsWith(dm_block_name, "-verity")) { auto npos = dm_block_name.rfind("-verity"); dm_block_name = dm_block_name.substr(0, npos); } else if (!android::base::GetProperty("ro.boot.avb_version", "").empty()) { // Verified Boot 1.0 doesn't add a -verity suffix. On AVB 2 devices, // if DAP is enabled, then a -verity suffix must be used to // differentiate between dm-linear and dm-verity devices. If we get // here, we're AVB 2 and looking at a non-verity partition. free(namelist[n]); continue; } dm_block_devices.emplace(dm_block_name, DEV_PATH + std::string(namelist[n]->d_name)); } free(namelist[n]); } free(namelist); return dm_block_devices; } } // namespace dm } // namespace android fs_mgr/libdm/include/libdm/dm.h +8 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #ifndef _LIBDM_DM_H_ #define _LIBDM_DM_H_ #include <dirent.h> #include <fcntl.h> #include <linux/dm-ioctl.h> #include <linux/kdev_t.h> Loading @@ -26,6 +27,7 @@ #include <unistd.h> #include <chrono> #include <map> #include <memory> #include <optional> #include <string> Loading Loading @@ -255,6 +257,12 @@ class DeviceMapper final { // * A failure occurred. std::optional<std::string> GetParentBlockDeviceByPath(const std::string& path); // Iterate the content over "/sys/block/dm-x/dm/name" and find // all the dm-wrapped block devices. // // Returns mapping <partition-name, /dev/block/dm-x> std::map<std::string, std::string> FindDmPartitions(); private: // Maximum possible device mapper targets registered in the kernel. // This is only used to read the list of targets from kernel so we allocate Loading fs_mgr/libsnapshot/snapuserd/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ cc_defaults { "liblog", "libsnapshot_cow", "libz", "libext4_utils", ], } Loading Loading @@ -121,6 +122,7 @@ cc_test { "libz", "libfs_mgr", "libdm", "libext4_utils", ], header_libs: [ "libstorage_literals_headers", Loading fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h +0 −2 Original line number Diff line number Diff line Loading @@ -47,8 +47,6 @@ typedef sector_t chunk_t; static constexpr uint32_t CHUNK_SIZE = 8; static constexpr uint32_t CHUNK_SHIFT = (__builtin_ffs(CHUNK_SIZE) - 1); #define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d)) // This structure represents the kernel COW header. // All the below fields should be in Little Endian format. struct disk_header { Loading fs_mgr/libsnapshot/snapuserd/snapuserd.cpp +113 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,22 @@ #include "snapuserd.h" #include <dirent.h> #include <fcntl.h> #include <linux/fs.h> #include <unistd.h> #include <algorithm> #include <csignal> #include <optional> #include <set> #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/parseint.h> #include <android-base/properties.h> #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <snapuserd/snapuserd_client.h> namespace android { Loading Loading @@ -678,6 +690,74 @@ bool Snapuserd::InitCowDevice() { return ReadMetadata(); } void Snapuserd::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 Snapuserd::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, &Snapuserd::ReadBlocksToCache, this, dm_block_device, partition_name, offset, read_sz_per_thread); offset += read_sz_per_thread; } } /* * Entry point to launch threads */ Loading Loading @@ -706,6 +786,39 @@ bool Snapuserd::Start() { std::async(std::launch::async, &WorkerThread::RunThread, worker_threads_[i].get())); } bool second_stage_init = true; // We don't want to read the blocks during first stage init. 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"; } bool ret = true; for (auto& t : threads) { ret = t.get() && ret; Loading Loading
fs_mgr/libdm/dm.cpp +56 −0 Original line number Diff line number Diff line Loading @@ -651,5 +651,61 @@ bool DeviceMapper::TargetInfo::IsOverflowSnapshot() const { return spec.target_type == "snapshot"s && data == "Overflow"s; } // Find directories in format of "/sys/block/dm-X". static int DmNameFilter(const dirent* de) { if (android::base::StartsWith(de->d_name, "dm-")) { return 1; } return 0; } std::map<std::string, std::string> DeviceMapper::FindDmPartitions() { static constexpr auto DM_PATH_PREFIX = "/sys/block/"; dirent** namelist; int n = scandir(DM_PATH_PREFIX, &namelist, DmNameFilter, alphasort); if (n == -1) { PLOG(ERROR) << "Failed to scan dir " << DM_PATH_PREFIX; return {}; } if (n == 0) { LOG(ERROR) << "No dm block device found."; free(namelist); return {}; } static constexpr auto DM_PATH_SUFFIX = "/dm/name"; static constexpr auto DEV_PATH = "/dev/block/"; std::map<std::string, std::string> dm_block_devices; while (n--) { std::string path = DM_PATH_PREFIX + std::string(namelist[n]->d_name) + DM_PATH_SUFFIX; std::string content; if (!android::base::ReadFileToString(path, &content)) { PLOG(WARNING) << "Failed to read " << path; } else { std::string dm_block_name = android::base::Trim(content); // AVB is using 'vroot' for the root block device but we're expecting 'system'. if (dm_block_name == "vroot") { dm_block_name = "system"; } else if (android::base::EndsWith(dm_block_name, "-verity")) { auto npos = dm_block_name.rfind("-verity"); dm_block_name = dm_block_name.substr(0, npos); } else if (!android::base::GetProperty("ro.boot.avb_version", "").empty()) { // Verified Boot 1.0 doesn't add a -verity suffix. On AVB 2 devices, // if DAP is enabled, then a -verity suffix must be used to // differentiate between dm-linear and dm-verity devices. If we get // here, we're AVB 2 and looking at a non-verity partition. free(namelist[n]); continue; } dm_block_devices.emplace(dm_block_name, DEV_PATH + std::string(namelist[n]->d_name)); } free(namelist[n]); } free(namelist); return dm_block_devices; } } // namespace dm } // namespace android
fs_mgr/libdm/include/libdm/dm.h +8 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #ifndef _LIBDM_DM_H_ #define _LIBDM_DM_H_ #include <dirent.h> #include <fcntl.h> #include <linux/dm-ioctl.h> #include <linux/kdev_t.h> Loading @@ -26,6 +27,7 @@ #include <unistd.h> #include <chrono> #include <map> #include <memory> #include <optional> #include <string> Loading Loading @@ -255,6 +257,12 @@ class DeviceMapper final { // * A failure occurred. std::optional<std::string> GetParentBlockDeviceByPath(const std::string& path); // Iterate the content over "/sys/block/dm-x/dm/name" and find // all the dm-wrapped block devices. // // Returns mapping <partition-name, /dev/block/dm-x> std::map<std::string, std::string> FindDmPartitions(); private: // Maximum possible device mapper targets registered in the kernel. // This is only used to read the list of targets from kernel so we allocate Loading
fs_mgr/libsnapshot/snapuserd/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ cc_defaults { "liblog", "libsnapshot_cow", "libz", "libext4_utils", ], } Loading Loading @@ -121,6 +122,7 @@ cc_test { "libz", "libfs_mgr", "libdm", "libext4_utils", ], header_libs: [ "libstorage_literals_headers", Loading
fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h +0 −2 Original line number Diff line number Diff line Loading @@ -47,8 +47,6 @@ typedef sector_t chunk_t; static constexpr uint32_t CHUNK_SIZE = 8; static constexpr uint32_t CHUNK_SHIFT = (__builtin_ffs(CHUNK_SIZE) - 1); #define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d)) // This structure represents the kernel COW header. // All the below fields should be in Little Endian format. struct disk_header { Loading
fs_mgr/libsnapshot/snapuserd/snapuserd.cpp +113 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,22 @@ #include "snapuserd.h" #include <dirent.h> #include <fcntl.h> #include <linux/fs.h> #include <unistd.h> #include <algorithm> #include <csignal> #include <optional> #include <set> #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/parseint.h> #include <android-base/properties.h> #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <snapuserd/snapuserd_client.h> namespace android { Loading Loading @@ -678,6 +690,74 @@ bool Snapuserd::InitCowDevice() { return ReadMetadata(); } void Snapuserd::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 Snapuserd::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, &Snapuserd::ReadBlocksToCache, this, dm_block_device, partition_name, offset, read_sz_per_thread); offset += read_sz_per_thread; } } /* * Entry point to launch threads */ Loading Loading @@ -706,6 +786,39 @@ bool Snapuserd::Start() { std::async(std::launch::async, &WorkerThread::RunThread, worker_threads_[i].get())); } bool second_stage_init = true; // We don't want to read the blocks during first stage init. 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"; } bool ret = true; for (auto& t : threads) { ret = t.get() && ret; Loading