Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9545f38b authored by Akilesh Kailash's avatar Akilesh Kailash Committed by Automerger Merge Worker
Browse files

Merge "snapuserd: Read partition blocks to memory" am: e19f7be1

Original change: https://android-review.googlesource.com/c/platform/system/core/+/1774746

Change-Id: Ifa4400c1326e156942f28a193893f715fc4f32bf
parents d2cff5a1 e19f7be1
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
@@ -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
+8 −0
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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",
+0 −2
Original line number Diff line number Diff line
@@ -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 {
+113 −0
Original line number Diff line number Diff line
@@ -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;
Loading