device-dax: Move resource pinning+mapping into the common driver
authorDan Williams <dan.j.williams@intel.com>
Mon, 29 Oct 2018 22:52:42 +0000 (15:52 -0700)
committerDan Williams <dan.j.williams@intel.com>
Mon, 7 Jan 2019 05:26:21 +0000 (21:26 -0800)
Move the responsibility of calling devm_request_resource() and
devm_memremap_pages() into the common device-dax driver. This is another
preparatory step to allowing an alternate personality driver for a
device-dax range.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/dax/bus.c
drivers/dax/bus.h
drivers/dax/dax-private.h
drivers/dax/device.c
drivers/dax/pmem.c

index 0cff32102c4c80ae1486adbd911e69bd5668ee76..69aae2cbd45f1e1fa807ed0ad1f36edfcdd838cd 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright(c) 2017-2018 Intel Corporation. All rights reserved. */
+#include <linux/memremap.h>
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/dax.h>
@@ -206,7 +207,8 @@ static void unregister_dev_dax(void *dev)
        put_device(dev);
 }
 
-struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id)
+struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id,
+               struct dev_pagemap *pgmap)
 {
        struct device *parent = dax_region->dev;
        struct dax_device *dax_dev;
@@ -222,6 +224,8 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id)
        if (!dev_dax)
                return ERR_PTR(-ENOMEM);
 
+       memcpy(&dev_dax->pgmap, pgmap, sizeof(*pgmap));
+
        /*
         * No 'host' or dax_operations since there is no access to this
         * device outside of mmap of the resulting character device.
index ea509504df3aadd8b4ede7cde31e9719383e94ba..e08e0c394983dcda471362a0025e94deb47ed310 100644 (file)
@@ -10,7 +10,8 @@ struct dax_region;
 void dax_region_put(struct dax_region *dax_region);
 struct dax_region *alloc_dax_region(struct device *parent, int region_id,
                struct resource *res, unsigned int align, unsigned long flags);
-struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id);
+struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id,
+               struct dev_pagemap *pgmap);
 int __dax_driver_register(struct device_driver *drv,
                struct module *module, const char *mod_name);
 #define dax_driver_register(driver) \
index c3a12170083737f1da6dd51311d64f17d0c50946..a82ce48f588448fde6c4e1eb0557d6b899fd8f5a 100644 (file)
@@ -42,15 +42,22 @@ struct dax_region {
 };
 
 /**
- * struct dev_dax - instance data for a subdivision of a dax region
+ * struct dev_dax - instance data for a subdivision of a dax region, and
+ * data while the device is activated in the driver.
  * @region - parent region
  * @dax_dev - core dax functionality
  * @dev - device core
+ * @pgmap - pgmap for memmap setup / lifetime (driver owned)
+ * @ref: pgmap reference count (driver owned)
+ * @cmp: @ref final put completion (driver owned)
  */
 struct dev_dax {
        struct dax_region *region;
        struct dax_device *dax_dev;
        struct device dev;
+       struct dev_pagemap pgmap;
+       struct percpu_ref ref;
+       struct completion cmp;
 };
 
 static inline struct dev_dax *to_dev_dax(struct device *dev)
index f55829404a241cdad873027e8007c9ef3a20c59b..6ad964d7b07799c7600bf78e70e257673a5eb81a 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright(c) 2016-2018 Intel Corporation. All rights reserved. */
+#include <linux/memremap.h>
 #include <linux/pagemap.h>
 #include <linux/module.h>
 #include <linux/device.h>
 #include "dax-private.h"
 #include "bus.h"
 
