Merge "Replace manual dm ioctls with libdm." am: bc5818774c
am: f1fa57d602

Change-Id: I8f49bf924272195c6ae2e827cfb78766d644d154
diff --git a/Android.bp b/Android.bp
index 1045dc2..03e9a3f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -30,6 +30,7 @@
     static_libs: [
         "libavb",
         "libbootloader_message",
+        "libdm",
         "libfec",
         "libfec_rs",
         "libfs_avb",
diff --git a/Devmapper.cpp b/Devmapper.cpp
index b42467c..d55d92d 100644
--- a/Devmapper.cpp
+++ b/Devmapper.cpp
@@ -23,7 +23,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -32,239 +31,72 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <libdm/dm.h>
 #include <utils/Trace.h>
 
 #include "Devmapper.h"
 
-#define DEVMAPPER_BUFFER_SIZE 4096
-
 using android::base::StringPrintf;
+using namespace android::dm;
 
 static const char* kVoldPrefix = "vold:";
 
-void Devmapper::ioctlInit(struct dm_ioctl* io, size_t dataSize, const char* name, unsigned flags) {
-    memset(io, 0, dataSize);
-    io->data_size = dataSize;
-    io->data_start = sizeof(struct dm_ioctl);
-    io->version[0] = 4;
-    io->version[1] = 0;
-    io->version[2] = 0;
-    io->flags = flags;
-    if (name) {
-        size_t ret = strlcpy(io->name, name, sizeof(io->name));
-        if (ret >= sizeof(io->name)) abort();
-    }
-}
-
 int Devmapper::create(const char* name_raw, const char* loopFile, const char* key,
                       unsigned long numSectors, char* ubuffer, size_t len) {
+    auto& dm = DeviceMapper::Instance();
     auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
-    const char* name = name_string.c_str();
 
-    char* buffer = (char*)malloc(DEVMAPPER_BUFFER_SIZE);
-    if (!buffer) {
-        PLOG(ERROR) << "Failed malloc";
+    DmTable table;
+    table.Emplace<DmTargetCrypt>(0, numSectors, "twofish", key, 0, loopFile, 0);
+
+    if (!dm.CreateDevice(name_string, table)) {
+        LOG(ERROR) << "Failed to create device-mapper device " << name_string;
         return -1;
     }
 
-    int fd;
-    if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
-        PLOG(ERROR) << "Failed open";
-        free(buffer);
+    std::string path;
+    if (!dm.GetDmDevicePathByName(name_string, &path)) {
+        LOG(ERROR) << "Failed to get device-mapper device path for " << name_string;
         return -1;
     }
-
-    struct dm_ioctl* io = (struct dm_ioctl*)buffer;
-
-    // Create the DM device
-    ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
-
-    if (ioctl(fd, DM_DEV_CREATE, io)) {
-        PLOG(ERROR) << "Failed DM_DEV_CREATE";
-        free(buffer);
-        close(fd);
-        return -1;
-    }
-
-    // Set the legacy geometry
-    ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
-
-    char* geoParams = buffer + sizeof(struct dm_ioctl);
-    // bps=512 spc=8 res=32 nft=2 sec=8190 mid=0xf0 spt=63 hds=64 hid=0 bspf=8 rdcl=2 infs=1 bkbs=2
-    strlcpy(geoParams, "0 64 63 0", DEVMAPPER_BUFFER_SIZE - sizeof(struct dm_ioctl));
-    geoParams += strlen(geoParams) + 1;
-    geoParams = (char*)_align(geoParams, 8);
-    if (ioctl(fd, DM_DEV_SET_GEOMETRY, io)) {
-        PLOG(ERROR) << "Failed DM_DEV_SET_GEOMETRY";
-        free(buffer);
-        close(fd);
-        return -1;
-    }
-
-    // Retrieve the device number we were allocated
-    ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
-    if (ioctl(fd, DM_DEV_STATUS, io)) {
-        PLOG(ERROR) << "Failed DM_DEV_STATUS";
-        free(buffer);
-        close(fd);
-        return -1;
-    }
-
-    unsigned minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
-    snprintf(ubuffer, len, "/dev/block/dm-%u", minor);
-
-    // Load the table
-    struct dm_target_spec* tgt;
-    tgt = (struct dm_target_spec*)&buffer[sizeof(struct dm_ioctl)];
-
-    ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, DM_STATUS_TABLE_FLAG);
-    io->target_count = 1;
-    tgt->status = 0;
-
-    tgt->sector_start = 0;
-    tgt->length = numSectors;
-
-    strlcpy(tgt->target_type, "crypt", sizeof(tgt->target_type));
-
-    char* cryptParams = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
-    snprintf(cryptParams,
-             DEVMAPPER_BUFFER_SIZE - (sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec)),
-             "twofish %s 0 %s 0", key, loopFile);
-    cryptParams += strlen(cryptParams) + 1;
-    cryptParams = (char*)_align(cryptParams, 8);
-    tgt->next = cryptParams - buffer;
-
-    if (ioctl(fd, DM_TABLE_LOAD, io)) {
-        PLOG(ERROR) << "Failed DM_TABLE_LOAD";
-        free(buffer);
-        close(fd);
-        return -1;
-    }
-
-    // Resume the new table
-    ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
-
-    if (ioctl(fd, DM_DEV_SUSPEND, io)) {
-        PLOG(ERROR) << "Failed DM_DEV_SUSPEND";
-        free(buffer);
-        close(fd);
-        return -1;
-    }
-
-    free(buffer);
-
-    close(fd);
+    snprintf(ubuffer, len, "%s", path.c_str());
     return 0;
 }
 
 int Devmapper::destroy(const char* name_raw) {
+    auto& dm = DeviceMapper::Instance();
+
     auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
-    const char* name = name_string.c_str();
-
-    char* buffer = (char*)malloc(DEVMAPPER_BUFFER_SIZE);
-    if (!buffer) {
-        PLOG(ERROR) << "Failed malloc";
-        return -1;
-    }
-
-    int fd;
-    if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
-        PLOG(ERROR) << "Failed open";
-        free(buffer);
-        return -1;
-    }
-
-    struct dm_ioctl* io = (struct dm_ioctl*)buffer;
-
-    // Create the DM device
-    ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
-
-    if (ioctl(fd, DM_DEV_REMOVE, io)) {
+    if (!dm.DeleteDevice(name_string)) {
         if (errno != ENXIO) {
             PLOG(ERROR) << "Failed DM_DEV_REMOVE";
         }
-        free(buffer);
-        close(fd);
         return -1;
     }
-
-    free(buffer);
-    close(fd);
     return 0;
 }
 
 int Devmapper::destroyAll() {
     ATRACE_NAME("Devmapper::destroyAll");
-    char* buffer = (char*)malloc(1024 * 64);
-    if (!buffer) {
-        PLOG(ERROR) << "Failed malloc";
-        return -1;
-    }
-    memset(buffer, 0, (1024 * 64));
 
-    char* buffer2 = (char*)malloc(DEVMAPPER_BUFFER_SIZE);
-    if (!buffer2) {
-        PLOG(ERROR) << "Failed malloc";
-        free(buffer);
+    auto& dm = DeviceMapper::Instance();
+    std::vector<DeviceMapper::DmBlockDevice> devices;
+    if (!dm.GetAvailableDevices(&devices)) {
+        LOG(ERROR) << "Failed to get dm devices";
         return -1;
     }
 
-    int fd;
-    if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
-        PLOG(ERROR) << "Failed open";
-        free(buffer);
-        free(buffer2);
-        return -1;
-    }
-
-    struct dm_ioctl* io = (struct dm_ioctl*)buffer;
-    ioctlInit(io, (1024 * 64), NULL, 0);
-
-    if (ioctl(fd, DM_LIST_DEVICES, io)) {
-        PLOG(ERROR) << "Failed DM_LIST_DEVICES";
-        free(buffer);
-        free(buffer2);
-        close(fd);
-        return -1;
-    }
-
-    struct dm_name_list* n = (struct dm_name_list*)(((char*)buffer) + io->data_start);
-    if (!n->dev) {
-        free(buffer);
-        free(buffer2);
-        close(fd);
-        return 0;
-    }
-
-    unsigned nxt = 0;
-    do {
-        n = (struct dm_name_list*)(((char*)n) + nxt);
-        auto name = std::string(n->name);
-        if (android::base::StartsWith(name, kVoldPrefix)) {
-            LOG(DEBUG) << "Tearing down stale dm device named " << name;
-
-            memset(buffer2, 0, DEVMAPPER_BUFFER_SIZE);
-            struct dm_ioctl* io2 = (struct dm_ioctl*)buffer2;
-            ioctlInit(io2, DEVMAPPER_BUFFER_SIZE, n->name, 0);
-            if (ioctl(fd, DM_DEV_REMOVE, io2)) {
+    for (const auto& device : devices) {
+        if (android::base::StartsWith(device.name(), kVoldPrefix)) {
+            LOG(DEBUG) << "Tearing down stale dm device named " << device.name();
+            if (!dm.DeleteDevice(device.name())) {
                 if (errno != ENXIO) {
-                    PLOG(WARNING) << "Failed to destroy dm device named " << name;
+                    PLOG(WARNING) << "Failed to destroy dm device named " << device.name();
                 }
             }
         } else {
-            LOG(DEBUG) << "Found unmanaged dm device named " << name;
+            LOG(DEBUG) << "Found unmanaged dm device named " << device.name();
         }
-        nxt = n->next;
-    } while (nxt);
-
-    free(buffer);
-    free(buffer2);
-    close(fd);
+    }
     return 0;
 }
-
-void* Devmapper::_align(void* ptr, unsigned int a) {
-    unsigned long agn = --a;
-
-    return (void*)(((unsigned long)ptr + agn) & ~agn);
-}
diff --git a/Devmapper.h b/Devmapper.h
index b1f6dfa..9d4896e 100644
--- a/Devmapper.h
+++ b/Devmapper.h
@@ -26,10 +26,6 @@
                       unsigned long numSectors, char* buffer, size_t len);
     static int destroy(const char* name);
     static int destroyAll();
-
-  private:
-    static void* _align(void* ptr, unsigned int a);
-    static void ioctlInit(struct dm_ioctl* io, size_t data_size, const char* name, unsigned flags);
 };
 
 #endif
diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp
index deb7194..573d4cc 100644
--- a/MetadataCrypt.cpp
+++ b/MetadataCrypt.cpp
@@ -23,19 +23,17 @@
 #include <vector>
 
 #include <fcntl.h>
-#include <sys/ioctl.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include <linux/dm-ioctl.h>
-
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/unique_fd.h>
 #include <cutils/fs.h>
 #include <fs_mgr.h>
+#include <libdm/dm.h>
 
 #include "Checkpoint.h"
 #include "EncryptInplace.h"
@@ -45,13 +43,12 @@
 #include "Utils.h"
 #include "VoldUtil.h"
 
-#define DM_CRYPT_BUF_SIZE 4096
 #define TABLE_LOAD_RETRIES 10
-#define DEFAULT_KEY_TARGET_TYPE "default-key"
 
 using android::fs_mgr::FstabEntry;
 using android::fs_mgr::GetEntryForMountPoint;
 using android::vold::KeyBuffer;
+using namespace android::dm;
 
 static const std::string kDmNameUserdata = "userdata";
 
@@ -146,16 +143,6 @@
 }  // namespace vold
 }  // namespace android
 
-static KeyBuffer default_key_params(const std::string& real_blkdev, const KeyBuffer& key) {
-    KeyBuffer hex_key;
-    if (android::vold::StrToHex(key, hex_key) != android::OK) {
-        LOG(ERROR) << "Failed to turn key to hex";
-        return KeyBuffer();
-    }
-    auto res = KeyBuffer() + "AES-256-XTS " + hex_key + " " + real_blkdev.c_str() + " 0";
-    return res;
-}
-
 static bool get_number_of_sectors(const std::string& real_blkdev, uint64_t* nr_sec) {
     if (android::vold::GetBlockDev512Sectors(real_blkdev, nr_sec) != android::OK) {
         PLOG(ERROR) << "Unable to measure size of " << real_blkdev;
@@ -164,86 +151,35 @@
     return true;
 }
 
-static struct dm_ioctl* dm_ioctl_init(char* buffer, size_t buffer_size, const std::string& dm_name) {
-    if (buffer_size < sizeof(dm_ioctl)) {
-        LOG(ERROR) << "dm_ioctl buffer too small";
-        return nullptr;
-    }
-
-    memset(buffer, 0, buffer_size);
-    struct dm_ioctl* io = (struct dm_ioctl*)buffer;
-    io->data_size = buffer_size;
-    io->data_start = sizeof(struct dm_ioctl);
-    io->version[0] = 4;
-    io->version[1] = 0;
-    io->version[2] = 0;
-    io->flags = 0;
-    dm_name.copy(io->name, sizeof(io->name));
-    return io;
-}
-
 static bool create_crypto_blk_dev(const std::string& dm_name, uint64_t nr_sec,
-                                  const std::string& target_type, const KeyBuffer& crypt_params,
+                                  const std::string& real_blkdev, const KeyBuffer& key,
                                   std::string* crypto_blkdev) {
-    android::base::unique_fd dm_fd(
-        TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC, 0)));
-    if (dm_fd == -1) {
-        PLOG(ERROR) << "Cannot open device-mapper";
+    auto& dm = DeviceMapper::Instance();
+
+    KeyBuffer hex_key_buffer;
+    if (android::vold::StrToHex(key, hex_key_buffer) != android::OK) {
+        LOG(ERROR) << "Failed to turn key to hex";
         return false;
     }
-    alignas(struct dm_ioctl) char buffer[DM_CRYPT_BUF_SIZE];
-    auto io = dm_ioctl_init(buffer, sizeof(buffer), dm_name);
-    if (!io || ioctl(dm_fd.get(), DM_DEV_CREATE, io) != 0) {
-        PLOG(ERROR) << "Cannot create dm-crypt device " << dm_name;
-        return false;
-    }
+    std::string hex_key(hex_key_buffer.data(), hex_key_buffer.size());
 
-    // Get the device status, in particular, the name of its device file
-    io = dm_ioctl_init(buffer, sizeof(buffer), dm_name);
-    if (ioctl(dm_fd.get(), DM_DEV_STATUS, io) != 0) {
-        PLOG(ERROR) << "Cannot retrieve dm-crypt device status " << dm_name;
-        return false;
-    }
-    *crypto_blkdev = std::string() + "/dev/block/dm-" +
-                     std::to_string((io->dev & 0xff) | ((io->dev >> 12) & 0xfff00));
-
-    io = dm_ioctl_init(buffer, sizeof(buffer), dm_name);
-    size_t paramix = io->data_start + sizeof(struct dm_target_spec);
-    size_t nullix = paramix + crypt_params.size();
-    size_t endix = (nullix + 1 + 7) & 8;  // Add room for \0 and align to 8 byte boundary
-
-    if (endix > sizeof(buffer)) {
-        LOG(ERROR) << "crypt_params too big for DM_CRYPT_BUF_SIZE";
-        return false;
-    }
-
-    io->target_count = 1;
-    auto tgt = (struct dm_target_spec*)(buffer + io->data_start);
-    tgt->status = 0;
-    tgt->sector_start = 0;
-    tgt->length = nr_sec;
-    target_type.copy(tgt->target_type, sizeof(tgt->target_type));
-    memcpy(buffer + paramix, crypt_params.data(),
-           std::min(crypt_params.size(), sizeof(buffer) - paramix));
-    buffer[nullix] = '\0';
-    tgt->next = endix;
+    DmTable table;
+    table.Emplace<DmTargetDefaultKey>(0, nr_sec, "AES-256-XTS", hex_key, real_blkdev, 0);
 
     for (int i = 0;; i++) {
-        if (ioctl(dm_fd.get(), DM_TABLE_LOAD, io) == 0) {
+        if (dm.CreateDevice(dm_name, table)) {
             break;
         }
         if (i + 1 >= TABLE_LOAD_RETRIES) {
-            PLOG(ERROR) << "DM_TABLE_LOAD ioctl failed";
+            LOG(ERROR) << "Could not create default-key device " << dm_name;
             return false;
         }
-        PLOG(INFO) << "DM_TABLE_LOAD ioctl failed, retrying";
+        PLOG(INFO) << "Could not create default-key device, retrying";
         usleep(500000);
     }
 
-    // Resume this device to activate it
-    io = dm_ioctl_init(buffer, sizeof(buffer), dm_name);
-    if (ioctl(dm_fd.get(), DM_DEV_SUSPEND, io)) {
-        PLOG(ERROR) << "Cannot resume dm-crypt device " << dm_name;
+    if (!dm.GetDmDevicePathByName(dm_name, crypto_blkdev)) {
+        LOG(ERROR) << "Cannot retrieve default-key device status " << dm_name;
         return false;
     }
     return true;
@@ -267,8 +203,7 @@
     uint64_t nr_sec;
     if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false;
     std::string crypto_blkdev;
-    if (!create_crypto_blk_dev(kDmNameUserdata, nr_sec, DEFAULT_KEY_TARGET_TYPE,
-                               default_key_params(data_rec->blk_device, key), &crypto_blkdev))
+    if (!create_crypto_blk_dev(kDmNameUserdata, nr_sec, data_rec->blk_device, key, &crypto_blkdev))
         return false;
     // FIXME handle the corrupt case
     if (needs_encrypt) {
diff --git a/cryptfs.cpp b/cryptfs.cpp
index 0b7101e..c5d0307 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -45,6 +45,7 @@
 #include <fs_mgr.h>
 #include <fscrypt/fscrypt.h>
 #include <hardware_legacy/power.h>
+#include <libdm/dm.h>
 #include <log/log.h>
 #include <logwrap/logwrap.h>
 #include <openssl/evp.h>
@@ -56,13 +57,11 @@
 #include <fcntl.h>
 #include <inttypes.h>
 #include <libgen.h>
-#include <linux/dm-ioctl.h>
 #include <linux/kdev_t.h>
 #include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/ioctl.h>
 #include <sys/mount.h>
 #include <sys/param.h>
 #include <sys/stat.h>
@@ -78,12 +77,11 @@
 using android::base::ParseUint;
 using android::base::StringPrintf;
 using android::fs_mgr::GetEntryForMountPoint;
+using namespace android::dm;
 using namespace std::chrono_literals;
 
 #define UNUSED __attribute__((unused))
 
-#define DM_CRYPT_BUF_SIZE 4096
-
 #define HASH_COUNT 2000
 
 constexpr size_t INTERMEDIATE_KEY_LEN_BYTES = 16;
@@ -253,19 +251,6 @@
     return;
 }
 
-static void ioctl_init(struct dm_ioctl* io, size_t dataSize, const char* name, unsigned flags) {
-    memset(io, 0, dataSize);
-    io->data_size = dataSize;
-    io->data_start = sizeof(struct dm_ioctl);
-    io->version[0] = 4;
-    io->version[1] = 0;
-    io->version[2] = 0;
-    io->flags = flags;
-    if (name) {
-        strlcpy(io->name, name, sizeof(io->name));
-    }
-}
-
 namespace {
 
 struct CryptoType;
@@ -973,109 +958,12 @@
     master_key_ascii[a] = '\0';
 }
 
-static int load_crypto_mapping_table(struct crypt_mnt_ftr* crypt_ftr,
-                                     const unsigned char* master_key, const char* real_blk_name,
-                                     const char* name, int fd, const char* extra_params) {
-    alignas(struct dm_ioctl) char buffer[DM_CRYPT_BUF_SIZE];
-    struct dm_ioctl* io;
-    struct dm_target_spec* tgt;
-    char* crypt_params;
-    // We need two ASCII characters to represent each byte, and need space for
-    // the '\0' terminator.
-    char master_key_ascii[MAX_KEY_LEN * 2 + 1];
-    size_t buff_offset;
-    int i;
-
-    io = (struct dm_ioctl*)buffer;
-
-    /* Load the mapping table for this device */
-    tgt = (struct dm_target_spec*)&buffer[sizeof(struct dm_ioctl)];
-
-    ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
-    io->target_count = 1;
-    tgt->status = 0;
-    tgt->sector_start = 0;
-    tgt->length = crypt_ftr->fs_size;
-    strlcpy(tgt->target_type, "crypt", DM_MAX_TYPE_NAME);
-
-    crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
-    convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
-
-    buff_offset = crypt_params - buffer;
-    SLOGI(
-        "Creating crypto dev \"%s\"; cipher=%s, keysize=%u, real_dev=%s, len=%llu, params=\"%s\"\n",
-        name, crypt_ftr->crypto_type_name, crypt_ftr->keysize, real_blk_name, tgt->length * 512,
-        extra_params);
-    snprintf(crypt_params, sizeof(buffer) - buff_offset, "%s %s 0 %s 0 %s",
-             crypt_ftr->crypto_type_name, master_key_ascii, real_blk_name, extra_params);
-    crypt_params += strlen(crypt_params) + 1;
-    crypt_params =
-        (char*)(((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */
-    tgt->next = crypt_params - buffer;
-
-    for (i = 0; i < TABLE_LOAD_RETRIES; i++) {
-        if (!ioctl(fd, DM_TABLE_LOAD, io)) {
-            break;
-        }
-        usleep(500000);
-    }
-
-    if (i == TABLE_LOAD_RETRIES) {
-        /* We failed to load the table, return an error */
-        return -1;
-    } else {
-        return i + 1;
-    }
-}
-
-static int get_dm_crypt_version(int fd, const char* name, int* version) {
-    char buffer[DM_CRYPT_BUF_SIZE];
-    struct dm_ioctl* io;
-    struct dm_target_versions* v;
-
-    io = (struct dm_ioctl*)buffer;
-
-    ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
-
-    if (ioctl(fd, DM_LIST_VERSIONS, io)) {
-        return -1;
-    }
-
-    /* Iterate over the returned versions, looking for name of "crypt".
-     * When found, get and return the version.
-     */
-    v = (struct dm_target_versions*)&buffer[sizeof(struct dm_ioctl)];
-    while (v->next) {
-        if (!strcmp(v->name, "crypt")) {
-            /* We found the crypt driver, return the version, and get out */
-            version[0] = v->version[0];
-            version[1] = v->version[1];
-            version[2] = v->version[2];
-            return 0;
-        }
-        v = (struct dm_target_versions*)(((char*)v) + v->next);
-    }
-
-    return -1;
-}
-
-static std::string extra_params_as_string(const std::vector<std::string>& extra_params_vec) {
-    if (extra_params_vec.empty()) return "";
-    std::string extra_params = std::to_string(extra_params_vec.size());
-    for (const auto& p : extra_params_vec) {
-        extra_params.append(" ");
-        extra_params.append(p);
-    }
-    return extra_params;
-}
-
 /*
  * If the ro.crypto.fde_sector_size system property is set, append the
  * parameters to make dm-crypt use the specified crypto sector size and round
  * the crypto device size down to a crypto sector boundary.
  */
-static int add_sector_size_param(std::vector<std::string>* extra_params_vec,
-                                 struct crypt_mnt_ftr* ftr) {
+static int add_sector_size_param(DmTargetCrypt* target, struct crypt_mnt_ftr* ftr) {
     constexpr char DM_CRYPT_SECTOR_SIZE[] = "ro.crypto.fde_sector_size";
     char value[PROPERTY_VALUE_MAX];
 
@@ -1089,12 +977,11 @@
             return -1;
         }
 
-        std::string param = StringPrintf("sector_size:%u", sector_size);
-        extra_params_vec->push_back(std::move(param));
+        target->SetSectorSize(sector_size);
 
         // With this option, IVs will match the sector numbering, instead
         // of being hard-coded to being based on 512-byte sectors.
-        extra_params_vec->emplace_back("iv_large_sectors");
+        target->SetIvLargeSectors();
 
         // Round the crypto device size down to a crypto sector boundary.
         ftr->fs_size &= ~((sector_size / 512) - 1);
@@ -1105,112 +992,67 @@
 static int create_crypto_blk_dev(struct crypt_mnt_ftr* crypt_ftr, const unsigned char* master_key,
                                  const char* real_blk_name, char* crypto_blk_name, const char* name,
                                  uint32_t flags) {
-    char buffer[DM_CRYPT_BUF_SIZE];
-    struct dm_ioctl* io;
-    unsigned int minor;
-    int fd = 0;
-    int err;
-    int retval = -1;
-    int version[3];
-    int load_count;
-    std::vector<std::string> extra_params_vec;
+    auto& dm = DeviceMapper::Instance();
 
-    if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
-        SLOGE("Cannot open device-mapper\n");
-        goto errout;
-    }
+    // We need two ASCII characters to represent each byte, and need space for
+    // the '\0' terminator.
+    char master_key_ascii[MAX_KEY_LEN * 2 + 1];
+    convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
 
-    io = (struct dm_ioctl*)buffer;
+    auto target = std::make_unique<DmTargetCrypt>(0, crypt_ftr->fs_size,
+                                                  (const char*)crypt_ftr->crypto_type_name,
+                                                  master_key_ascii, 0, real_blk_name, 0);
+    target->AllowDiscards();
 
-    ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
-    err = ioctl(fd, DM_DEV_CREATE, io);
-    if (err) {
-        SLOGE("Cannot create dm-crypt device %s: %s\n", name, strerror(errno));
-        goto errout;
-    }
-
-    /* Get the device status, in particular, the name of it's device file */
-    ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
-    if (ioctl(fd, DM_DEV_STATUS, io)) {
-        SLOGE("Cannot retrieve dm-crypt device status\n");
-        goto errout;
-    }
-    minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
-    snprintf(crypto_blk_name, MAXPATHLEN, "/dev/block/dm-%u", minor);
-
-    if (!get_dm_crypt_version(fd, name, version)) {
-        /* Support for allow_discards was added in version 1.11.0 */
-        if ((version[0] >= 2) || ((version[0] == 1) && (version[1] >= 11))) {
-            extra_params_vec.emplace_back("allow_discards");
-        }
-    }
     if (flags & CREATE_CRYPTO_BLK_DEV_FLAGS_ALLOW_ENCRYPT_OVERRIDE) {
-        extra_params_vec.emplace_back("allow_encrypt_override");
+        target->AllowEncryptOverride();
     }
-    if (add_sector_size_param(&extra_params_vec, crypt_ftr)) {
+    if (add_sector_size_param(target.get(), crypt_ftr)) {
         SLOGE("Error processing dm-crypt sector size param\n");
-        goto errout;
+        return -1;
     }
-    load_count = load_crypto_mapping_table(crypt_ftr, master_key, real_blk_name, name, fd,
-                                           extra_params_as_string(extra_params_vec).c_str());
-    if (load_count < 0) {
+
+    DmTable table;
+    table.AddTarget(std::move(target));
+
+    int load_count = 1;
+    while (load_count < TABLE_LOAD_RETRIES) {
+        if (dm.CreateDevice(name, table)) {
+            break;
+        }
+        load_count++;
+    }
+
+    if (load_count >= TABLE_LOAD_RETRIES) {
         SLOGE("Cannot load dm-crypt mapping table.\n");
-        goto errout;
-    } else if (load_count > 1) {
+        return -1;
+    }
+    if (load_count > 1) {
         SLOGI("Took %d tries to load dmcrypt table.\n", load_count);
     }
 
-    /* Resume this device to activate it */
-    ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
-
-    if (ioctl(fd, DM_DEV_SUSPEND, io)) {
-        SLOGE("Cannot resume the dm-crypt device\n");
-        goto errout;
+    std::string path;
+    if (!dm.GetDmDevicePathByName(name, &path)) {
+        SLOGE("Cannot determine dm-crypt path for %s.\n", name);
+        return -1;
     }
+    snprintf(crypto_blk_name, MAXPATHLEN, "%s", path.c_str());
 
     /* Ensure the dm device has been created before returning. */
     if (android::vold::WaitForFile(crypto_blk_name, 1s) < 0) {
         // WaitForFile generates a suitable log message
-        goto errout;
+        return -1;
     }
-
-    /* We made it here with no errors.  Woot! */
-    retval = 0;
-
-errout:
-    close(fd); /* If fd is <0 from a failed open call, it's safe to just ignore the close error */
-
-    return retval;
+    return 0;
 }
 
-static int delete_crypto_blk_dev(const char* name) {
-    int fd;
-    char buffer[DM_CRYPT_BUF_SIZE];
-    struct dm_ioctl* io;
-    int retval = -1;
-    int err;
-
-    if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
-        SLOGE("Cannot open device-mapper\n");
-        goto errout;
+static int delete_crypto_blk_dev(const std::string& name) {
+    auto& dm = DeviceMapper::Instance();
+    if (!dm.DeleteDevice(name)) {
+        SLOGE("Cannot remove dm-crypt device %s: %s\n", name.c_str(), strerror(errno));
+        return -1;
     }
-
-    io = (struct dm_ioctl*)buffer;
-
-    ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
-    err = ioctl(fd, DM_DEV_REMOVE, io);
-    if (err) {
-        SLOGE("Cannot remove dm-crypt device %s: %s\n", name, strerror(errno));
-        goto errout;
-    }
-
-    /* We made it here with no errors.  Woot! */
-    retval = 0;
-
-errout:
-    close(fd); /* If fd is <0 from a failed open call, it's safe to just ignore the close error */
-
-    return retval;
+    return 0;
 }
 
 static int pbkdf2(const char* passwd, const unsigned char* salt, unsigned char* ikey,
@@ -1924,7 +1766,7 @@
  * storage volume.
  */
 int cryptfs_revert_ext_volume(const char* label) {
-    return delete_crypto_blk_dev((char*)label);
+    return delete_crypto_blk_dev(label);
 }
 
 int cryptfs_crypto_complete(void) {