Arrange for dm to lookup the dax services available from member
devices. Update the dax-capable targets, linear and stripe, to route dax
operations to the underlying device.

Signed-off-by: Dan Williams <dan.j.willi...@intel.com>
---
 drivers/md/dm-linear.c        |   24 ++++++++++++++++++++++++
 drivers/md/dm-snap.c          |   12 ++++++++++++
 drivers/md/dm-stripe.c        |   30 ++++++++++++++++++++++++++++++
 drivers/md/dm-target.c        |   11 +++++++++++
 drivers/md/dm.c               |   16 ++++++++++++----
 include/linux/device-mapper.h |    7 +++++++
 6 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 4788b0b989a9..e91ca8089333 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -159,6 +159,29 @@ static long linear_direct_access(struct dm_target *ti, 
sector_t sector,
        return ret;
 }
 
+static long linear_dax_direct_access(struct dm_target *ti, phys_addr_t 
dev_addr,
+                                    void **kaddr, pfn_t *pfn, long size)
+{
+       struct linear_c *lc = ti->private;
+       struct block_device *bdev = lc->dev->bdev;
+       struct dax_inode *dax_inode = lc->dev->dax_inode;
+       struct blk_dax_ctl dax = {
+               .sector = linear_map_sector(ti, dev_addr >> SECTOR_SHIFT),
+               .size = size,
+       };
+       long ret;
+
+       ret = bdev_dax_direct_access(bdev, dax_inode, &dax);
+       *kaddr = dax.addr;
+       *pfn = dax.pfn;
+
+       return ret;
+}
+
+static const struct dm_dax_operations linear_dax_ops = {
+       .dm_direct_access = linear_dax_direct_access,
+};
+
 static struct target_type linear_target = {
        .name   = "linear",
        .version = {1, 3, 0},
@@ -170,6 +193,7 @@ static struct target_type linear_target = {
        .prepare_ioctl = linear_prepare_ioctl,
        .iterate_devices = linear_iterate_devices,
        .direct_access = linear_direct_access,
+       .dax_ops = &linear_dax_ops,
 };
 
 int __init dm_linear_init(void)
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index c65feeada864..1990e3bd6958 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -2309,6 +2309,13 @@ static long origin_direct_access(struct dm_target *ti, 
sector_t sector,
        return -EIO;
 }
 
+static long origin_dax_direct_access(struct dm_target *ti, phys_addr_t 
dev_addr,
+               void **kaddr, pfn_t *pfn, long size)
+{
+       DMWARN("device does not support dax.");
+       return -EIO;
+}
+
 /*
  * Set the target "max_io_len" field to the minimum of all the snapshots'
  * chunk sizes.
@@ -2357,6 +2364,10 @@ static int origin_iterate_devices(struct dm_target *ti,
        return fn(ti, o->dev, 0, ti->len, data);
 }
 
+static const struct dm_dax_operations origin_dax_ops = {
+       .dm_direct_access = origin_dax_direct_access,
+};
+
 static struct target_type origin_target = {
        .name    = "snapshot-origin",
        .version = {1, 9, 0},
@@ -2369,6 +2380,7 @@ static struct target_type origin_target = {
        .status  = origin_status,
        .iterate_devices = origin_iterate_devices,
        .direct_access = origin_direct_access,
+       .dax_ops = &origin_dax_ops,
 };
 
 static struct target_type snapshot_target = {
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 28193a57bf47..47fb56a6184a 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -331,6 +331,31 @@ static long stripe_direct_access(struct dm_target *ti, 
sector_t sector,
        return ret;
 }
 
+static long stripe_dax_direct_access(struct dm_target *ti, phys_addr_t 
dev_addr,
+               void **kaddr, pfn_t *pfn, long size)
+{
+       struct stripe_c *sc = ti->private;
+       uint32_t stripe;
+       struct block_device *bdev;
+       struct dax_inode *dax_inode;
+       struct blk_dax_ctl dax = {
+               .size = size,
+       };
+       long ret;
+
+       stripe_map_sector(sc, dev_addr >> SECTOR_SHIFT, &stripe, &dax.sector);
+
+       dax.sector += sc->stripe[stripe].physical_start;
+       bdev = sc->stripe[stripe].dev->bdev;
+       dax_inode = sc->stripe[stripe].dev->dax_inode;
+
+       ret = bdev_dax_direct_access(bdev, dax_inode, &dax);
+       *kaddr = dax.addr;
+       *pfn = dax.pfn;
+
+       return ret;
+}
+
 /*
  * Stripe status:
  *
@@ -437,6 +462,10 @@ static void stripe_io_hints(struct dm_target *ti,
        blk_limits_io_opt(limits, chunk_size * sc->stripes);
 }
 
+static const struct dm_dax_operations stripe_dax_ops = {
+       .dm_direct_access = stripe_dax_direct_access,
+};
+
 static struct target_type stripe_target = {
        .name   = "striped",
        .version = {1, 6, 0},
@@ -449,6 +478,7 @@ static struct target_type stripe_target = {
        .iterate_devices = stripe_iterate_devices,
        .io_hints = stripe_io_hints,
        .direct_access = stripe_direct_access,
+       .dax_ops = &stripe_dax_ops,
 };
 
 int __init dm_stripe_init(void)
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c
index 710ae28fd618..ab072f53cf24 100644
--- a/drivers/md/dm-target.c
+++ b/drivers/md/dm-target.c
@@ -154,6 +154,16 @@ static long io_err_direct_access(struct dm_target *ti, 
sector_t sector,
        return -EIO;
 }
 
+static long io_err_dax_direct_access(struct dm_target *ti, phys_addr_t 
dev_addr,
+                                    void **kaddr, pfn_t *pfn, long size)
+{
+       return -EIO;
+}
+
+static const struct dm_dax_operations err_dax_ops = {
+       .dm_direct_access = io_err_dax_direct_access,
+};
+
 static struct target_type error_target = {
        .name = "error",
        .version = {1, 5, 0},
@@ -165,6 +175,7 @@ static struct target_type error_target = {
        .clone_and_map_rq = io_err_clone_and_map_rq,
        .release_clone_rq = io_err_release_clone_rq,
        .direct_access = io_err_direct_access,
+       .dax_ops = &err_dax_ops,
 };
 
 int __init dm_target_init(void)
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 1b3d9253e92c..5c5eeda0eb0a 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -627,6 +627,7 @@ static int open_table_device(struct table_device *td, dev_t 
dev,
        }
 
        td->dm_dev.bdev = bdev;
+       td->dm_dev.dax_inode = dax_get_by_host(bdev->bd_disk->disk_name);
        return 0;
 }
 
@@ -640,7 +641,9 @@ static void close_table_device(struct table_device *td, 
struct mapped_device *md
 
        bd_unlink_disk_holder(td->dm_dev.bdev, dm_disk(md));
        blkdev_put(td->dm_dev.bdev, td->dm_dev.mode | FMODE_EXCL);
+       put_dax_inode(td->dm_dev.dax_inode);
        td->dm_dev.bdev = NULL;
+       td->dm_dev.dax_inode = NULL;
 }
 
 static struct table_device *find_table_device(struct list_head *l, dev_t dev,
@@ -907,7 +910,7 @@ 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_direct_access(struct mapped_device *md, phys_addr_t dev_addr,
-                              void **kaddr, pfn_t *pfn, long size)
+                              void **kaddr, pfn_t *pfn, long size, bool blk)
 {
        sector_t sector = dev_addr >> SECTOR_SHIFT;
        struct dm_table *map;
@@ -926,8 +929,11 @@ static long __dm_direct_access(struct mapped_device *md, 
phys_addr_t dev_addr,
        len = max_io_len(sector, ti) << SECTOR_SHIFT;
        size = min(len, size);
 
-       if (ti->type->direct_access)
+       if (blk && ti->type->direct_access)
                ret = ti->type->direct_access(ti, sector, kaddr, pfn, size);
+       else if (ti->type->dax_ops)
+               ret = ti->type->dax_ops->dm_direct_access(ti, dev_addr, kaddr,
+                               pfn, size);
 out:
        dm_put_live_table(md, srcu_idx);
        return min(ret, size);
@@ -938,7 +944,8 @@ static long dm_blk_direct_access(struct block_device *bdev, 
sector_t sector,
 {
        struct mapped_device *md = bdev->bd_disk->private_data;
 
-       return __dm_direct_access(md, sector << SECTOR_SHIFT, kaddr, pfn, size);
+       return __dm_direct_access(md, sector << SECTOR_SHIFT, kaddr, pfn, size,
+                       true);
 }
 
 static long dm_dax_direct_access(struct dax_inode *dax_inode,
@@ -947,7 +954,8 @@ static long dm_dax_direct_access(struct dax_inode 
*dax_inode,
 {
        struct mapped_device *md = dax_inode_get_private(dax_inode);
 
-       return __dm_direct_access(md, dev_addr, kaddr, pfn, size);
+       return __dm_direct_access(md, dev_addr, kaddr, pfn, size,
+                       false);
 }
 
 /*
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index ef7962e84444..1b64f412bb45 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -137,12 +137,18 @@ void dm_error(const char *message);
 
 struct dm_dev {
        struct block_device *bdev;
+       struct dax_inode *dax_inode;
        fmode_t mode;
        char name[16];
 };
 
 dev_t dm_get_dev_t(const char *path);
 
+struct dm_dax_operations {
+       long (*dm_direct_access)(struct dm_target *ti, phys_addr_t dev_addr,
+                       void **kaddr, pfn_t *pfn, long size);
+};
+
 /*
  * Constructors should call these functions to ensure destination devices
  * are opened/closed correctly.
@@ -180,6 +186,7 @@ struct target_type {
        dm_iterate_devices_fn iterate_devices;
        dm_io_hints_fn io_hints;
        dm_direct_access_fn direct_access;
+       const struct dm_dax_operations *dax_ops;
 
        /* For internal device-mapper use. */
        struct list_head list;

--
To unsubscribe from this list: send the line "unsubscribe linux-block" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to