Commit f26c5719 authored by Dan Williams's avatar Dan Williams

dm: add dax_device and dax_operations support

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: default avatarMike Snitzer <snitzer@redhat.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent b0686260
...@@ -200,6 +200,7 @@ config BLK_DEV_DM_BUILTIN ...@@ -200,6 +200,7 @@ config BLK_DEV_DM_BUILTIN
config BLK_DEV_DM config BLK_DEV_DM
tristate "Device mapper support" tristate "Device mapper support"
select BLK_DEV_DM_BUILTIN select BLK_DEV_DM_BUILTIN
select DAX
---help--- ---help---
Device-mapper is a low level volume manager. It works by allowing Device-mapper is a low level volume manager. It works by allowing
people to specify mappings for ranges of logical sectors. Various people to specify mappings for ranges of logical sectors. Various
......
...@@ -58,6 +58,7 @@ struct mapped_device { ...@@ -58,6 +58,7 @@ struct mapped_device {
struct target_type *immutable_target_type; struct target_type *immutable_target_type;
struct gendisk *disk; struct gendisk *disk;
struct dax_device *dax_dev;
char name[16]; char name[16];
void *interface_ptr; void *interface_ptr;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/blkpg.h> #include <linux/blkpg.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/mempool.h> #include <linux/mempool.h>
#include <linux/dax.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
...@@ -908,31 +909,68 @@ int dm_set_target_max_io_len(struct dm_target *ti, sector_t len) ...@@ -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); EXPORT_SYMBOL_GPL(dm_set_target_max_io_len);
static long dm_blk_direct_access(struct block_device *bdev, sector_t sector, static struct dm_target *dm_dax_get_live_target(struct mapped_device *md,
void **kaddr, pfn_t *pfn, long size) sector_t sector, int *srcu_idx)
{ {
struct mapped_device *md = bdev->bd_disk->private_data;
struct dm_table *map; struct dm_table *map;
struct dm_target *ti; 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) if (!map)
goto out; return NULL;
ti = dm_table_find_target(map, sector); ti = dm_table_find_target(map, sector);
if (!dm_target_is_valid(ti)) if (!dm_target_is_valid(ti))
goto out; return NULL;
len = max_io_len(sector, ti) << SECTOR_SHIFT; return ti;
size = min(len, size); }
if (ti->type->direct_access) static long dm_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff,
ret = ti->type->direct_access(ti, sector, kaddr, pfn, size); long nr_pages, void **kaddr, pfn_t *pfn)
out: {
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); 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) ...@@ -1437,6 +1475,7 @@ static int next_free_minor(int *minor)
} }
static const struct block_device_operations dm_blk_dops; 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); static void dm_wq_work(struct work_struct *work);
...@@ -1483,6 +1522,12 @@ static void cleanup_mapped_device(struct mapped_device *md) ...@@ -1483,6 +1522,12 @@ static void cleanup_mapped_device(struct mapped_device *md)
if (md->bs) if (md->bs)
bioset_free(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) { if (md->disk) {
spin_lock(&_minor_lock); spin_lock(&_minor_lock);
md->disk->private_data = NULL; md->disk->private_data = NULL;
...@@ -1510,6 +1555,7 @@ static void cleanup_mapped_device(struct mapped_device *md) ...@@ -1510,6 +1555,7 @@ static void cleanup_mapped_device(struct mapped_device *md)
static struct mapped_device *alloc_dev(int minor) static struct mapped_device *alloc_dev(int minor)
{ {
int r, numa_node_id = dm_get_numa_node(); int r, numa_node_id = dm_get_numa_node();
struct dax_device *dax_dev;
struct mapped_device *md; struct mapped_device *md;
void *old_md; void *old_md;
...@@ -1574,6 +1620,12 @@ static struct mapped_device *alloc_dev(int minor) ...@@ -1574,6 +1620,12 @@ static struct mapped_device *alloc_dev(int minor)
md->disk->queue = md->queue; md->disk->queue = md->queue;
md->disk->private_data = md; md->disk->private_data = md;
sprintf(md->disk->disk_name, "dm-%d", minor); 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); add_disk(md->disk);
format_dev_t(md->name, MKDEV(_major, minor)); format_dev_t(md->name, MKDEV(_major, minor));
...@@ -2781,6 +2833,10 @@ static const struct block_device_operations dm_blk_dops = { ...@@ -2781,6 +2833,10 @@ static const struct block_device_operations dm_blk_dops = {
.owner = THIS_MODULE .owner = THIS_MODULE
}; };
static const struct dax_operations dm_dax_ops = {
.direct_access = dm_dax_direct_access,
};
/* /*
* module hooks * module hooks
*/ */
......
...@@ -130,6 +130,7 @@ typedef int (*dm_busy_fn) (struct dm_target *ti); ...@@ -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, typedef long (*dm_direct_access_fn) (struct dm_target *ti, sector_t sector,
void **kaddr, pfn_t *pfn, long size); void **kaddr, pfn_t *pfn, long size);
#define PAGE_SECTORS (PAGE_SIZE / 512)
void dm_error(const char *message); void dm_error(const char *message);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment