dm: add dax_device and dax_operations support
authorDan Williams <dan.j.williams@intel.com>
Wed, 12 Apr 2017 19:35:44 +0000 (12:35 -0700)
committerDan Williams <dan.j.williams@intel.com>
Thu, 20 Apr 2017 18:57:52 +0000 (11:57 -0700)
Allocate a dax_device to represent the capacity of a device-mapper
instance. Provide a ->direct_access() method via the new dax_operations
indirection that mirrors the functionality of the current direct_access
support via block_device_operations.  Once fs/dax.c has been converted
to use dax_operations the old dm_blk_direct_access() will be removed.

A new helper dm_dax_get_live_target() is introduced to separate some of
the dm-specifics from the direct_access implementation.

This enabling is only for the top-level dm representation to upper
layers. Converting target direct_access implementations is deferred to a
separate patch.

Cc: Toshi Kani <toshi.kani@hpe.com>
Reviewed-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/md/Kconfig
drivers/md/dm-core.h
drivers/md/dm.c
include/linux/device-mapper.h

index b7767da50c268c388f7ad01f292d6e082ccc1219..1de8372d9459a6a6ba08cfdcbd0955ce664767d7 100644 (file)
@@ -200,6 +200,7 @@ config BLK_DEV_DM_BUILTIN
 config BLK_DEV_DM
        tristate "Device mapper support"
        select BLK_DEV_DM_BUILTIN
+       select DAX
        ---help---
          Device-mapper is a low level volume manager.  It works by allowing
          people to specify mappings for ranges of logical sectors.  Various
index 136fda3ff9e55d46a2ef686e8655ba50754d5c20..538630190f66246084305f329d62918e319aa7ba 100644 (file)
@@ -58,6 +58,7 @@ struct mapped_device {
        struct target_type *immutable_target_type;
 
        struct gendisk *disk;
+       struct dax_device *dax_dev;
        char name[16];
 
        void *interface_ptr;
index dfb75979e4555d806ea52a494e161d4c6f8fa86b..bd56dfe43a992815c80409b19b34e75cc424ad92 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/blkpg.h>
 #include <linux/bio.h>
 #include <linux/mempool.h>
+#include <linux/dax.h>
 #include <linux/slab.h>
 #include <linux/idr.h>
 #include <linux/hdreg.h>
@@ -908,31 +909,68 @@ int dm_set_target_max_io_len(struct dm_target *ti, sector_t len)
 }
 EXPORT_SYMBOL_GPL(dm_set_target_max_io_len);
 
-static long dm_blk_direct_access(struct block_device *bdev, sector_t sector,
-                                void **kaddr, pfn_t *pfn, long size)
+static struct dm_target *dm_dax_get_live_target(struct mapped_device *md,
+               sector_t sector, int *srcu_idx)
 {
-       struct mapped_device *md = bdev->bd_disk->private_data;
        struct dm_table *map;
        struct dm_target *ti;
-       int srcu_idx;
-       long len, ret = -EIO;
 
-       map = dm_get_live_table(md, &srcu_idx);
+       map = dm_get_live_table(md, srcu_idx);
        if (!map)
-               goto out;
+               return NULL;
 
        ti = dm_table_find_target(map, sector);
        if (!dm_target_is_valid(ti))
-               goto out;
+               return NULL;
 
-       len = max_io_len(sector, ti) << SECTOR_SHIFT;
-       size = min(len, size);
+       return ti;
+}
 
-       if (ti->type->direct_access)
-               ret = ti->type->direct_access(ti, sector, kaddr, pfn, size);
-out:
+static long dm_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff,
+               long nr_pages, void **kaddr, pfn_t *pfn)
+{
+       struct mapped_device *md = dax_get_private(dax_dev);
+       sector_t sector = pgoff * PAGE_SECTORS;
+       struct dm_target *ti;
+       long len, ret = -EIO;
+       int srcu_idx;
+
+       ti = dm_dax_get_live_target(md, sector, &srcu_idx);
+
+       if (!ti)
+               goto out;
+       if (!ti->type->direct_access)
+               goto out;
+       len = max_io_len(sector, ti) / PAGE_SECTORS;
+       if (len < 1)
+               goto out;
+       nr_pages = min(len, nr_pages);
+       if (ti->type->direct_access) {
+               ret = ti->type->direct_access(ti, sector, kaddr, pfn,
+                               nr_pages * PAGE_SIZE);
+               /*
+                * FIXME: convert ti->type->direct_access to return
+                * nr_pages directly.
+                */
+               if (ret >= 0)
+                       ret /= PAGE_SIZE;
+       }
+ out:
        dm_put_live_table(md, srcu_idx);
-       return min(ret, size);
+
+       return ret;
+}
+
+static long dm_blk_direct_access(struct block_device *bdev, sector_t sector,
+               void **kaddr, pfn_t *pfn, long size)
+{
+       struct mapped_device *md = bdev->bd_disk->private_data;
+       struct dax_device *dax_dev = md->dax_dev;
+       long nr_pages = size / PAGE_SIZE;
+
+       nr_pages = dm_dax_direct_access(dax_dev, sector / PAGE_SECTORS,
+                       nr_pages, kaddr, pfn);
+       return nr_pages < 0 ? nr_pages : nr_pages * PAGE_SIZE;
 }
 
 /*
@@ -1437,6 +1475,7 @@ static int next_free_minor(int *minor)
 }
 
 static const struct block_device_operations dm_blk_dops;
+static const struct dax_operations dm_dax_ops;
 
 static void dm_wq_work(struct work_struct *work);
 
@@ -1483,6 +1522,12 @@ static void cleanup_mapped_device(struct mapped_device *md)
        if (md->bs)
                bioset_free(md->bs);
 
+       if (md->dax_dev) {
+               kill_dax(md->dax_dev);
+               put_dax(md->dax_dev);
+               md->dax_dev = NULL;
+       }
+
        if (md->disk) {
                spin_lock(&_minor_lock);
                md->disk->private_data = NULL;
@@ -1510,6 +1555,7 @@ static void cleanup_mapped_device(struct mapped_device *md)
 static struct mapped_device *alloc_dev(int minor)
 {
        int r, numa_node_id = dm_get_numa_node();
+       struct dax_device *dax_dev;
        struct mapped_device *md;
        void *old_md;
 
@@ -1574,6 +1620,12 @@ static struct mapped_device *alloc_dev(int minor)
        md->disk->queue = md->queue;
        md->disk->private_data = md;
        sprintf(md->disk->disk_name, "dm-%d", minor);
+
+       dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops);
+       if (!dax_dev)
+               goto bad;
+       md->dax_dev = dax_dev;
+
        add_disk(md->disk);
        format_dev_t(md->name, MKDEV(_major, minor));
 
@@ -2781,6 +2833,10 @@ static const struct block_device_operations dm_blk_dops = {
        .owner = THIS_MODULE
 };
 
+static const struct dax_operations dm_dax_ops = {
+       .direct_access = dm_dax_direct_access,
+};
+
 /*
  * module hooks
  */
index a7e6903866fdc98689bb5189cffd4b8cb7a715fa..bcba4d89089cfbc73764a29e0a4128c49bdc950f 100644 (file)
@@ -130,6 +130,7 @@ typedef int (*dm_busy_fn) (struct dm_target *ti);
  */
 typedef long (*dm_direct_access_fn) (struct dm_target *ti, sector_t sector,
                                     void **kaddr, pfn_t *pfn, long size);
+#define PAGE_SECTORS (PAGE_SIZE / 512)
 
 void dm_error(const char *message);