]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/nvdimm/pmem.c
libnvdimm, pmem: disable dax flushing when pmem is fronting a volatile region
[mirror_ubuntu-artful-kernel.git] / drivers / nvdimm / pmem.c
index c544d466ea51071a3c09a53544df61d8a1bae759..e7a40f77f7299379b1b96388bbf74d21b4a5e316 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/blk-mq.h>
 #include <linux/pfn_t.h>
 #include <linux/slab.h>
-#include <linux/pmem.h>
+#include <linux/uio.h>
 #include <linux/dax.h>
 #include <linux/nd.h>
 #include "pmem.h"
@@ -70,7 +70,7 @@ static int pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
                badblocks_clear(&pmem->bb, sector, cleared);
        }
 
-       invalidate_pmem(pmem->virt_addr + offset, len);
+       arch_invalidate_pmem(pmem->virt_addr + offset, len);
 
        return rc;
 }
@@ -80,7 +80,7 @@ static void write_pmem(void *pmem_addr, struct page *page,
 {
        void *mem = kmap_atomic(page);
 
-       memcpy_to_pmem(pmem_addr, mem + off, len);
+       memcpy_flushcache(pmem_addr, mem + off, len);
        kunmap_atomic(mem);
 }
 
@@ -235,8 +235,27 @@ static long pmem_dax_direct_access(struct dax_device *dax_dev,
        return __pmem_direct_access(pmem, pgoff, nr_pages, kaddr, pfn);
 }
 
+static size_t pmem_copy_from_iter(struct dax_device *dax_dev, pgoff_t pgoff,
+               void *addr, size_t bytes, struct iov_iter *i)
+{
+       return copy_from_iter_flushcache(addr, bytes, i);
+}
+
+static void pmem_dax_flush(struct dax_device *dax_dev, pgoff_t pgoff,
+               void *addr, size_t size)
+{
+       arch_wb_cache_pmem(addr, size);
+}
+
 static const struct dax_operations pmem_dax_ops = {
        .direct_access = pmem_dax_direct_access,
+       .copy_from_iter = pmem_copy_from_iter,
+       .flush = pmem_dax_flush,
+};
+
+static const struct attribute_group *pmem_attribute_groups[] = {
+       &dax_attribute_group,
+       NULL,
 };
 
 static void pmem_release_queue(void *q)
@@ -265,14 +284,15 @@ static int pmem_attach_disk(struct device *dev,
        struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
        struct nd_region *nd_region = to_nd_region(dev->parent);
        struct vmem_altmap __altmap, *altmap = NULL;
+       int nid = dev_to_node(dev), fua, wbc;
        struct resource *res = &nsio->res;
        struct nd_pfn *nd_pfn = NULL;
        struct dax_device *dax_dev;
-       int nid = dev_to_node(dev);
        struct nd_pfn_sb *pfn_sb;
        struct pmem_device *pmem;
        struct resource pfn_res;
        struct request_queue *q;
+       struct device *gendev;
        struct gendisk *disk;
        void *addr;
 
@@ -294,8 +314,12 @@ static int pmem_attach_disk(struct device *dev,
        dev_set_drvdata(dev, pmem);
        pmem->phys_addr = res->start;
        pmem->size = resource_size(res);
-       if (nvdimm_has_flush(nd_region) < 0)
+       fua = nvdimm_has_flush(nd_region);
+       if (!IS_ENABLED(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) || fua < 0) {
                dev_warn(dev, "unable to guarantee persistence of writes\n");
+               fua = 0;
+       }
+       wbc = nvdimm_has_cache(nd_region);
 
        if (!devm_request_mem_region(dev, res->start, resource_size(res),
                                dev_name(&ndns->dev))) {
@@ -339,7 +363,7 @@ static int pmem_attach_disk(struct device *dev,
                return PTR_ERR(addr);
        pmem->virt_addr = addr;
 
-       blk_queue_write_cache(q, true, true);
+       blk_queue_write_cache(q, wbc, fua);
        blk_queue_make_request(q, pmem_make_request);
        blk_queue_physical_block_size(q, PAGE_SIZE);
        blk_queue_max_hw_sectors(q, UINT_MAX);
@@ -369,8 +393,12 @@ static int pmem_attach_disk(struct device *dev,
                put_disk(disk);
                return -ENOMEM;
        }
+       dax_write_cache(dax_dev, wbc);
        pmem->dax_dev = dax_dev;
 
+       gendev = disk_to_dev(disk);
+       gendev->groups = pmem_attribute_groups;
+
        device_add_disk(dev, disk);
        if (devm_add_action_or_reset(dev, pmem_release_disk, pmem))
                return -ENOMEM;