1. 程式人生 > 其它 >fs_mgr_libdm模組-dm裝置的建立

fs_mgr_libdm模組-dm裝置的建立

目錄

概述

android/system/core/fs_mgr/libdm和dm裝置的建立

原始碼解析

1. DmTarget模組

1.1 DmTargetLinear建構函式

DmTargetLinear(uint64_t start, uint64_t length, const std::string& block_device,
                   uint64_t physical_sector)
    // 開始,長度,/dev/block/mmcblk,物理扇區起始數
        : DmTarget(start, length), block_device_(block_device), physical_sector_(physical_sector) {}

1.2 DmTarget建構函式

DmTarget(uint64_t start, uint64_t length) : start_(start), length_(length) {}

1.3 Serialize

std::string DmTarget::Serialize() const {
    // Create a string containing a dm_target_spec, parameter data, and an
    // explicit null terminator.
    std::string data(sizeof(dm_target_spec), '\0');
    // dm_target_spec + /dev/block/mmcblk0p05 1234
    data += GetParameterString();
    data.push_back('\0');

    // The kernel expects each target to be 8-byte aligned.
    size_t padding = DM_ALIGN(data.size()) - data.size();
    for (size_t i = 0; i < padding; i++) {
        data.push_back('\0');
    }

    // Finally fill in the dm_target_spec.
    struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(&data[0]);
    spec->sector_start = start();
    spec->length = size();
    snprintf(spec->target_type, sizeof(spec->target_type), "%s", name().c_str());
    spec->next = (uint32_t)data.size();
    return data;
}
struct dm_target_spec {
  __u64 sector_start;
  __u64 length;
  __s32 status;
  __u32 next;
  char target_type[DM_MAX_TYPE_NAME];
};

1.4 GetParameterString-/dev/block/mmcblk0p05-1234

std::string DmTargetLinear::GetParameterString() const {
    return block_device_ + " " + std::to_string(physical_sector_);
}

2. DeviceMapper模組

2.1 DeviceMapper建構函式-開啟device-mapper裝置

DeviceMapper::DeviceMapper() : fd_(-1) {
    // 開啟/dev/device-mapper裝置
    fd_ = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
    if (fd_ < 0) {
        PLOG(ERROR) << "Failed to open device-mapper";
    }
}

2.2 CreateDevice-建立dm裝置

// system_a,table,path是要傳回去的,/sys/devices/virtual/block/dm-0/dm可以看到
bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
                                const std::chrono::milliseconds& timeout_ms) {
    // 1. 生成uuid
    std::string uuid = GenerateUuid();
    // 2. 通過ioctl函式建立DM_DEV_CREATE裝置
    if (!CreateDevice(name, uuid)) {
        return false;
    }

    // We use the unique path for testing whether the device is ready. After
    // that, it's safe to use the dm-N path which is compatible with callers
    // that expect it to be formatted as such.
    std::string unique_path;
    // 1. 載入dm table
    // 2. 獲取裝置檔案/dev/block/mapper/by-uuid/uuid
    // 3. 獲取裝置檔案/dev/block/dm-0
    if (!LoadTableAndActivate(name, table) || !GetDeviceUniquePath(name, &unique_path) ||
        !GetDmDevicePathByName(name, path)) {
        DeleteDevice(name);
        return false;
    }

    if (timeout_ms <= std::chrono::milliseconds::zero()) {
        return true;
    }

    if (IsRecovery()) {
        bool non_ab_device = android::base::GetProperty("ro.build.ab_update", "").empty();
        int sdk = android::base::GetIntProperty("ro.build.version.sdk", 0);
        if (non_ab_device && sdk && sdk <= 29) {
            LOG(INFO) << "Detected ueventd incompatibility, reverting to legacy libdm behavior.";
            unique_path = *path;
        }
    }

    if (!WaitForFile(unique_path, timeout_ms)) {
        LOG(ERROR) << "Failed waiting for device path: " << unique_path;
        DeleteDevice(name);
        return false;
    }
    return true;
}
bool DeviceMapper::CreateDevice(const std::string& name, const std::string& uuid) {
    if (name.empty()) {
        LOG(ERROR) << "Unnamed device mapper device creation is not supported";
        return false;
    }
    if (name.size() >= DM_NAME_LEN) {
        LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
        return false;
    }

    struct dm_ioctl io;
    InitIo(&io, name);
    if (!uuid.empty()) {
        snprintf(io.uuid, sizeof(io.uuid), "%s", uuid.c_str());
    }
// 建立dm裝置
    if (ioctl(fd_, DM_DEV_CREATE, &io)) {
        PLOG(ERROR) << "DM_DEV_CREATE failed for [" << name << "]";
        return false;
    }

    // Check to make sure the newly created device doesn't already have targets
    // added or opened by someone
    CHECK(io.target_count == 0) << "Unexpected targets for newly created [" << name << "] device";
    CHECK(io.open_count == 0) << "Unexpected opens for newly created [" << name << "] device";

    // Creates a new device mapper device with the name passed in
    return true;
}

