Merge changes from topic "zram_loop"
* changes:
Set the I/O scheduler of loop devices to 'none'
Rename two local variables
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index a5eda29..8e3d5a5 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -651,5 +651,61 @@
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
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 8fcdf74..31c3003 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -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 @@
// * 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
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index bc97afc..47268d4 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -78,6 +78,7 @@
"liblog",
"libsnapshot_cow",
"libz",
+ "libext4_utils",
],
}
@@ -121,6 +122,7 @@
"libz",
"libfs_mgr",
"libdm",
+ "libext4_utils",
],
header_libs: [
"libstorage_literals_headers",
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
index 6bb7a39..c592257 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
+++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
@@ -47,8 +47,6 @@
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 {
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd.cpp
index 0aacab2..2abf431 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd.cpp
@@ -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 @@
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 @@
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;
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd.h b/fs_mgr/libsnapshot/snapuserd/snapuserd.h
index b223e89..b30041d 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd.h
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd.h
@@ -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 @@
// 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 @@
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 @@
bool merge_initiated_ = false;
bool attached_ = false;
+ bool is_socket_present_;
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_server.cpp
index 672c13c..2f87557 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_server.cpp
@@ -227,6 +227,7 @@
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 @@
}
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) {
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/snapuserd_server.h
index 846f848..3b6ff15 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_server.h
@@ -96,6 +96,7 @@
bool terminating_;
volatile bool received_socket_signal_ = false;
std::vector<struct pollfd> watched_fds_;
+ bool is_socket_present_ = false;
std::mutex lock_;