Merge "init/fs_mgr: prototype first-stage dm-linear support"
am: 3e946da535

Change-Id: I79fd25d997b451807f9f8ed6ba4145c24defc631
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index f23150d..05dba15 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -42,6 +42,7 @@
         "fs_mgr_verity.cpp",
         "fs_mgr_avb.cpp",
         "fs_mgr_avb_ops.cpp",
+        "fs_mgr_dm_linear.cpp",
     ],
     static_libs: [
         "libfec",
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index e9040df..6e9ffba 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -794,6 +794,29 @@
     return true;
 }
 
+bool fs_mgr_update_logical_partition(struct fstab_rec* rec) {
+    // Logical partitions are specified with a named partition rather than a
+    // block device, so if the block device is a path, then it has already
+    // been updated.
+    if (rec->blk_device[0] == '/') {
+        return true;
+    }
+
+    android::base::unique_fd dm_fd(open("/dev/device-mapper", O_RDONLY));
+    if (dm_fd < 0) {
+        PLOG(ERROR) << "open /dev/device-mapper failed";
+        return false;
+    }
+    struct dm_ioctl io;
+    std::string device_name;
+    if (!fs_mgr_dm_get_device_name(&io, rec->blk_device, dm_fd, &device_name)) {
+        return false;
+    }
+    free(rec->blk_device);
+    rec->blk_device = strdup(device_name.c_str());
+    return true;
+}
+
 /* When multiple fstab records share the same mount_point, it will
  * try to mount each one in turn, and ignore any duplicates after a
  * first successful mount.
@@ -845,6 +868,13 @@
             }
         }
 
+        if ((fstab->recs[i].fs_mgr_flags & MF_LOGICAL)) {
+            if (!fs_mgr_update_logical_partition(&fstab->recs[i])) {
+                LERROR << "Could not set up logical partition, skipping!";
+                continue;
+            }
+        }
+
         if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
             !fs_mgr_wait_for_file(fstab->recs[i].blk_device, 20s)) {
             LERROR << "Skipping '" << fstab->recs[i].blk_device << "' during mount_all";
@@ -1065,6 +1095,13 @@
             return FS_MGR_DOMNT_FAILED;
         }
 
+        if ((fstab->recs[i].fs_mgr_flags & MF_LOGICAL)) {
+            if (!fs_mgr_update_logical_partition(&fstab->recs[i])) {
+                LERROR << "Could not set up logical partition, skipping!";
+                continue;
+            }
+        }
+
         /* First check the filesystem if requested */
         if (fstab->recs[i].fs_mgr_flags & MF_WAIT && !fs_mgr_wait_for_file(n_blk_device, 20s)) {
             LERROR << "Skipping mounting '" << n_blk_device << "'";
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index cf6b497..5a9cb65 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -585,7 +585,13 @@
 
     // Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
     // to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix.
-    std::string partition_name(basename(fstab_entry->blk_device));
+    std::string partition_name;
+    if (fstab_entry->fs_mgr_flags & MF_LOGICAL) {
+        partition_name = fstab_entry->logical_partition_name;
+    } else {
+        partition_name = basename(fstab_entry->blk_device);
+    }
+
     if (fstab_entry->fs_mgr_flags & MF_SLOTSELECT) {
         auto ab_suffix = partition_name.rfind(fs_mgr_get_slot_suffix());
         if (ab_suffix != std::string::npos) {
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
new file mode 100644
index 0000000..b2f3a68
--- /dev/null
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "fs_mgr_dm_linear.h"
+
+#include <inttypes.h>
+#include <linux/dm-ioctl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sstream>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+
+#include "fs_mgr_priv.h"
+#include "fs_mgr_priv_dm_ioctl.h"
+
+namespace android {
+namespace fs_mgr {
+
+std::string LogicalPartitionExtent::Serialize() const {
+    // Note: we need to include an explicit null-terminator.
+    std::string argv =
+        android::base::StringPrintf("%s %" PRIu64, block_device_.c_str(), first_sector_);
+    argv.push_back(0);
+
+    // The kernel expects each target to be aligned.
+    size_t spec_bytes = sizeof(struct dm_target_spec) + argv.size();
+    size_t padding = ((spec_bytes + 7) & ~7) - spec_bytes;
+    for (size_t i = 0; i < padding; i++) {
+        argv.push_back(0);
+    }
+
+    struct dm_target_spec spec;
+    spec.sector_start = logical_sector_;
+    spec.length = num_sectors_;
+    spec.status = 0;
+    strcpy(spec.target_type, "linear");
+    spec.next = sizeof(struct dm_target_spec) + argv.size();
+
+    return std::string((char*)&spec, sizeof(spec)) + argv;
+}
+
+static bool LoadDmTable(int dm_fd, const LogicalPartition& partition) {
+    // Combine all dm_target_spec buffers together.
+    std::string target_string;
+    for (const auto& extent : partition.extents) {
+        target_string += extent.Serialize();
+    }
+
+    // Allocate the ioctl buffer.
+    size_t buffer_size = sizeof(struct dm_ioctl) + target_string.size();
+    std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(buffer_size);
+
+    // Initialize the ioctl buffer header, then copy our target specs in.
+    struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
+    fs_mgr_dm_ioctl_init(io, buffer_size, partition.name);
+    io->target_count = partition.extents.size();
+    if (partition.attributes & kPartitionReadonly) {
+        io->flags |= DM_READONLY_FLAG;
+    }
+    memcpy(io + 1, target_string.c_str(), target_string.size());
+
+    if (ioctl(dm_fd, DM_TABLE_LOAD, io)) {
+        PERROR << "Failed ioctl() on DM_TABLE_LOAD, partition " << partition.name;
+        return false;
+    }
+    return true;
+}
+
+static bool LoadTablesAndActivate(int dm_fd, const LogicalPartition& partition) {
+    if (!LoadDmTable(dm_fd, partition)) {
+        return false;
+    }
+
+    struct dm_ioctl io;
+    return fs_mgr_dm_resume_table(&io, partition.name, dm_fd);
+}
+
+static bool CreateDmDeviceForPartition(int dm_fd, const LogicalPartition& partition) {
+    struct dm_ioctl io;
+    if (!fs_mgr_dm_create_device(&io, partition.name, dm_fd)) {
+        return false;
+    }
+    if (!LoadTablesAndActivate(dm_fd, partition)) {
+        // Remove the device rather than leave it in an inactive state.
+        fs_mgr_dm_destroy_device(&io, partition.name, dm_fd);
+        return false;
+    }
+
+    LINFO << "Created device-mapper device: " << partition.name;
+    return true;
+}
+
+bool CreateLogicalPartitions(const LogicalPartitionTable& table) {
+    android::base::unique_fd dm_fd(open("/dev/device-mapper", O_RDWR));
+    if (dm_fd < 0) {
+        PLOG(ERROR) << "failed to open /dev/device-mapper";
+        return false;
+    }
+    for (const auto& partition : table.partitions) {
+        if (!CreateDmDeviceForPartition(dm_fd, partition)) {
+            LOG(ERROR) << "could not create dm-linear device for partition: " << partition.name;
+            return false;
+        }
+    }
+    return true;
+}
+
+std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree() {
+    return nullptr;
+}
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 3fbef9f..472ab59 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -109,6 +109,7 @@
     {"logicalblk=", MF_LOGICALBLKSIZE},
     {"sysfs_path=", MF_SYSFS},
     {"defaults", 0},
+    {"logical", MF_LOGICAL},
     {0, 0},
 };
 
@@ -445,10 +446,6 @@
             LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
             return {};
         }
-        if (!StartsWith(value, "/dev")) {
-            LERROR << "dt_fstab: Invalid device node for partition " << dp->d_name;
-            return {};
-        }
         fstab_entry.push_back(value);
 
         std::string mount_point;
@@ -631,6 +628,10 @@
         fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
         fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
         fstab->recs[cnt].sysfs_path = flag_vals.sysfs_path;
+        if (fstab->recs[cnt].fs_mgr_flags & MF_LOGICAL) {
+            fstab->recs[cnt].logical_partition_name = strdup(fstab->recs[cnt].blk_device);
+        }
+
         cnt++;
     }
     /* If an A/B partition, modify block device to be the real block device */
@@ -797,6 +798,7 @@
     for (i = 0; i < fstab->num_entries; i++) {
         /* Free the pointers return by strdup(3) */
         free(fstab->recs[i].blk_device);
+        free(fstab->recs[i].logical_partition_name);
         free(fstab->recs[i].mount_point);
         free(fstab->recs[i].fs_type);
         free(fstab->recs[i].fs_options);
@@ -944,3 +946,7 @@
 {
     return fstab->fs_mgr_flags & MF_SYSFS;
 }
+
+int fs_mgr_is_logical(const struct fstab_rec* fstab) {
+    return fstab->fs_mgr_flags & MF_LOGICAL;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index ade0cc4..afd7227 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -82,6 +82,7 @@
  *
  */
 
+// clang-format off
 #define MF_WAIT                  0x1
 #define MF_CHECK                 0x2
 #define MF_CRYPT                 0x4
@@ -111,6 +112,8 @@
 #define MF_AVB             0X2000000
 #define MF_KEYDIRECTORY    0X4000000
 #define MF_SYSFS           0X8000000
+#define MF_LOGICAL        0x10000000
+// clang-format on
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 0a113b4..3b01d0e 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -36,19 +36,30 @@
     std::string ab_suffix;
 
     for (n = 0; n < fstab->num_entries; n++) {
-        if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) {
-            char *tmp;
+        fstab_rec& record = fstab->recs[n];
+        if (record.fs_mgr_flags & MF_SLOTSELECT) {
             if (ab_suffix.empty()) {
                 ab_suffix = fs_mgr_get_slot_suffix();
                 // Return false if failed to get ab_suffix when MF_SLOTSELECT is specified.
                 if (ab_suffix.empty()) return false;
             }
-            if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, ab_suffix.c_str()) > 0) {
-                free(fstab->recs[n].blk_device);
-                fstab->recs[n].blk_device = tmp;
-            } else {
+
+            char* new_blk_device;
+            if (asprintf(&new_blk_device, "%s%s", record.blk_device, ab_suffix.c_str()) <= 0) {
                 return false;
             }
+            free(record.blk_device);
+            record.blk_device = new_blk_device;
+
+            char* new_partition_name;
+            if (record.logical_partition_name) {
+                if (asprintf(&new_partition_name, "%s%s", record.logical_partition_name,
+                             ab_suffix.c_str()) <= 0) {
+                    return false;
+                }
+                free(record.logical_partition_name);
+                record.logical_partition_name = new_partition_name;
+            }
         }
     }
     return true;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 653d8fa..72f019e 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -76,6 +76,7 @@
 bool fs_mgr_load_verity_state(int* mode);
 bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
 int fs_mgr_swapon_all(struct fstab *fstab);
+bool fs_mgr_update_logical_partition(struct fstab_rec* rec);
 
 int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
 
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
new file mode 100644
index 0000000..7f928e5
--- /dev/null
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CORE_FS_MGR_DM_LINEAR_H
+#define __CORE_FS_MGR_DM_LINEAR_H
+
+#include <stdint.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace fs_mgr {
+
+static const uint32_t kPartitionReadonly = 0x1;
+
+class LogicalPartitionExtent {
+  public:
+    LogicalPartitionExtent() : logical_sector_(0), first_sector_(0), num_sectors_(0) {}
+    LogicalPartitionExtent(uint64_t logical_sector, uint64_t first_sector, uint64_t num_sectors,
+                           const std::string& block_device)
+        : logical_sector_(logical_sector),
+          first_sector_(first_sector),
+          num_sectors_(num_sectors),
+          block_device_(block_device) {}
+
+    // Return a string containing the dm_target_spec buffer needed to use this
+    // extent in a device-mapper table.
+    std::string Serialize() const;
+
+    const std::string& block_device() const { return block_device_; }
+
+  private:
+    // Logical sector this extent represents in the presented block device.
+    // This is equal to the previous extent's logical sector plus the number
+    // of sectors in that extent. The first extent always starts at 0.
+    uint64_t logical_sector_;
+    // First 512-byte sector of this extent, on the source block device.
+    uint64_t first_sector_;
+    // Number of 512-byte sectors.
+    uint64_t num_sectors_;
+    // Target block device.
+    std::string block_device_;
+};
+
+struct LogicalPartition {
+    LogicalPartition() : attributes(0), num_sectors(0) {}
+
+    std::string name;
+    uint32_t attributes;
+    // Number of 512-byte sectors total.
+    uint64_t num_sectors;
+    // List of extents.
+    std::vector<LogicalPartitionExtent> extents;
+};
+
+struct LogicalPartitionTable {
+    // List of partitions in the partition table.
+    std::vector<LogicalPartition> partitions;
+};
+
+// Load a dm-linear table from the device tree if one is available; otherwise,
+// return null.
+std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree();
+
+// Create device-mapper devices for the given partition table.
+//
+// On success, two devices nodes will be created for each partition, both
+// pointing to the same device:
+//   /dev/block/dm-<N> where N is a sequential ID assigned by device-mapper.
+//   /dev/block/dm-<name> where |name| is the partition name.
+//
+bool CreateLogicalPartitions(const LogicalPartitionTable& table);
+
+}  // namespace fs_mgr
+}  // namespace android
+
+#endif  // __CORE_FS_MGR_DM_LINEAR_H
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 8c585dd..04ccfc5 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -37,6 +37,7 @@
 
 struct fstab_rec {
     char* blk_device;
+    char* logical_partition_name;
     char* mount_point;
     char* fs_type;
     unsigned long flags;
@@ -84,6 +85,7 @@
 int fs_mgr_is_nofail(const struct fstab_rec* fstab);
 int fs_mgr_is_latemount(const struct fstab_rec* fstab);
 int fs_mgr_is_quota(const struct fstab_rec* fstab);
+int fs_mgr_is_logical(const struct fstab_rec* fstab);
 int fs_mgr_has_sysfs_path(const struct fstab_rec* fstab);
 
 std::string fs_mgr_get_slot_suffix();
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 1b6e97e..a5ba647 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -33,11 +33,13 @@
 #include "devices.h"
 #include "fs_mgr.h"
 #include "fs_mgr_avb.h"
+#include "fs_mgr_dm_linear.h"
 #include "uevent.h"
 #include "uevent_listener.h"
 #include "util.h"
 
 using android::base::Timer;
+using android::fs_mgr::LogicalPartitionTable;
 
 namespace android {
 namespace init {
@@ -58,18 +60,21 @@
   protected:
     ListenerAction HandleBlockDevice(const std::string& name, const Uevent&);
     bool InitRequiredDevices();
-    bool InitVerityDevice(const std::string& verity_device);
+    bool InitMappedDevice(const std::string& verity_device);
+    bool CreateLogicalPartitions();
     bool MountPartitions();
+    bool GetBackingDmLinearDevices();
 
     virtual ListenerAction UeventCallback(const Uevent& uevent);
 
     // Pure virtual functions.
-    virtual bool GetRequiredDevices() = 0;
+    virtual bool GetDmVerityDevices() = 0;
     virtual bool SetUpDmVerity(fstab_rec* fstab_rec) = 0;
 
     bool need_dm_verity_;
 
     std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> device_tree_fstab_;
+    std::unique_ptr<LogicalPartitionTable> dm_linear_table_;
     std::vector<fstab_rec*> mount_fstab_recs_;
     std::set<std::string> required_devices_partition_names_;
     DeviceHandler device_handler_;
@@ -82,7 +87,7 @@
     ~FirstStageMountVBootV1() override = default;
 
   protected:
-    bool GetRequiredDevices() override;
+    bool GetDmVerityDevices() override;
     bool SetUpDmVerity(fstab_rec* fstab_rec) override;
 };
 
@@ -95,7 +100,7 @@
 
   protected:
     ListenerAction UeventCallback(const Uevent& uevent) override;
-    bool GetRequiredDevices() override;
+    bool GetDmVerityDevices() override;
     bool SetUpDmVerity(fstab_rec* fstab_rec) override;
     bool InitAvbHandle();
 
@@ -114,6 +119,17 @@
     return access("/sbin/recovery", F_OK) == 0;
 }
 
+static inline bool IsDmLinearEnabled() {
+    bool enabled = false;
+    import_kernel_cmdline(
+        false, [&enabled](const std::string& key, const std::string& value, bool in_qemu) {
+            if (key == "androidboot.lrap" && value == "1") {
+                enabled = true;
+            }
+        });
+    return enabled;
+}
+
 // Class Definitions
 // -----------------
 FirstStageMount::FirstStageMount()
@@ -127,6 +143,10 @@
     } else {
         LOG(INFO) << "Failed to read fstab from device tree";
     }
+
+    if (IsDmLinearEnabled()) {
+        dm_linear_table_ = android::fs_mgr::LoadPartitionsFromDeviceTree();
+    }
 }
 
 std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