+static struct dev_dax *ref_to_dev_dax(struct percpu_ref *ref)
+{
+       return container_of(ref, struct dev_dax, ref);
+}
+
+static void dev_dax_percpu_release(struct percpu_ref *ref)
+{
+       struct dev_dax *dev_dax = ref_to_dev_dax(ref);
+
+       dev_dbg(&dev_dax->dev, "%s\n", __func__);
+       complete(&dev_dax->cmp);
+}
+
+static void dev_dax_percpu_exit(void *data)
+{
+       struct percpu_ref *ref = data;
+       struct dev_dax *dev_dax = ref_to_dev_dax(ref);
+
+       dev_dbg(&dev_dax->dev, "%s\n", __func__);
+       wait_for_completion(&dev_dax->cmp);
+       percpu_ref_exit(ref);
+}
+
+static void dev_dax_percpu_kill(struct percpu_ref *data)
+{
+       struct percpu_ref *ref = data;
+       struct dev_dax *dev_dax = ref_to_dev_dax(ref);
+
+       dev_dbg(&dev_dax->dev, "%s\n", __func__);
+       percpu_ref_kill(ref);
+}
+
 static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma,
                const char *func)
 {
@@ -416,10 +449,38 @@ static int dev_dax_probe(struct device *dev)
 {
        struct dev_dax *dev_dax = to_dev_dax(dev);
        struct dax_device *dax_dev = dev_dax->dax_dev;
+       struct resource *res = &dev_dax->region->res;
        struct inode *inode;
        struct cdev *cdev;
+       void *addr;
        int rc;
 
+       /* 1:1 map region resource range to device-dax instance range */
+       if (!devm_request_mem_region(dev, res->start, resource_size(res),
+                               dev_name(dev))) {
+               dev_warn(dev, "could not reserve region %pR\n", res);
+               return -EBUSY;
+       }
+
+       init_completion(&dev_dax->cmp);
+       rc = percpu_ref_init(&dev_dax->ref, dev_dax_percpu_release, 0,
+                       GFP_KERNEL);
+       if (rc)
+               return rc;
+
+       rc = devm_add_action_or_reset(dev, dev_dax_percpu_exit, &dev_dax->ref);
+       if (rc)
+               return rc;
+
+       dev_dax->pgmap.ref = &dev_dax->ref;
+       dev_dax->pgmap.kill = dev_dax_percpu_kill;
+       addr = devm_memremap_pages(dev, &dev_dax->pgmap);
+       if (IS_ERR(addr)) {
+               devm_remove_action(dev, dev_dax_percpu_exit, &dev_dax->ref);
+               percpu_ref_exit(&dev_dax->ref);
+               return PTR_ERR(addr);
+       }
+
        inode = dax_inode(dax_dev);
        cdev = inode->i_cdev;
        cdev_init(cdev, &dax_fops);
index e1b50d8fd1f8a3a4c2711ba41c457886c2762fdf..d3cefa7868ac7d81eb111eee7bce4acdb045e9a0 100644 (file)
 #include "../nvdimm/nd.h"
 #include "bus.h"
 
-struct dax_pmem {
-       struct device *dev;
-       struct percpu_ref ref;
-       struct dev_pagemap pgmap;
-       struct completion cmp;
-};
-
-static struct dax_pmem *to_dax_pmem(struct percpu_ref *ref)
-{
-       return container_of(ref, struct dax_pmem, ref);
-}
-
-static void dax_pmem_percpu_release(struct percpu_ref *ref)
-{
-       struct dax_pmem *dax_pmem = to_dax_pmem(ref);
-
-       dev_dbg(dax_pmem->dev, "trace\n");
-       complete(&dax_pmem->cmp);
-}
-
-static void dax_pmem_percpu_exit(void *data)
-{
-       struct percpu_ref *ref = data;
-       struct dax_pmem *dax_pmem = to_dax_pmem(ref);
-
-       dev_dbg(dax_pmem->dev, "trace\n");
-       wait_for_completion(&dax_pmem->cmp);
-       percpu_ref_exit(ref);
-}
-
-static void dax_pmem_percpu_kill(struct percpu_ref *ref)
-{
-       struct dax_pmem *dax_pmem = to_dax_pmem(ref);
-
-       dev_dbg(dax_pmem->dev, "trace\n");
-       percpu_ref_kill(ref);
-}
-
 static int dax_pmem_probe(struct device *dev)
 {
-       void *addr;
        struct resource res;
        int rc, id, region_id;
+       resource_size_t offset;
        struct nd_pfn_sb *pfn_sb;
        struct dev_dax *dev_dax;
-       struct dax_pmem *dax_pmem;
        struct nd_namespace_io *nsio;
        struct dax_region *dax_region;
+       struct dev_pagemap pgmap = { 0 };
        struct nd_namespace_common *ndns;
        struct nd_dax *nd_dax = to_nd_dax(dev);
        struct nd_pfn *nd_pfn = &nd_dax->nd_pfn;
@@ -75,61 +37,37 @@ static int dax_pmem_probe(struct device *dev)
                return PTR_ERR(ndns);
        nsio = to_nd_namespace_io(&ndns->dev);
 
-       dax_pmem = devm_kzalloc(dev, sizeof(*dax_pmem), GFP_KERNEL);
-       if (!dax_pmem)
-               return -ENOMEM;
-
        /* parse the 'pfn' info block via ->rw_bytes */
        rc = devm_nsio_enable(dev, nsio);
        if (rc)
                return rc;
-       rc = nvdimm_setup_pfn(nd_pfn, &dax_pmem->pgmap);
+       rc = nvdimm_setup_pfn(nd_pfn, &pgmap);
        if (rc)
                return rc;
        devm_nsio_disable(dev, nsio);
 
-       pfn_sb = nd_pfn->pfn_sb;
-
-       if (!devm_request_mem_region(dev, nsio->res.start,
-                               resource_size(&nsio->res),
+       /* reserve the metadata area, device-dax will reserve the data */
+        pfn_sb = nd_pfn->pfn_sb;
+       offset = le64_to_cpu(pfn_sb->dataoff);
+       if (!devm_request_mem_region(dev, nsio->res.start, offset,
                                dev_name(&ndns->dev))) {
-               dev_warn(dev, "could not reserve region %pR\n", &nsio->res);
-               return -EBUSY;
-       }
-
-       dax_pmem->dev = dev;
-       init_completion(&dax_pmem->cmp);
-       rc = percpu_ref_init(&dax_pmem->ref, dax_pmem_percpu_release, 0,
-                       GFP_KERNEL);
-       if (rc)
-               return rc;
-
-       rc = devm_add_action(dev, dax_pmem_percpu_exit, &dax_pmem->ref);
-       if (rc) {
-               percpu_ref_exit(&dax_pmem->ref);
-               return rc;
-       }
-
-       dax_pmem->pgmap.ref = &dax_pmem->ref;
-       dax_pmem->pgmap.kill = dax_pmem_percpu_kill;
-       addr = devm_memremap_pages(dev, &dax_pmem->pgmap);
-       if (IS_ERR(addr))
-               return PTR_ERR(addr);
-
-       /* adjust the dax_region resource to the start of data */
-       memcpy(&res, &dax_pmem->pgmap.res, sizeof(res));
-       res.start += le64_to_cpu(pfn_sb->dataoff);
+                dev_warn(dev, "could not reserve metadata\n");
+                return -EBUSY;
+        }
 
        rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", &region_id, &id);
        if (rc != 2)
                return -EINVAL;
 
+       /* adjust the dax_region resource to the start of data */
+       memcpy(&res, &pgmap.res, sizeof(res));
+       res.start += offset;
        dax_region = alloc_dax_region(dev, region_id, &res,
                        le32_to_cpu(pfn_sb->align), PFN_DEV|PFN_MAP);
        if (!dax_region)
                return -ENOMEM;
 
-       dev_dax = devm_create_dev_dax(dax_region, id);
+       dev_dax = devm_create_dev_dax(dax_region, id, &pgmap);
 
        /* child dev_dax instances now own the lifetime of the dax_region */
        dax_region_put(dax_region);