summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-18 13:52:08 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-18 13:52:08 -0400
commitf8c3500cd137867927bc080f4a6e02e0222dd1b8 (patch)
tree4bbcdedca12ec9d4db6f48f37052c983abc387b4
parentd77e9e4e18ce9da3b4981a5c537979c42b06638c (diff)
parent8c2e408e73f735d2e6e8b43f9b038c9abb082939 (diff)
Merge tag 'libnvdimm-for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm updates from Dan Williams: "Primarily just the virtio_pmem driver: - virtio_pmem The new virtio_pmem facility introduces a paravirtualized persistent memory device that allows a guest VM to use DAX mechanisms to access a host-file with host-page-cache. It arranges for MAP_SYNC to be disabled and instead triggers a host fsync() when a 'write-cache flush' command is sent to the virtual disk device. - Miscellaneous small fixups" * tag 'libnvdimm-for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: virtio_pmem: fix sparse warning xfs: disable map_sync for async flush ext4: disable map_sync for async flush dax: check synchronous mapping is supported dm: enable synchronous dax libnvdimm: add dax_dev sync flag virtio-pmem: Add virtio pmem driver libnvdimm: nd_region flush callback support libnvdimm, namespace: Drop uuid_t implementation detail
-rw-r--r--drivers/acpi/nfit/core.c4
-rw-r--r--drivers/dax/bus.c2
-rw-r--r--drivers/dax/super.c19
-rw-r--r--drivers/md/dm-table.c24
-rw-r--r--drivers/md/dm.c5
-rw-r--r--drivers/md/dm.h5
-rw-r--r--drivers/nvdimm/Makefile1
-rw-r--r--drivers/nvdimm/claim.c6
-rw-r--r--drivers/nvdimm/namespace_devs.c8
-rw-r--r--drivers/nvdimm/nd.h1
-rw-r--r--drivers/nvdimm/nd_virtio.c125
-rw-r--r--drivers/nvdimm/pmem.c18
-rw-r--r--drivers/nvdimm/region_devs.c33
-rw-r--r--drivers/nvdimm/virtio_pmem.c122
-rw-r--r--drivers/nvdimm/virtio_pmem.h55
-rw-r--r--drivers/s390/block/dcssblk.c2
-rw-r--r--drivers/virtio/Kconfig11
-rw-r--r--fs/ext4/file.c10
-rw-r--r--fs/xfs/xfs_file.c9
-rw-r--r--include/linux/dax.h41
-rw-r--r--include/linux/libnvdimm.h10
-rw-r--r--include/uapi/linux/virtio_ids.h1
-rw-r--r--include/uapi/linux/virtio_pmem.h34
23 files changed, 508 insertions, 38 deletions
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 23022cf20d26..c02fa27dd3f3 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -2426,7 +2426,7 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
2426 offset = to_interleave_offset(offset, mmio); 2426 offset = to_interleave_offset(offset, mmio);
2427 2427
2428 writeq(cmd, mmio->addr.base + offset); 2428 writeq(cmd, mmio->addr.base + offset);
2429 nvdimm_flush(nfit_blk->nd_region); 2429 nvdimm_flush(nfit_blk->nd_region, NULL);
2430 2430
2431 if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH) 2431 if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH)
2432 readq(mmio->addr.base + offset); 2432 readq(mmio->addr.base + offset);
@@ -2475,7 +2475,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
2475 } 2475 }
2476 2476
2477 if (rw) 2477 if (rw)
2478 nvdimm_flush(nfit_blk->nd_region); 2478 nvdimm_flush(nfit_blk->nd_region, NULL);
2479 2479
2480 rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0; 2480 rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0;
2481 return rc; 2481 return rc;
diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c
index 2109cfe80219..5f184e751c82 100644
--- a/drivers/dax/bus.c
+++ b/drivers/dax/bus.c
@@ -388,7 +388,7 @@ struct dev_dax *__devm_create_dev_dax(struct dax_region *dax_region, int id,
388 * No 'host' or dax_operations since there is no access to this 388 * No 'host' or dax_operations since there is no access to this
389 * device outside of mmap of the resulting character device. 389 * device outside of mmap of the resulting character device.
390 */ 390 */
391 dax_dev = alloc_dax(dev_dax, NULL, NULL); 391 dax_dev = alloc_dax(dev_dax, NULL, NULL, DAXDEV_F_SYNC);
392 if (!dax_dev) 392 if (!dax_dev)
393 goto err; 393 goto err;
394 394
diff --git a/drivers/dax/super.c b/drivers/dax/super.c
index 4e5ae7e8b557..8ab12068eea3 100644
--- a/drivers/dax/super.c
+++ b/drivers/dax/super.c
@@ -195,6 +195,8 @@ enum dax_device_flags {
195 DAXDEV_ALIVE, 195 DAXDEV_ALIVE,
196 /* gate whether dax_flush() calls the low level flush routine */ 196 /* gate whether dax_flush() calls the low level flush routine */
197 DAXDEV_WRITE_CACHE, 197 DAXDEV_WRITE_CACHE,
198 /* flag to check if device supports synchronous flush */
199 DAXDEV_SYNC,
198}; 200};
199 201
200/** 202/**
@@ -372,6 +374,18 @@ bool dax_write_cache_enabled(struct dax_device *dax_dev)
372} 374}
373EXPORT_SYMBOL_GPL(dax_write_cache_enabled); 375EXPORT_SYMBOL_GPL(dax_write_cache_enabled);
374 376
377bool __dax_synchronous(struct dax_device *dax_dev)
378{
379 return test_bit(DAXDEV_SYNC, &dax_dev->flags);
380}
381EXPORT_SYMBOL_GPL(__dax_synchronous);
382
383void __set_dax_synchronous(struct dax_device *dax_dev)
384{
385 set_bit(DAXDEV_SYNC, &dax_dev->flags);
386}
387EXPORT_SYMBOL_GPL(__set_dax_synchronous);
388
375bool dax_alive(struct dax_device *dax_dev) 389bool dax_alive(struct dax_device *dax_dev)
376{ 390{
377 lockdep_assert_held(&dax_srcu); 391 lockdep_assert_held(&dax_srcu);
@@ -526,7 +540,7 @@ static void dax_add_host(struct dax_device *dax_dev, const char *host)
526} 540}
527 541
528struct dax_device *alloc_dax(void *private, const char *__host, 542struct dax_device *alloc_dax(void *private, const char *__host,
529 const struct dax_operations *ops) 543 const struct dax_operations *ops, unsigned long flags)
530{ 544{
531 struct dax_device *dax_dev; 545 struct dax_device *dax_dev;
532 const char *host; 546 const char *host;
@@ -549,6 +563,9 @@ struct dax_device *alloc_dax(void *private, const char *__host,
549 dax_add_host(dax_dev, host); 563 dax_add_host(dax_dev, host);
550 dax_dev->ops = ops; 564 dax_dev->ops = ops;
551 dax_dev->private = private; 565 dax_dev->private = private;
566 if (flags & DAXDEV_F_SYNC)
567 set_dax_synchronous(dax_dev);
568
552 return dax_dev; 569 return dax_dev;
553 570
554 err_dev: 571 err_dev:
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index ec8b27e20de3..caaee8032afe 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -881,7 +881,7 @@ void dm_table_set_type(struct dm_table *t, enum dm_queue_mode type)
881EXPORT_SYMBOL_GPL(dm_table_set_type); 881EXPORT_SYMBOL_GPL(dm_table_set_type);
882 882
883/* validate the dax capability of the target device span */ 883/* validate the dax capability of the target device span */
884static int device_supports_dax(struct dm_target *ti, struct dm_dev *dev, 884int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
885 sector_t start, sector_t len, void *data) 885 sector_t start, sector_t len, void *data)
886{ 886{
887 int blocksize = *(int *) data; 887 int blocksize = *(int *) data;
@@ -890,7 +890,15 @@ static int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
890 start, len); 890 start, len);
891} 891}
892 892
893bool dm_table_supports_dax(struct dm_table *t, int blocksize) 893/* Check devices support synchronous DAX */
894static int device_synchronous(struct dm_target *ti, struct dm_dev *dev,
895 sector_t start, sector_t len, void *data)
896{
897 return dax_synchronous(dev->dax_dev);
898}
899
900bool dm_table_supports_dax(struct dm_table *t,
901 iterate_devices_callout_fn iterate_fn, int *blocksize)
894{ 902{
895 struct dm_target *ti; 903 struct dm_target *ti;
896 unsigned i; 904 unsigned i;
@@ -903,8 +911,7 @@ bool dm_table_supports_dax(struct dm_table *t, int blocksize)
903 return false; 911 return false;
904 912
905 if (!ti->type->iterate_devices || 913 if (!ti->type->iterate_devices ||
906 !ti->type->iterate_devices(ti, device_supports_dax, 914 !ti->type->iterate_devices(ti, iterate_fn, blocksize))
907 &blocksize))
908 return false; 915 return false;
909 } 916 }
910 917
@@ -940,6 +947,7 @@ static int dm_table_determine_type(struct dm_table *t)
940 struct dm_target *tgt; 947 struct dm_target *tgt;
941 struct list_head *devices = dm_table_get_devices(t); 948 struct list_head *devices = dm_table_get_devices(t);
942 enum dm_queue_mode live_md_type = dm_get_md_type(t->md); 949 enum dm_queue_mode live_md_type = dm_get_md_type(t->md);
950 int page_size = PAGE_SIZE;
943 951
944 if (t->type != DM_TYPE_NONE) { 952 if (t->type != DM_TYPE_NONE) {
945 /* target already set the table's type */ 953 /* target already set the table's type */
@@ -984,7 +992,7 @@ static int dm_table_determine_type(struct dm_table *t)
984verify_bio_based: 992verify_bio_based:
985 /* We must use this table as bio-based */ 993 /* We must use this table as bio-based */
986 t->type = DM_TYPE_BIO_BASED; 994 t->type = DM_TYPE_BIO_BASED;
987 if (dm_table_supports_dax(t, PAGE_SIZE) || 995 if (dm_table_supports_dax(t, device_supports_dax, &page_size) ||
988 (list_empty(devices) && live_md_type == DM_TYPE_DAX_BIO_BASED)) { 996 (list_empty(devices) && live_md_type == DM_TYPE_DAX_BIO_BASED)) {
989 t->type = DM_TYPE_DAX_BIO_BASED; 997 t->type = DM_TYPE_DAX_BIO_BASED;
990 } else { 998 } else {
@@ -1883,6 +1891,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
1883 struct queue_limits *limits) 1891 struct queue_limits *limits)
1884{ 1892{
1885 bool wc = false, fua = false; 1893 bool wc = false, fua = false;
1894 int page_size = PAGE_SIZE;
1886 1895
1887 /* 1896 /*
1888 * Copy table's limits to the DM device's request_queue 1897 * Copy table's limits to the DM device's request_queue
@@ -1910,8 +1919,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
1910 } 1919 }
1911 blk_queue_write_cache(q, wc, fua); 1920 blk_queue_write_cache(q, wc, fua);
1912 1921
1913 if (dm_table_supports_dax(t, PAGE_SIZE)) 1922 if (dm_table_supports_dax(t, device_supports_dax, &page_size)) {
1914 blk_queue_flag_set(QUEUE_FLAG_DAX, q); 1923 blk_queue_flag_set(QUEUE_FLAG_DAX, q);
1924 if (dm_table_supports_dax(t, device_synchronous, NULL))
1925 set_dax_synchronous(t->md->dax_dev);
1926 }
1915 else 1927 else
1916 blk_queue_flag_clear(QUEUE_FLAG_DAX, q); 1928 blk_queue_flag_clear(QUEUE_FLAG_DAX, q);
1917 1929
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 61f1152b74e9..d0beef033e2f 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1117,7 +1117,7 @@ static bool dm_dax_supported(struct dax_device *dax_dev, struct block_device *bd
1117 if (!map) 1117 if (!map)
1118 return false; 1118 return false;
1119 1119
1120 ret = dm_table_supports_dax(map, blocksize); 1120 ret = dm_table_supports_dax(map, device_supports_dax, &blocksize);
1121 1121
1122 dm_put_live_table(md, srcu_idx); 1122 dm_put_live_table(md, srcu_idx);
1123 1123
@@ -1989,7 +1989,8 @@ static struct mapped_device *alloc_dev(int minor)
1989 sprintf(md->disk->disk_name, "dm-%d", minor); 1989 sprintf(md->disk->disk_name, "dm-%d", minor);
1990 1990
1991 if (IS_ENABLED(CONFIG_DAX_DRIVER)) { 1991 if (IS_ENABLED(CONFIG_DAX_DRIVER)) {
1992 md->dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops); 1992 md->dax_dev = alloc_dax(md, md->disk->disk_name,
1993 &dm_dax_ops, 0);
1993 if (!md->dax_dev) 1994 if (!md->dax_dev)
1994 goto bad; 1995 goto bad;
1995 } 1996 }
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 17e3db54404c..0475673337f3 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -72,7 +72,10 @@ bool dm_table_bio_based(struct dm_table *t);
72bool dm_table_request_based(struct dm_table *t); 72bool dm_table_request_based(struct dm_table *t);
73void dm_table_free_md_mempools(struct dm_table *t); 73void dm_table_free_md_mempools(struct dm_table *t);
74struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t); 74struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
75bool dm_table_supports_dax(struct dm_table *t, int blocksize); 75bool dm_table_supports_dax(struct dm_table *t, iterate_devices_callout_fn fn,
76 int *blocksize);
77int device_supports_dax(struct dm_target *ti, struct dm_dev *dev,
78 sector_t start, sector_t len, void *data);
76 79
77void dm_lock_md_type(struct mapped_device *md); 80void dm_lock_md_type(struct mapped_device *md);
78void dm_unlock_md_type(struct mapped_device *md); 81void dm_unlock_md_type(struct mapped_device *md);
diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile
index 6f2a088afad6..cefe233e0b52 100644
--- a/drivers/nvdimm/Makefile
+++ b/drivers/nvdimm/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_ND_BTT) += nd_btt.o
5obj-$(CONFIG_ND_BLK) += nd_blk.o 5obj-$(CONFIG_ND_BLK) += nd_blk.o
6obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o 6obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o
7obj-$(CONFIG_OF_PMEM) += of_pmem.o 7obj-$(CONFIG_OF_PMEM) += of_pmem.o
8obj-$(CONFIG_VIRTIO_PMEM) += virtio_pmem.o nd_virtio.o
8 9
9nd_pmem-y := pmem.o 10nd_pmem-y := pmem.o
10 11
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c
index 26c1c7618891..2985ca949912 100644
--- a/drivers/nvdimm/claim.c
+++ b/drivers/nvdimm/claim.c
@@ -255,7 +255,7 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
255 struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev); 255 struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
256 unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512); 256 unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
257 sector_t sector = offset >> 9; 257 sector_t sector = offset >> 9;
258 int rc = 0; 258 int rc = 0, ret = 0;
259 259
260 if (unlikely(!size)) 260 if (unlikely(!size))
261 return 0; 261 return 0;
@@ -293,7 +293,9 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
293 } 293 }
294 294
295 memcpy_flushcache(nsio->addr + offset, buf, size); 295 memcpy_flushcache(nsio->addr + offset, buf, size);
296 nvdimm_flush(to_nd_region(ndns->dev.parent)); 296 ret = nvdimm_flush(to_nd_region(ndns->dev.parent), NULL);
297 if (ret)
298 rc = ret;
297 299
298 return rc; 300 return rc;
299} 301}
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index a434a5964cb9..2d8d7e554877 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1822,8 +1822,8 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid,
1822 && !guid_equal(&nd_set->type_guid, 1822 && !guid_equal(&nd_set->type_guid,
1823 &nd_label->type_guid)) { 1823 &nd_label->type_guid)) {
1824 dev_dbg(ndd->dev, "expect type_guid %pUb got %pUb\n", 1824 dev_dbg(ndd->dev, "expect type_guid %pUb got %pUb\n",
1825 nd_set->type_guid.b, 1825 &nd_set->type_guid,
1826 nd_label->type_guid.b); 1826 &nd_label->type_guid);
1827 continue; 1827 continue;
1828 } 1828 }
1829 1829
@@ -2227,8 +2227,8 @@ static struct device *create_namespace_blk(struct nd_region *nd_region,
2227 if (namespace_label_has(ndd, type_guid)) { 2227 if (namespace_label_has(ndd, type_guid)) {
2228 if (!guid_equal(&nd_set->type_guid, &nd_label->type_guid)) { 2228 if (!guid_equal(&nd_set->type_guid, &nd_label->type_guid)) {
2229 dev_dbg(ndd->dev, "expect type_guid %pUb got %pUb\n", 2229 dev_dbg(ndd->dev, "expect type_guid %pUb got %pUb\n",
2230 nd_set->type_guid.b, 2230 &nd_set->type_guid,
2231 nd_label->type_guid.b); 2231 &nd_label->type_guid);
2232 return ERR_PTR(-EAGAIN); 2232 return ERR_PTR(-EAGAIN);
2233 } 2233 }
2234 2234
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index d24304c0e6d7..1b9955651379 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -155,6 +155,7 @@ struct nd_region {
155 struct badblocks bb; 155 struct badblocks bb;
156 struct nd_interleave_set *nd_set; 156 struct nd_interleave_set *nd_set;
157 struct nd_percpu_lane __percpu *lane; 157 struct nd_percpu_lane __percpu *lane;
158 int (*flush)(struct nd_region *nd_region, struct bio *bio);
158 struct nd_mapping mapping[0]; 159 struct nd_mapping mapping[0];
159}; 160};
160 161
diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c
new file mode 100644
index 000000000000..10351d5b49fa
--- /dev/null
+++ b/drivers/nvdimm/nd_virtio.c
@@ -0,0 +1,125 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * virtio_pmem.c: Virtio pmem Driver
4 *
5 * Discovers persistent memory range information
6 * from host and provides a virtio based flushing
7 * interface.
8 */
9#include "virtio_pmem.h"
10#include "nd.h"
11
12 /* The interrupt handler */
13void virtio_pmem_host_ack(struct virtqueue *vq)
14{
15 struct virtio_pmem *vpmem = vq->vdev->priv;
16 struct virtio_pmem_request *req_data, *req_buf;
17 unsigned long flags;
18 unsigned int len;
19
20 spin_lock_irqsave(&vpmem->pmem_lock, flags);
21 while ((req_data = virtqueue_get_buf(vq, &len)) != NULL) {
22 req_data->done = true;
23 wake_up(&req_data->host_acked);
24
25 if (!list_empty(&vpmem->req_list)) {
26 req_buf = list_first_entry(&vpmem->req_list,
27 struct virtio_pmem_request, list);
28 req_buf->wq_buf_avail = true;
29 wake_up(&req_buf->wq_buf);
30 list_del(&req_buf->list);
31 }
32 }
33 spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
34}
35EXPORT_SYMBOL_GPL(virtio_pmem_host_ack);
36
37 /* The request submission function */
38static int virtio_pmem_flush(struct nd_region *nd_region)
39{
40 struct virtio_device *vdev = nd_region->provider_data;
41 struct virtio_pmem *vpmem = vdev->priv;
42 struct virtio_pmem_request *req_data;
43 struct scatterlist *sgs[2], sg, ret;
44 unsigned long flags;
45 int err, err1;
46
47 might_sleep();
48 req_data = kmalloc(sizeof(*req_data), GFP_KERNEL);
49 if (!req_data)
50 return -ENOMEM;
51
52 req_data->done = false;
53 init_waitqueue_head(&req_data->host_acked);
54 init_waitqueue_head(&req_data->wq_buf);
55 INIT_LIST_HEAD(&req_data->list);
56 req_data->req.type = cpu_to_le32(VIRTIO_PMEM_REQ_TYPE_FLUSH);
57 sg_init_one(&sg, &req_data->req, sizeof(req_data->req));
58 sgs[0] = &sg;
59 sg_init_one(&ret, &req_data->resp.ret, sizeof(req_data->resp));
60 sgs[1] = &ret;
61
62 spin_lock_irqsave(&vpmem->pmem_lock, flags);
63 /*
64 * If virtqueue_add_sgs returns -ENOSPC then req_vq virtual
65 * queue does not have free descriptor. We add the request
66 * to req_list and wait for host_ack to wake us up when free
67 * slots are available.
68 */
69 while ((err = virtqueue_add_sgs(vpmem->req_vq, sgs, 1, 1, req_data,
70 GFP_ATOMIC)) == -ENOSPC) {
71
72 dev_info(&vdev->dev, "failed to send command to virtio pmem device, no free slots in the virtqueue\n");
73 req_data->wq_buf_avail = false;
74 list_add_tail(&req_data->list, &vpmem->req_list);
75 spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
76
77 /* A host response results in "host_ack" getting called */
78 wait_event(req_data->wq_buf, req_data->wq_buf_avail);
79 spin_lock_irqsave(&vpmem->pmem_lock, flags);
80 }
81 err1 = virtqueue_kick(vpmem->req_vq);
82 spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
83 /*
84 * virtqueue_add_sgs failed with error different than -ENOSPC, we can't
85 * do anything about that.
86 */
87 if (err || !err1) {
88 dev_info(&vdev->dev, "failed to send command to virtio pmem device\n");
89 err = -EIO;
90 } else {
91 /* A host repsonse results in "host_ack" getting called */
92 wait_event(req_data->host_acked, req_data->done);
93 err = le32_to_cpu(req_data->resp.ret);
94 }
95
96 kfree(req_data);
97 return err;
98};
99
100/* The asynchronous flush callback function */
101int async_pmem_flush(struct nd_region *nd_region, struct bio *bio)
102{
103 /*
104 * Create child bio for asynchronous flush and chain with
105 * parent bio. Otherwise directly call nd_region flush.
106 */
107 if (bio && bio->bi_iter.bi_sector != -1) {
108 struct bio *child = bio_alloc(GFP_ATOMIC, 0);
109
110 if (!child)
111 return -ENOMEM;
112 bio_copy_dev(child, bio);
113 child->bi_opf = REQ_PREFLUSH;
114 child->bi_iter.bi_sector = -1;
115 bio_chain(child, bio);
116 submit_bio(child);
117 return 0;
118 }
119 if (virtio_pmem_flush(nd_region))
120 return -EIO;
121
122 return 0;
123};
124EXPORT_SYMBOL_GPL(async_pmem_flush);
125MODULE_LICENSE("GPL");
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index e7d8cc9f41e8..2bf3acd69613 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -184,6 +184,7 @@ static blk_status_t pmem_do_bvec(struct pmem_device *pmem, struct page *page,
184 184
185static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio) 185static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
186{ 186{
187 int ret = 0;
187 blk_status_t rc = 0; 188 blk_status_t rc = 0;
188 bool do_acct; 189 bool do_acct;
189 unsigned long start; 190 unsigned long start;
@@ -193,7 +194,7 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
193 struct nd_region *nd_region = to_region(pmem); 194 struct nd_region *nd_region = to_region(pmem);
194 195
195 if (bio->bi_opf & REQ_PREFLUSH) 196 if (bio->bi_opf & REQ_PREFLUSH)
196 nvdimm_flush(nd_region); 197 ret = nvdimm_flush(nd_region, bio);
197 198
198 do_acct = nd_iostat_start(bio, &start); 199 do_acct = nd_iostat_start(bio, &start);
199 bio_for_each_segment(bvec, bio, iter) { 200 bio_for_each_segment(bvec, bio, iter) {
@@ -208,7 +209,10 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
208 nd_iostat_end(bio, start); 209 nd_iostat_end(bio, start);
209 210
210 if (bio->bi_opf & REQ_FUA) 211 if (bio->bi_opf & REQ_FUA)
211 nvdimm_flush(nd_region); 212 ret = nvdimm_flush(nd_region, bio);
213
214 if (ret)
215 bio->bi_status = errno_to_blk_status(ret);
212 216
213 bio_endio(bio); 217 bio_endio(bio);
214 return BLK_QC_T_NONE; 218 return BLK_QC_T_NONE;
@@ -362,6 +366,7 @@ static int pmem_attach_disk(struct device *dev,
362 struct gendisk *disk; 366 struct gendisk *disk;
363 void *addr; 367 void *addr;
364 int rc; 368 int rc;
369 unsigned long flags = 0UL;
365 370
366 pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL); 371 pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL);
367 if (!pmem) 372 if (!pmem)
@@ -457,14 +462,15 @@ static int pmem_attach_disk(struct device *dev,
457 nvdimm_badblocks_populate(nd_region, &pmem->bb, &bb_res); 462 nvdimm_badblocks_populate(nd_region, &pmem->bb, &bb_res);
458 disk->bb = &pmem->bb; 463 disk->bb = &pmem->bb;
459 464
460 dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops); 465 if (is_nvdimm_sync(nd_region))
466 flags = DAXDEV_F_SYNC;
467 dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops, flags);
461 if (!dax_dev) { 468 if (!dax_dev) {
462 put_disk(disk); 469 put_disk(disk);
463 return -ENOMEM; 470 return -ENOMEM;
464 } 471 }
465 dax_write_cache(dax_dev, nvdimm_has_cache(nd_region)); 472 dax_write_cache(dax_dev, nvdimm_has_cache(nd_region));
466 pmem->dax_dev = dax_dev; 473 pmem->dax_dev = dax_dev;
467
468 gendev = disk_to_dev(disk); 474 gendev = disk_to_dev(disk);
469 gendev->groups = pmem_attribute_groups; 475 gendev->groups = pmem_attribute_groups;
470 476
@@ -522,14 +528,14 @@ static int nd_pmem_remove(struct device *dev)
522 sysfs_put(pmem->bb_state); 528 sysfs_put(pmem->bb_state);
523 pmem->bb_state = NULL; 529 pmem->bb_state = NULL;
524 } 530 }
525 nvdimm_flush(to_nd_region(dev->parent)); 531 nvdimm_flush(to_nd_region(dev->parent), NULL);
526 532
527 return 0; 533 return 0;
528} 534}
529 535
530static void nd_pmem_shutdown(struct device *dev) 536static void nd_pmem_shutdown(struct device *dev)
531{ 537{
532 nvdimm_flush(to_nd_region(dev->parent)); 538 nvdimm_flush(to_nd_region(dev->parent), NULL);
533} 539}
534 540
535static void nd_pmem_notify(struct device *dev, enum nvdimm_event event) 541static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index 4fed9ce9c2fe..56f2227f192a 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -287,7 +287,9 @@ static ssize_t deep_flush_store(struct device *dev, struct device_attribute *att
287 return rc; 287 return rc;
288 if (!flush) 288 if (!flush)
289 return -EINVAL; 289 return -EINVAL;
290 nvdimm_flush(nd_region); 290 rc = nvdimm_flush(nd_region, NULL);
291 if (rc)
292 return rc;
291 293
292 return len; 294 return len;
293} 295}
@@ -1077,6 +1079,11 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
1077 dev->of_node = ndr_desc->of_node; 1079 dev->of_node = ndr_desc->of_node;
1078 nd_region->ndr_size = resource_size(ndr_desc->res); 1080 nd_region->ndr_size = resource_size(ndr_desc->res);
1079 nd_region->ndr_start = ndr_desc->res->start; 1081 nd_region->ndr_start = ndr_desc->res->start;
1082 if (ndr_desc->flush)
1083 nd_region->flush = ndr_desc->flush;
1084 else
1085 nd_region->flush = NULL;
1086
1080 nd_device_register(dev); 1087 nd_device_register(dev);
1081 1088
1082 return nd_region; 1089 return nd_region;
@@ -1117,11 +1124,24 @@ struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus,
1117} 1124}
1118EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create); 1125EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create);
1119 1126
1127int nvdimm_flush(struct nd_region *nd_region, struct bio *bio)
1128{
1129 int rc = 0;
1130
1131 if (!nd_region->flush)
1132 rc = generic_nvdimm_flush(nd_region);
1133 else {
1134 if (nd_region->flush(nd_region, bio))
1135 rc = -EIO;
1136 }
1137
1138 return rc;
1139}
1120/** 1140/**
1121 * nvdimm_flush - flush any posted write queues between the cpu and pmem media 1141 * nvdimm_flush - flush any posted write queues between the cpu and pmem media
1122 * @nd_region: blk or interleaved pmem region 1142 * @nd_region: blk or interleaved pmem region
1123 */ 1143 */
1124void nvdimm_flush(struct nd_region *nd_region) 1144int generic_nvdimm_flush(struct nd_region *nd_region)
1125{ 1145{
1126 struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev); 1146 struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev);
1127 int i, idx; 1147 int i, idx;
@@ -1145,6 +1165,8 @@ void nvdimm_flush(struct nd_region *nd_region)
1145 if (ndrd_get_flush_wpq(ndrd, i, 0)) 1165 if (ndrd_get_flush_wpq(ndrd, i, 0))
1146 writeq(1, ndrd_get_flush_wpq(ndrd, i, idx)); 1166 writeq(1, ndrd_get_flush_wpq(ndrd, i, idx));
1147 wmb(); 1167 wmb();
1168
1169 return 0;
1148} 1170}
1149EXPORT_SYMBOL_GPL(nvdimm_flush); 1171EXPORT_SYMBOL_GPL(nvdimm_flush);
1150 1172
@@ -1189,6 +1211,13 @@ int nvdimm_has_cache(struct nd_region *nd_region)
1189} 1211}
1190EXPORT_SYMBOL_GPL(nvdimm_has_cache); 1212EXPORT_SYMBOL_GPL(nvdimm_has_cache);
1191 1213
1214bool is_nvdimm_sync(struct nd_region *nd_region)
1215{
1216 return is_nd_pmem(&nd_region->dev) &&
1217 !test_bit(ND_REGION_ASYNC, &nd_region->flags);
1218}
1219EXPORT_SYMBOL_GPL(is_nvdimm_sync);
1220
1192struct conflict_context { 1221struct conflict_context {
1193 struct nd_region *nd_region; 1222 struct nd_region *nd_region;
1194 resource_size_t start, size; 1223 resource_size_t start, size;
diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c
new file mode 100644
index 000000000000..5e3d07b47e0c
--- /dev/null
+++ b/drivers/nvdimm/virtio_pmem.c
@@ -0,0 +1,122 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * virtio_pmem.c: Virtio pmem Driver
4 *
5 * Discovers persistent memory range information
6 * from host and registers the virtual pmem device
7 * with libnvdimm core.
8 */
9#include "virtio_pmem.h"
10#include "nd.h"
11
12static struct virtio_device_id id_table[] = {
13 { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID },
14 { 0 },
15};
16
17 /* Initialize virt queue */
18static int init_vq(struct virtio_pmem *vpmem)
19{
20 /* single vq */
21 vpmem->req_vq = virtio_find_single_vq(vpmem->vdev,
22 virtio_pmem_host_ack, "flush_queue");
23 if (IS_ERR(vpmem->req_vq))
24 return PTR_ERR(vpmem->req_vq);
25
26 spin_lock_init(&vpmem->pmem_lock);
27 INIT_LIST_HEAD(&vpmem->req_list);
28
29 return 0;
30};
31
32static int virtio_pmem_probe(struct virtio_device *vdev)
33{
34 struct nd_region_desc ndr_desc = {};
35 int nid = dev_to_node(&vdev->dev);
36 struct nd_region *nd_region;
37 struct virtio_pmem *vpmem;
38 struct resource res;
39 int err = 0;
40
41 if (!vdev->config->get) {
42 dev_err(&vdev->dev, "%s failure: config access disabled\n",
43 __func__);
44 return -EINVAL;
45 }
46
47 vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL);
48 if (!vpmem) {
49 err = -ENOMEM;
50 goto out_err;
51 }
52
53 vpmem->vdev = vdev;
54 vdev->priv = vpmem;
55 err = init_vq(vpmem);
56 if (err) {
57 dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n");
58 goto out_err;
59 }
60
61 virtio_cread(vpmem->vdev, struct virtio_pmem_config,
62 start, &vpmem->start);
63 virtio_cread(vpmem->vdev, struct virtio_pmem_config,
64 size, &vpmem->size);
65
66 res.start = vpmem->start;
67 res.end = vpmem->start + vpmem->size - 1;
68 vpmem->nd_desc.provider_name = "virtio-pmem";
69 vpmem->nd_desc.module = THIS_MODULE;
70
71 vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev,
72 &vpmem->nd_desc);
73 if (!vpmem->nvdimm_bus) {
74 dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n");
75 err = -ENXIO;
76 goto out_vq;
77 }
78
79 dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
80
81 ndr_desc.res = &res;
82 ndr_desc.numa_node = nid;
83 ndr_desc.flush = async_pmem_flush;
84 set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
85 set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
86 nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc);
87 if (!nd_region) {
88 dev_err(&vdev->dev, "failed to create nvdimm region\n");
89 err = -ENXIO;
90 goto out_nd;
91 }
92 nd_region->provider_data = dev_to_virtio(nd_region->dev.parent->parent);
93 return 0;
94out_nd:
95 nvdimm_bus_unregister(vpmem->nvdimm_bus);
96out_vq:
97 vdev->config->del_vqs(vdev);
98out_err:
99 return err;
100}
101
102static void virtio_pmem_remove(struct virtio_device *vdev)
103{
104 struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
105
106 nvdimm_bus_unregister(nvdimm_bus);
107 vdev->config->del_vqs(vdev);
108 vdev->config->reset(vdev);
109}
110
111static struct virtio_driver virtio_pmem_driver = {
112 .driver.name = KBUILD_MODNAME,
113 .driver.owner = THIS_MODULE,
114 .id_table = id_table,
115 .probe = virtio_pmem_probe,
116 .remove = virtio_pmem_remove,
117};
118
119module_virtio_driver(virtio_pmem_driver);
120MODULE_DEVICE_TABLE(virtio, id_table);
121MODULE_DESCRIPTION("Virtio pmem driver");
122MODULE_LICENSE("GPL");
diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h
new file mode 100644
index 000000000000..0dddefe594c4
--- /dev/null
+++ b/drivers/nvdimm/virtio_pmem.h
@@ -0,0 +1,55 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * virtio_pmem.h: virtio pmem Driver
4 *
5 * Discovers persistent memory range information
6 * from host and provides a virtio based flushing
7 * interface.
8 **/
9
10#ifndef _LINUX_VIRTIO_PMEM_H
11#define _LINUX_VIRTIO_PMEM_H
12
13#include <linux/module.h>
14#include <uapi/linux/virtio_pmem.h>
15#include <linux/libnvdimm.h>
16#include <linux/spinlock.h>
17
18struct virtio_pmem_request {
19 struct virtio_pmem_req req;
20 struct virtio_pmem_resp resp;
21
22 /* Wait queue to process deferred work after ack from host */
23 wait_queue_head_t host_acked;
24 bool done;
25
26 /* Wait queue to process deferred work after virt queue buffer avail */
27 wait_queue_head_t wq_buf;
28 bool wq_buf_avail;
29 struct list_head list;
30};
31
32struct virtio_pmem {
33 struct virtio_device *vdev;
34
35 /* Virtio pmem request queue */
36 struct virtqueue *req_vq;
37
38 /* nvdimm bus registers virtio pmem device */
39 struct nvdimm_bus *nvdimm_bus;
40 struct nvdimm_bus_descriptor nd_desc;
41
42 /* List to store deferred work if virtqueue is full */
43 struct list_head req_list;
44
45 /* Synchronize virtqueue data */
46 spinlock_t pmem_lock;
47
48 /* Memory region information */
49 __u64 start;
50 __u64 size;
51};
52
53void virtio_pmem_host_ack(struct virtqueue *vq);
54int async_pmem_flush(struct nd_region *nd_region, struct bio *bio);
55#endif
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index d04d4378ca50..63502ca537eb 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -679,7 +679,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
679 goto put_dev; 679 goto put_dev;
680 680
681 dev_info->dax_dev = alloc_dax(dev_info, dev_info->gd->disk_name, 681 dev_info->dax_dev = alloc_dax(dev_info, dev_info->gd->disk_name,
682 &dcssblk_dax_ops); 682 &dcssblk_dax_ops, DAXDEV_F_SYNC);
683 if (!dev_info->dax_dev) { 683 if (!dev_info->dax_dev) {
684 rc = -ENOMEM; 684 rc = -ENOMEM;
685 goto put_dev; 685 goto put_dev;
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 023fc3bc01c6..078615cf2afc 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -43,6 +43,17 @@ config VIRTIO_PCI_LEGACY
43 43
44 If unsure, say Y. 44 If unsure, say Y.
45 45
46config VIRTIO_PMEM
47 tristate "Support for virtio pmem driver"
48 depends on VIRTIO
49 depends on LIBNVDIMM
50 help
51 This driver provides access to virtio-pmem devices, storage devices
52 that are mapped into the physical address space - similar to NVDIMMs
53 - with a virtio-based flushing interface.
54
55 If unsure, say Y.
56
46config VIRTIO_BALLOON 57config VIRTIO_BALLOON
47 tristate "Virtio balloon driver" 58 tristate "Virtio balloon driver"
48 depends on VIRTIO 59 depends on VIRTIO
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index f4a24a46245e..70b0438dbc94 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -371,15 +371,17 @@ static const struct vm_operations_struct ext4_file_vm_ops = {
371static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma) 371static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
372{ 372{
373 struct inode *inode = file->f_mapping->host; 373 struct inode *inode = file->f_mapping->host;
374 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
375 struct dax_device *dax_dev = sbi->s_daxdev;
374 376
375 if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) 377 if (unlikely(ext4_forced_shutdown(sbi)))
376 return -EIO; 378 return -EIO;
377 379
378 /* 380 /*
379 * We don't support synchronous mappings for non-DAX files. At least 381 * We don't support synchronous mappings for non-DAX files and
380 * until someone comes with a sensible use case. 382 * for DAX files if underneath dax_device is not synchronous.
381 */ 383 */
382 if (!IS_DAX(file_inode(file)) && (vma->vm_flags & VM_SYNC)) 384 if (!daxdev_mapping_supported(vma, dax_dev))
383 return -EOPNOTSUPP; 385 return -EOPNOTSUPP;
384 386
385 file_accessed(file); 387 file_accessed(file);
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index e93bacbd49ae..28101bbc0b78 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -1197,11 +1197,14 @@ xfs_file_mmap(
1197 struct file *filp, 1197 struct file *filp,
1198 struct vm_area_struct *vma) 1198 struct vm_area_struct *vma)
1199{ 1199{
1200 struct dax_device *dax_dev;
1201
1202 dax_dev = xfs_find_daxdev_for_inode(file_inode(filp));
1200 /* 1203 /*
1201 * We don't support synchronous mappings for non-DAX files. At least 1204 * We don't support synchronous mappings for non-DAX files and
1202 * until someone comes with a sensible use case. 1205 * for DAX files if underneath dax_device is not synchronous.
1203 */ 1206 */
1204 if (!IS_DAX(file_inode(filp)) && (vma->vm_flags & VM_SYNC)) 1207 if (!daxdev_mapping_supported(vma, dax_dev))
1205 return -EOPNOTSUPP; 1208 return -EOPNOTSUPP;
1206 1209
1207 file_accessed(filp); 1210 file_accessed(filp);
diff --git a/include/linux/dax.h b/include/linux/dax.h
index becaea5f4488..9bd8528bd305 100644
--- a/include/linux/dax.h
+++ b/include/linux/dax.h
@@ -7,6 +7,9 @@
7#include <linux/radix-tree.h> 7#include <linux/radix-tree.h>
8#include <asm/pgtable.h> 8#include <asm/pgtable.h>
9 9
10/* Flag for synchronous flush */
11#define DAXDEV_F_SYNC (1UL << 0)
12
10typedef unsigned long dax_entry_t; 13typedef unsigned long dax_entry_t;
11 14
12struct iomap_ops; 15struct iomap_ops;
@@ -38,18 +41,40 @@ extern struct attribute_group dax_attribute_group;
38#if IS_ENABLED(CONFIG_DAX) 41#if IS_ENABLED(CONFIG_DAX)
39struct dax_device *dax_get_by_host(const char *host); 42struct dax_device *dax_get_by_host(const char *host);
40struct dax_device *alloc_dax(void *private, const char *host, 43struct dax_device *alloc_dax(void *private, const char *host,
41 const struct dax_operations *ops); 44 const struct dax_operations *ops, unsigned long flags);
42void put_dax(struct dax_device *dax_dev); 45void put_dax(struct dax_device *dax_dev);
43void kill_dax(struct dax_device *dax_dev); 46void kill_dax(struct dax_device *dax_dev);
44void dax_write_cache(struct dax_device *dax_dev, bool wc); 47void dax_write_cache(struct dax_device *dax_dev, bool wc);
45bool dax_write_cache_enabled(struct dax_device *dax_dev); 48bool dax_write_cache_enabled(struct dax_device *dax_dev);
49bool __dax_synchronous(struct dax_device *dax_dev);
50static inline bool dax_synchronous(struct dax_device *dax_dev)
51{
52 return __dax_synchronous(dax_dev);
53}
54void __set_dax_synchronous(struct dax_device *dax_dev);
55static inline void set_dax_synchronous(struct dax_device *dax_dev)
56{
57 __set_dax_synchronous(dax_dev);
58}
59/*
60 * Check if given mapping is supported by the file / underlying device.
61 */
62static inline bool daxdev_mapping_supported(struct vm_area_struct *vma,
63 struct dax_device *dax_dev)
64{
65 if (!(vma->vm_flags & VM_SYNC))
66 return true;
67 if (!IS_DAX(file_inode(vma->vm_file)))
68 return false;
69 return dax_synchronous(dax_dev);
70}
46#else 71#else
47static inline struct dax_device *dax_get_by_host(const char *host) 72static inline struct dax_device *dax_get_by_host(const char *host)
48{ 73{
49 return NULL; 74 return NULL;
50} 75}
51static inline struct dax_device *alloc_dax(void *private, const char *host, 76static inline struct dax_device *alloc_dax(void *private, const char *host,
52 const struct dax_operations *ops) 77 const struct dax_operations *ops, unsigned long flags)
53{ 78{
54 /* 79 /*
55 * Callers should check IS_ENABLED(CONFIG_DAX) to know if this 80 * Callers should check IS_ENABLED(CONFIG_DAX) to know if this
@@ -70,6 +95,18 @@ static inline bool dax_write_cache_enabled(struct dax_device *dax_dev)
70{ 95{
71 return false; 96 return false;
72} 97}
98static inline bool dax_synchronous(struct dax_device *dax_dev)
99{
100 return true;
101}
102static inline void set_dax_synchronous(struct dax_device *dax_dev)
103{
104}
105static inline bool daxdev_mapping_supported(struct vm_area_struct *vma,
106 struct dax_device *dax_dev)
107{
108 return !(vma->vm_flags & VM_SYNC);
109}
73#endif 110#endif
74 111
75struct writeback_control; 112struct writeback_control;
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index 03d5c3aece9d..7a64b3ddb408 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -11,6 +11,7 @@
11#include <linux/types.h> 11#include <linux/types.h>
12#include <linux/uuid.h> 12#include <linux/uuid.h>
13#include <linux/spinlock.h> 13#include <linux/spinlock.h>
14#include <linux/bio.h>
14 15
15struct badrange_entry { 16struct badrange_entry {
16 u64 start; 17 u64 start;
@@ -57,6 +58,9 @@ enum {
57 */ 58 */
58 ND_REGION_PERSIST_MEMCTRL = 2, 59 ND_REGION_PERSIST_MEMCTRL = 2,
59 60
61 /* Platform provides asynchronous flush mechanism */
62 ND_REGION_ASYNC = 3,
63
60 /* mark newly adjusted resources as requiring a label update */ 64 /* mark newly adjusted resources as requiring a label update */
61 DPA_RESOURCE_ADJUSTED = 1 << 0, 65 DPA_RESOURCE_ADJUSTED = 1 << 0,
62}; 66};
@@ -113,6 +117,7 @@ struct nd_mapping_desc {
113 int position; 117 int position;
114}; 118};
115 119
120struct nd_region;
116struct nd_region_desc { 121struct nd_region_desc {
117 struct resource *res; 122 struct resource *res;
118 struct nd_mapping_desc *mapping; 123 struct nd_mapping_desc *mapping;
@@ -125,6 +130,7 @@ struct nd_region_desc {
125 int target_node; 130 int target_node;
126 unsigned long flags; 131 unsigned long flags;
127 struct device_node *of_node; 132 struct device_node *of_node;
133 int (*flush)(struct nd_region *nd_region, struct bio *bio);
128}; 134};
129 135
130struct device; 136struct device;
@@ -252,10 +258,12 @@ unsigned long nd_blk_memremap_flags(struct nd_blk_region *ndbr);
252unsigned int nd_region_acquire_lane(struct nd_region *nd_region); 258unsigned int nd_region_acquire_lane(struct nd_region *nd_region);
253void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane); 259void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane);
254u64 nd_fletcher64(void *addr, size_t len, bool le); 260u64 nd_fletcher64(void *addr, size_t len, bool le);
255void nvdimm_flush(struct nd_region *nd_region); 261int nvdimm_flush(struct nd_region *nd_region, struct bio *bio);
262int generic_nvdimm_flush(struct nd_region *nd_region);
256int nvdimm_has_flush(struct nd_region *nd_region); 263int nvdimm_has_flush(struct nd_region *nd_region);
257int nvdimm_has_cache(struct nd_region *nd_region); 264int nvdimm_has_cache(struct nd_region *nd_region);
258int nvdimm_in_overwrite(struct nvdimm *nvdimm); 265int nvdimm_in_overwrite(struct nvdimm *nvdimm);
266bool is_nvdimm_sync(struct nd_region *nd_region);
259 267
260static inline int nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, void *buf, 268static inline int nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, void *buf,
261 unsigned int buf_len, int *cmd_rc) 269 unsigned int buf_len, int *cmd_rc)
diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
index cfe47c5d9a56..348fd0176f75 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -44,5 +44,6 @@
44#define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ 44#define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */
45#define VIRTIO_ID_CRYPTO 20 /* virtio crypto */ 45#define VIRTIO_ID_CRYPTO 20 /* virtio crypto */
46#define VIRTIO_ID_IOMMU 23 /* virtio IOMMU */ 46#define VIRTIO_ID_IOMMU 23 /* virtio IOMMU */
47#define VIRTIO_ID_PMEM 27 /* virtio pmem */
47 48
48#endif /* _LINUX_VIRTIO_IDS_H */ 49#endif /* _LINUX_VIRTIO_IDS_H */
diff --git a/include/uapi/linux/virtio_pmem.h b/include/uapi/linux/virtio_pmem.h
new file mode 100644
index 000000000000..9a63ed6d062f
--- /dev/null
+++ b/include/uapi/linux/virtio_pmem.h
@@ -0,0 +1,34 @@
1/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
2/*
3 * Definitions for virtio-pmem devices.
4 *
5 * Copyright (C) 2019 Red Hat, Inc.
6 *
7 * Author(s): Pankaj Gupta <pagupta@redhat.com>
8 */
9
10#ifndef _UAPI_LINUX_VIRTIO_PMEM_H
11#define _UAPI_LINUX_VIRTIO_PMEM_H
12
13#include <linux/types.h>
14#include <linux/virtio_ids.h>
15#include <linux/virtio_config.h>
16
17struct virtio_pmem_config {
18 __u64 start;
19 __u64 size;
20};
21
22#define VIRTIO_PMEM_REQ_TYPE_FLUSH 0
23
24struct virtio_pmem_resp {
25 /* Host return status corresponding to flush request */
26 __le32 ret;
27};
28
29struct virtio_pmem_req {
30 /* command type */
31 __le32 type;
32};
33
34#endif