@@ -138,7 +158,7 @@
 }
 
 bool FirstStageMount::DoFirstStageMount() {
-    if (mount_fstab_recs_.empty()) {
+    if (!dm_linear_table_ && mount_fstab_recs_.empty()) {
         // Nothing to mount.
         LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
         return true;
@@ -146,13 +166,30 @@
 
     if (!InitDevices()) return false;
 
+    if (!CreateLogicalPartitions()) return false;
+
     if (!MountPartitions()) return false;
 
     return true;
 }
 
 bool FirstStageMount::InitDevices() {
-    return GetRequiredDevices() && InitRequiredDevices();
+    return GetBackingDmLinearDevices() && GetDmVerityDevices() && InitRequiredDevices();
+}
+
+bool FirstStageMount::GetBackingDmLinearDevices() {
+    // Add any additional devices required for dm-linear mappings.
+    if (!dm_linear_table_) {
+        return true;
+    }
+
+    for (const auto& partition : dm_linear_table_->partitions) {
+        for (const auto& extent : partition.extents) {
+            const std::string& partition_name = android::base::Basename(extent.block_device());
+            required_devices_partition_names_.emplace(partition_name);
+        }
+    }
+    return true;
 }
 
 // Creates devices with uevent->partition_name matching one in the member variable
@@ -163,7 +200,7 @@
         return true;
     }
 
-    if (need_dm_verity_) {
+    if (dm_linear_table_ || need_dm_verity_) {
         const std::string dm_path = "/devices/virtual/misc/device-mapper";
         bool found = false;
         auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
@@ -210,6 +247,13 @@
     return true;
 }
 
+bool FirstStageMount::CreateLogicalPartitions() {
+    if (!dm_linear_table_) {
+        return true;
+    }
+    return android::fs_mgr::CreateLogicalPartitions(*dm_linear_table_.get());
+}
+
 ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent) {
     // Matches partition name to create device nodes.
     // Both required_devices_partition_names_ and uevent->partition_name have A/B
@@ -247,14 +291,14 @@
 }
 
 // Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
-bool FirstStageMount::InitVerityDevice(const std::string& verity_device) {
-    const std::string device_name(basename(verity_device.c_str()));
+bool FirstStageMount::InitMappedDevice(const std::string& dm_device) {
+    const std::string device_name(basename(dm_device.c_str()));
     const std::string syspath = "/sys/block/" + device_name;
     bool found = false;
 
-    auto verity_callback = [&device_name, &verity_device, this, &found](const Uevent& uevent) {
+    auto verity_callback = [&device_name, &dm_device, this, &found](const Uevent& uevent) {
         if (uevent.device_name == device_name) {
-            LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
+            LOG(VERBOSE) << "Creating device-mapper device : " << dm_device;
             device_handler_.HandleDeviceEvent(uevent);
             found = true;
             return ListenerAction::kStop;
@@ -279,6 +323,14 @@
 
 bool FirstStageMount::MountPartitions() {
     for (auto fstab_rec : mount_fstab_recs_) {
+        if (fs_mgr_is_logical(fstab_rec)) {
+            if (!fs_mgr_update_logical_partition(fstab_rec)) {
+                return false;
+            }
+            if (!InitMappedDevice(fstab_rec->blk_device)) {
+                return false;
+            }
+        }
         if (!SetUpDmVerity(fstab_rec)) {
             PLOG(ERROR) << "Failed to setup verity for '" << fstab_rec->mount_point << "'";
             return false;
@@ -291,7 +343,7 @@
     return true;
 }
 
-bool FirstStageMountVBootV1::GetRequiredDevices() {
+bool FirstStageMountVBootV1::GetDmVerityDevices() {
     std::string verity_loc_device;
     need_dm_verity_ = false;
 
@@ -344,7 +396,7 @@
                 // The exact block device name (fstab_rec->blk_device) is changed to
                 // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
                 // first stage.
-                return InitVerityDevice(fstab_rec->blk_device);
+                return InitMappedDevice(fstab_rec->blk_device);
             default:
                 return false;
         }
@@ -371,7 +423,7 @@
     }
 }
 
-bool FirstStageMountVBootV2::GetRequiredDevices() {
+bool FirstStageMountVBootV2::GetDmVerityDevices() {
     need_dm_verity_ = false;
 
     // fstab_rec->blk_device has A/B suffix.
@@ -444,7 +496,7 @@
                 // The exact block device name (fstab_rec->blk_device) is changed to
                 // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
                 // first stage.
-                return InitVerityDevice(fstab_rec->blk_device);
+                return InitMappedDevice(fstab_rec->blk_device);
             default:
                 return false;
         }