libnvdimm: async notification support
authorDan Williams <dan.j.williams@intel.com>
Thu, 18 Feb 2016 18:29:49 +0000 (10:29 -0800)
committerDan Williams <dan.j.williams@intel.com>
Sat, 5 Mar 2016 20:24:06 +0000 (12:24 -0800)
In preparation for asynchronous address range scrub support add an
ability for the pmem driver to dynamically consume address range scrub
results.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/nvdimm/bus.c
drivers/nvdimm/nd.h
drivers/nvdimm/pmem.c
drivers/nvdimm/region.c
include/linux/nd.h

index c3ba888e3e3a0739cfb22e6cf7a11a77145fa4b4..2508251439e706ad6f14fb87799ccfe87319857d 100644 (file)
@@ -133,6 +133,32 @@ static int nvdimm_bus_remove(struct device *dev)
        return rc;
 }
 
+void nd_device_notify(struct device *dev, enum nvdimm_event event)
+{
+       device_lock(dev);
+       if (dev->driver) {
+               struct nd_device_driver *nd_drv;
+
+               nd_drv = to_nd_device_driver(dev->driver);
+               if (nd_drv->notify)
+                       nd_drv->notify(dev, event);
+       }
+       device_unlock(dev);
+}
+EXPORT_SYMBOL(nd_device_notify);
+
+void nvdimm_region_notify(struct nd_region *nd_region, enum nvdimm_event event)
+{
+       struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(&nd_region->dev);
+
+       if (!nvdimm_bus)
+               return;
+
+       /* caller is responsible for holding a reference on the device */
+       nd_device_notify(&nd_region->dev, event);
+}
+EXPORT_SYMBOL_GPL(nvdimm_region_notify);
+
 static struct bus_type nvdimm_bus_type = {
        .name = "nd",
        .uevent = nvdimm_bus_uevent,
index ba1633b9da31fb2491101708cf105a765ec29bb4..78b82f6dd191f412b28930d85ccafafd0323c7b4 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mutex.h>
 #include <linux/ndctl.h>
 #include <linux/types.h>
+#include <linux/nd.h>
 #include "label.h"
 
 enum {
@@ -168,6 +169,7 @@ int nd_integrity_init(struct gendisk *disk, unsigned long meta_size);
 void wait_nvdimm_bus_probe_idle(struct device *dev);
 void nd_device_register(struct device *dev);
 void nd_device_unregister(struct device *dev, enum nd_async_mode mode);
+void nd_device_notify(struct device *dev, enum nvdimm_event event);
 int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf,
                size_t len);
 ssize_t nd_sector_size_show(unsigned long current_lbasize,
index 8d0b546701848eb2b57d87b7207490133e5c32a9..efc2a5e671c67ee045c747e7a3ad6a1c4e92098e 100644 (file)
@@ -488,12 +488,27 @@ static int nd_pmem_remove(struct device *dev)
        return 0;
 }
 
+static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
+{
+       struct pmem_device *pmem = dev_get_drvdata(dev);
+       struct nd_namespace_common *ndns = pmem->ndns;
+
+       if (event != NVDIMM_REVALIDATE_POISON)
+               return;
+
+       if (is_nd_btt(dev))
+               nvdimm_namespace_add_poison(ndns, &pmem->bb, 0);
+       else
+               nvdimm_namespace_add_poison(ndns, &pmem->bb, pmem->data_offset);
+}
+
 MODULE_ALIAS("pmem");
 MODULE_ALIAS_ND_DEVICE(ND_DEVICE_NAMESPACE_IO);
 MODULE_ALIAS_ND_DEVICE(ND_DEVICE_NAMESPACE_PMEM);
 static struct nd_device_driver nd_pmem_driver = {
        .probe = nd_pmem_probe,
        .remove = nd_pmem_remove,
+       .notify = nd_pmem_notify,
        .drv = {
                .name = "nd_pmem",
        },
index 7da63eac78eec1b449457fb123bbac4154deaef3..4b7715e29cfffc5de69a31836d715081726d2275 100644 (file)
@@ -93,9 +93,21 @@ static int nd_region_remove(struct device *dev)
        return 0;
 }
 
+static int child_notify(struct device *dev, void *data)
+{
+       nd_device_notify(dev, *(enum nvdimm_event *) data);
+       return 0;
+}
+
+static void nd_region_notify(struct device *dev, enum nvdimm_event event)
+{
+       device_for_each_child(dev, &event, child_notify);
+}
+
 static struct nd_device_driver nd_region_driver = {
        .probe = nd_region_probe,
        .remove = nd_region_remove,
+       .notify = nd_region_notify,
        .drv = {
                .name = "nd_region",
        },
index 507e47c86737df88ffa682f09be22e8a57a977ec..5489ab756d1a5e58b4861411227fd1e3552fd93c 100644 (file)
 #include <linux/ndctl.h>
 #include <linux/device.h>
 
+enum nvdimm_event {
+       NVDIMM_REVALIDATE_POISON,
+};
+
 struct nd_device_driver {
        struct device_driver drv;
        unsigned long type;
        int (*probe)(struct device *dev);
        int (*remove)(struct device *dev);
+       void (*notify)(struct device *dev, enum nvdimm_event event);
 };
 
 static inline struct nd_device_driver *to_nd_device_driver(
@@ -144,6 +149,8 @@ static inline int nvdimm_write_bytes(struct nd_namespace_common *ndns,
        MODULE_ALIAS("nd:t" __stringify(type) "*")
 #define ND_DEVICE_MODALIAS_FMT "nd:t%d"
 
+struct nd_region;
+void nvdimm_region_notify(struct nd_region *nd_region, enum nvdimm_event event);
 int __must_check __nd_driver_register(struct nd_device_driver *nd_drv,
                struct module *module, const char *mod_name);
 #define nd_driver_register(driver) \