2.3 GenerateUuid-隨機生成uuid數

static std::string GenerateUuid() {
    uuid_t uuid_bytes;
    // 通過/dev/urandom生成隨機數
    uuid_generate(uuid_bytes);

    char uuid_chars[37] = {};
    // 將二進位制格式轉成36-byte字串的型別
    uuid_unparse_lower(uuid_bytes, uuid_chars);

    return std::string{uuid_chars};
}

2.4 InitIo-初始化dm_ioctl資料

void DeviceMapper::InitIo(struct dm_ioctl* io, const std::string& name) const {
    CHECK(io != nullptr) << "nullptr passed to dm_ioctl initialization";
    memset(io, 0, sizeof(*io));

    io->version[0] = DM_VERSION0;
    io->version[1] = DM_VERSION1;
    io->version[2] = DM_VERSION2;
    io->data_size = sizeof(*io);
    io->data_start = 0;
    if (!name.empty()) {
        snprintf(io->name, sizeof(io->name), "%s", name.c_str());
    }
}

2.5 LoadTableAndActivate-傳table資料下去

// system_a table
bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable& table) {
    std::string ioctl_buffer(sizeof(struct dm_ioctl), 0);
    // 建成serialize
    ioctl_buffer += table.Serialize();

    struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(&ioctl_buffer[0]);
    InitIo(io, name);
    io->data_size = ioctl_buffer.size();
    io->data_start = sizeof(struct dm_ioctl);
    io->target_count = static_cast<uint32_t>(table.num_targets());
    if (table.readonly()) {
        io->flags |= DM_READONLY_FLAG;
    }// 設成DM_TABLE_LOAD
    if (ioctl(fd_, DM_TABLE_LOAD, io)) {
        PLOG(ERROR) << "DM_TABLE_LOAD failed";
        return false;
    }

    InitIo(io, name);
    // 設成DM_DEV_SUSPEND
    if (ioctl(fd_, DM_DEV_SUSPEND, io)) {
        PLOG(ERROR) << "DM_TABLE_SUSPEND resume failed";
        return false;
    }
    return true;
}

2.6 GetDeviceUniquePath-獲取dm裝置的uuid,看dm裝置是否建立成功了

bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) {
    struct dm_ioctl io;
    InitIo(&io, name);
    if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
        PLOG(ERROR) << "Failed to get device path: " << name;
        return false;
    }

    if (io.uuid[0] == '\0') {
        LOG(ERROR) << "Device does not have a unique path: " << name;
        return false;
    }
    *path = "/dev/block/mapper/by-uuid/"s + io.uuid;
    return true;
}

2.7 GetDmDevicePathByName-獲取dm裝置,看dm裝置是否建立成功

bool DeviceMapper::GetDmDevicePathByName(const std::string& name, std::string* path) {
    struct dm_ioctl io;
    InitIo(&io, name);
    if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
        PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
        return false;
    }

    uint32_t dev_num = minor(io.dev);
    *path = "/dev/block/dm-" + std::to_string(dev_num);
    return true;
}

3. DmTable模組

3.1 Serialize

std::string DmTable::Serialize() const {
    if (!valid()) {
        return "";
    }

    std::string table;
    for (const auto& target : targets_) {
        table += target->Serialize();
    }
    return table;
}

問題

補充

參考