Merge "snapuserd: Read partition blocks to memory"
This commit is contained in:
commit
e19f7be126
8 changed files with 189 additions and 2 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -26,6 +27,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ cc_defaults {
|
|||
"liblog",
|
||||
"libsnapshot_cow",
|
||||
"libz",
|
||||
"libext4_utils",
|
||||
],
|
||||
}
|
||||
|
||||
|
|
@ -121,6 +122,7 @@ cc_test {
|
|||
"libz",
|
||||
"libfs_mgr",
|
||||
"libdm",
|
||||
"libext4_utils",
|
||||
],
|
||||
header_libs: [
|
||||
"libstorage_literals_headers",
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
@ -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
|
||||
*/
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <ext4_utils/ext4_utils.h>
|
||||
#include <libdm/dm.h>
|
||||
#include <libsnapshot/cow_reader.h>
|
||||
#include <libsnapshot/cow_writer.h>
|
||||
|
|
@ -302,6 +303,7 @@ class Snapuserd : public std::enable_shared_from_this<Snapuserd> {
|
|||
// Total number of blocks to be merged in a given read-ahead buffer region
|
||||
void SetTotalRaBlocksMerged(int x) { total_ra_blocks_merged_ = x; }
|
||||
int GetTotalRaBlocksMerged() { return total_ra_blocks_merged_; }
|
||||
void SetSocketPresent(bool socket) { is_socket_present_ = socket; }
|
||||
|
||||
private:
|
||||
bool IsChunkIdMetadata(chunk_t chunk);
|
||||
|
|
@ -314,6 +316,10 @@ class Snapuserd : public std::enable_shared_from_this<Snapuserd> {
|
|||
bool IsBlockAligned(int read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); }
|
||||
struct BufferState* GetBufferState();
|
||||
|
||||
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);
|
||||
|
||||
std::string cow_device_;
|
||||
std::string backing_store_device_;
|
||||
std::string control_device_;
|
||||
|
|
@ -353,6 +359,7 @@ class Snapuserd : public std::enable_shared_from_this<Snapuserd> {
|
|||
|
||||
bool merge_initiated_ = false;
|
||||
bool attached_ = false;
|
||||
bool is_socket_present_;
|
||||
};
|
||||
|
||||
} // namespace snapshot
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ bool SnapuserdServer::Receivemsg(android::base::borrowed_fd fd, const std::strin
|
|||
void SnapuserdServer::RunThread(std::shared_ptr<DmUserHandler> handler) {
|
||||
LOG(INFO) << "Entering thread for handler: " << handler->misc_name();
|
||||
|
||||
handler->snapuserd()->SetSocketPresent(is_socket_present_);
|
||||
if (!handler->snapuserd()->Start()) {
|
||||
LOG(ERROR) << " Failed to launch all worker threads";
|
||||
}
|
||||
|
|
@ -290,6 +291,7 @@ bool SnapuserdServer::StartWithSocket(bool start_listening) {
|
|||
}
|
||||
|
||||
AddWatchedFd(sockfd_, POLLIN);
|
||||
is_socket_present_ = true;
|
||||
|
||||
// If started in first-stage init, the property service won't be online.
|
||||
if (access("/dev/socket/property_service", F_OK) == 0) {
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ class SnapuserdServer : public Stoppable {
|
|||
bool terminating_;
|
||||
volatile bool received_socket_signal_ = false;
|
||||
std::vector<struct pollfd> watched_fds_;
|
||||
bool is_socket_present_ = false;
|
||||
|
||||
std::mutex lock_;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue