diff options
author | Dan Williams <dan.j.williams@intel.com> | 2017-04-12 15:35:44 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2017-04-20 14:57:52 -0400 |
commit | f26c5719b2d7b00de69eb83eb1c1c831759fdc9b (patch) | |
tree | d2f4dc917d539e7dae0424d7722affdc1cdd2006 /drivers/md | |
parent | b0686260fecaa924d8eff2ace94bee70506bc308 (diff) |
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: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/Kconfig | 1 | ||||
-rw-r--r-- | drivers/md/dm-core.h | 1 | ||||
-rw-r--r-- | drivers/md/dm.c | 84 |
3 files changed, 72 insertions, 14 deletions
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index b7767da50c26..1de8372d9459 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig | |||
@@ -200,6 +200,7 @@ config BLK_DEV_DM_BUILTIN | |||
200 | config BLK_DEV_DM | 200 | config BLK_DEV_DM |
201 | tristate "Device mapper support" | 201 | tristate "Device mapper support" |
202 | select BLK_DEV_DM_BUILTIN | 202 | select BLK_DEV_DM_BUILTIN |
203 | select DAX | ||
203 | ---help--- | 204 | ---help--- |
204 | Device-mapper is a low level volume manager. It works by allowing | 205 | Device-mapper is a low level volume manager. It works by allowing |
205 | people to specify mappings for ranges of logical sectors. Various | 206 | people to specify mappings for ranges of logical sectors. Various |
diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index 136fda3ff9e5..538630190f66 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h | |||
@@ -58,6 +58,7 @@ struct mapped_device { | |||
58 | struct target_type *immutable_target_type; | 58 | struct target_type *immutable_target_type; |
59 | 59 | ||
60 | struct gendisk *disk; | 60 | struct gendisk *disk; |
61 | struct dax_device *dax_dev; | ||
61 | char name[16]; | 62 | char name[16]; |
62 | 63 | ||
63 | void *interface_ptr; | 64 | void *interface_ptr; |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index dfb75979e455..bd56dfe43a99 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/blkpg.h> | 16 | #include <linux/blkpg.h> |
17 | #include <linux/bio.h> | 17 | #include <linux/bio.h> |
18 | #include <linux/mempool.h> | 18 | #include <linux/mempool.h> |
19 | #include <linux/dax.h> | ||
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | #include <linux/idr.h> | 21 | #include <linux/idr.h> |
21 | #include <linux/hdreg.h> | 22 | #include <linux/hdreg.h> |
@@ -908,31 +909,68 @@ int dm_set_target_max_io_len(struct dm_target *ti, sector_t len) | |||
908 | } | 909 | } |
909 | EXPORT_SYMBOL_GPL(dm_set_target_max_io_len); | 910 | EXPORT_SYMBOL_GPL(dm_set_target_max_io_len); |
910 | 911 | ||
911 | static long dm_blk_direct_access(struct block_device *bdev, sector_t sector, | 912 | static struct dm_target *dm_dax_get_live_target(struct mapped_device *md, |
912 | void **kaddr, pfn_t *pfn, long size) | 913 | sector_t sector, int *srcu_idx) |
913 | { | 914 | { |
914 | struct mapped_device *md = bdev->bd_disk->private_data; | ||
915 | struct dm_table *map; | 915 | struct dm_table *map; |
916 | struct dm_target *ti; | 916 | struct dm_target *ti; |
917 | int srcu_idx; | ||
918 | long len, ret = -EIO; | ||
919 | 917 | ||
920 | map = dm_get_live_table(md, &srcu_idx); | 918 | map = dm_get_live_table(md, srcu_idx); |
921 | if (!map) | 919 | if (!map) |
922 | goto out; | 920 | return NULL; |
923 | 921 | ||
924 | ti = dm_table_find_target(map, sector); | 922 | ti = dm_table_find_target(map, sector); |
925 | if (!dm_target_is_valid(ti)) | 923 | if (!dm_target_is_valid(ti)) |
926 | goto out; | 924 | return NULL; |
927 | 925 | ||
928 | len = max_io_len(sector, ti) << SECTOR_SHIFT; | 926 | return ti; |
929 | size = min(len, size); | 927 | } |
930 | 928 | ||
931 | if (ti->type->direct_access) | 929 | static long dm_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, |
932 | ret = ti->type->direct_access(ti, sector, kaddr, pfn, size); | 930 | long nr_pages, void **kaddr, pfn_t *pfn) |
933 | out: | 931 | { |
932 | struct mapped_device *md = dax_get_private(dax_dev); | ||
933 | sector_t sector = pgoff * PAGE_SECTORS; | ||
934 | struct dm_target *ti; | ||
935 | long len, ret = -EIO; | ||
936 | int srcu_idx; | ||
937 | |||
938 | ti = dm_dax_get_live_target(md, sector, &srcu_idx); | ||
939 | |||
940 | if (!ti) | ||
941 | goto out; | ||
942 | if (!ti->type->direct_access) | ||
943 | goto out; | ||
944 | len = max_io_len(sector, ti) / PAGE_SECTORS; | ||
945 | if (len < 1) | ||
946 | goto out; | ||
947 | nr_pages = min(len, nr_pages); | ||
948 | if (ti->type->direct_access) { | ||
949 | ret = ti->type->direct_access(ti, sector, kaddr, pfn, | ||
950 | nr_pages * PAGE_SIZE); | ||
951 | /* | ||
952 | * FIXME: convert ti->type->direct_access to return | ||
953 | * nr_pages directly. | ||
954 | */ | ||
955 | if (ret >= 0) | ||
956 | ret /= PAGE_SIZE; | ||
957 | } | ||
958 | out: | ||
934 | dm_put_live_table(md, srcu_idx); | 959 | dm_put_live_table(md, srcu_idx); |
935 | return min(ret, size); | 960 | |
961 | return ret; | ||
962 | } | ||
963 | |||
964 | static long dm_blk_direct_access(struct block_device *bdev, sector_t sector, | ||
965 | void **kaddr, pfn_t *pfn, long size) | ||
966 | { | ||
967 | struct mapped_device *md = bdev->bd_disk->private_data; | ||
968 | struct dax_device *dax_dev = md->dax_dev; | ||
969 | long nr_pages = size / PAGE_SIZE; | ||
970 | |||
971 | nr_pages = dm_dax_direct_access(dax_dev, sector / PAGE_SECTORS, | ||
972 | nr_pages, kaddr, pfn); | ||
973 | return nr_pages < 0 ? nr_pages : nr_pages * PAGE_SIZE; | ||
936 | } | 974 | } |
937 | 975 | ||
938 | /* | 976 | /* |
@@ -1437,6 +1475,7 @@ static int next_free_minor(int *minor) | |||
1437 | } | 1475 | } |
1438 | 1476 | ||
1439 | static const struct block_device_operations dm_blk_dops; | 1477 | static const struct block_device_operations dm_blk_dops; |
1478 | static const struct dax_operations dm_dax_ops; | ||
1440 | 1479 | ||
1441 | static void dm_wq_work(struct work_struct *work); | 1480 | static void dm_wq_work(struct work_struct *work); |
1442 | 1481 | ||
@@ -1483,6 +1522,12 @@ static void cleanup_mapped_device(struct mapped_device *md) | |||
1483 | if (md->bs) | 1522 | if (md->bs) |
1484 | bioset_free(md->bs); | 1523 | bioset_free(md->bs); |
1485 | 1524 | ||
1525 | if (md->dax_dev) { | ||
1526 | kill_dax(md->dax_dev); | ||
1527 | put_dax(md->dax_dev); | ||
1528 | md->dax_dev = NULL; | ||
1529 | } | ||
1530 | |||
1486 | if (md->disk) { | 1531 | if (md->disk) { |
1487 | spin_lock(&_minor_lock); | 1532 | spin_lock(&_minor_lock); |
1488 | md->disk->private_data = NULL; | 1533 | md->disk->private_data = NULL; |
@@ -1510,6 +1555,7 @@ static void cleanup_mapped_device(struct mapped_device *md) | |||
1510 | static struct mapped_device *alloc_dev(int minor) | 1555 | static struct mapped_device *alloc_dev(int minor) |
1511 | { | 1556 | { |
1512 | int r, numa_node_id = dm_get_numa_node(); | 1557 | int r, numa_node_id = dm_get_numa_node(); |
1558 | struct dax_device *dax_dev; | ||
1513 | struct mapped_device *md; | 1559 | struct mapped_device *md; |
1514 | void *old_md; | 1560 | void *old_md; |
1515 | 1561 | ||
@@ -1574,6 +1620,12 @@ static struct mapped_device *alloc_dev(int minor) | |||
1574 | md->disk->queue = md->queue; | 1620 | md->disk->queue = md->queue; |
1575 | md->disk->private_data = md; | 1621 | md->disk->private_data = md; |
1576 | sprintf(md->disk->disk_name, "dm-%d", minor); | 1622 | sprintf(md->disk->disk_name, "dm-%d", minor); |
1623 | |||
1624 | dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops); | ||
1625 | if (!dax_dev) | ||
1626 | goto bad; | ||
1627 | md->dax_dev = dax_dev; | ||
1628 | |||
1577 | add_disk(md->disk); | 1629 | add_disk(md->disk); |
1578 | format_dev_t(md->name, MKDEV(_major, minor)); | 1630 | format_dev_t(md->name, MKDEV(_major, minor)); |
1579 | 1631 | ||
@@ -2781,6 +2833,10 @@ static const struct block_device_operations dm_blk_dops = { | |||
2781 | .owner = THIS_MODULE | 2833 | .owner = THIS_MODULE |
2782 | }; | 2834 | }; |
2783 | 2835 | ||
2836 | static const struct dax_operations dm_dax_ops = { | ||
2837 | .direct_access = dm_dax_direct_access, | ||
2838 | }; | ||
2839 | |||
2784 | /* | 2840 | /* |
2785 | * module hooks | 2841 | * module hooks |
2786 | */ | 2842 | */ |