linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/13] prep for device-dax, untangle pfn-device setup
@ 2016-03-24  1:25 Dan Williams
  2016-03-24  1:25 ` [PATCH 01/13] libnvdimm, pfn: fix nvdimm_namespace_add_poison() vs section alignment Dan Williams
                   ` (12 more replies)
  0 siblings, 13 replies; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:25 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vishal Verma, Ross Zwisler, linux-kernel, stable

The infrastructure for setting up a pfn-device (struct page memmap array
allocation for reserved memory) is generally useful.  Untangle it from
the pmem driver and make it available as core libnvdimm functionality.
The motivation for this work is an investigation into a standalone
device-dax facility, but the changes stand on their own.

Outside of exporting nvdimm_setup_pfn() as a generic facility this also
includes the following benefits:

1/ fix a section alignment vs badblocks tracking bug

2/ struct pmem_device sheds 24 bytes

3/ struct blk_device is replaced with some (smaller in total) extensions
   to struct nd_namespace_blk.

4/ Reduce pointer chasing by retrieving driver private data from
   ->queuedata rather than bio->bi_bdev->bd_disk->private_data.

---

Dan Williams (13):
      libnvdimm, pfn: fix nvdimm_namespace_add_poison() vs section alignment
      libnvdimm, pmem: kill pmem->ndns
      libnvdimm, pfn, convert nd_pfn_probe() to devm
      libnvdimm, btt, convert nd_btt_probe() to devm
      libnvdimm, blk: use devm_add_action to release bdev resources
      libnvdimm, blk: use ->queuedata for driver private data
      libnvdimm, pmem: use ->queuedata for driver private data
      libnvdimm, blk: move i/o infrastructure to nd_namespace_blk
      libnvdimm, pmem: use devm_add_action to release bdev resources
      libnvdimm, pmem: clean up resource print / request
      libnvdimm, pmem, pfn: make pmem_rw_bytes generic and refactor pfn setup
      libnvdimm, pmem, pfn: move pfn setup to the core
      libnvdimm, pmem: kill ->pmem_queue and ->pmem_disk


 drivers/nvdimm/blk.c              |  208 ++++++++--------
 drivers/nvdimm/btt.c              |   20 +-
 drivers/nvdimm/btt_devs.c         |   24 +-
 drivers/nvdimm/claim.c            |   61 +++++
 drivers/nvdimm/core.c             |   41 ++-
 drivers/nvdimm/nd.h               |   50 +++-
 drivers/nvdimm/pfn_devs.c         |  208 +++++++++++++++-
 drivers/nvdimm/pmem.c             |  475 +++++++++----------------------------
 include/linux/nd.h                |   11 +
 tools/testing/nvdimm/Kbuild       |    1 
 tools/testing/nvdimm/test/iomap.c |   27 ++
 11 files changed, 579 insertions(+), 547 deletions(-)

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 01/13] libnvdimm, pfn: fix nvdimm_namespace_add_poison() vs section alignment
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
@ 2016-03-24  1:25 ` Dan Williams
  2016-03-24 10:10   ` Johannes Thumshirn
  2016-03-24  1:25 ` [PATCH 02/13] libnvdimm, pmem: kill pmem->ndns Dan Williams
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:25 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vishal Verma, linux-kernel, stable

When section alignment padding is in effect we need to shift / truncate
the range that is queried for poison by the 'start_pad' or 'end_trunc'
reservations.

It's easiest if we just pass in an adjusted resource range rather than
deriving it from the passed in namespace.  With the resource range
resolution pushed out to the caller we can also push the
namespace-to-region lookup to the caller and drop the implicit pmem-type
assumption about the passed in namespace object.

Cc: Vishal Verma <vishal.l.verma@intel.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/core.c |   41 ++++++++++++++++++++---------------------
 drivers/nvdimm/nd.h   |    4 ++--
 drivers/nvdimm/pmem.c |   36 +++++++++++++++++++++++++++++-------
 3 files changed, 51 insertions(+), 30 deletions(-)

diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
index 79646d0c3277..182a93fe3712 100644
--- a/drivers/nvdimm/core.c
+++ b/drivers/nvdimm/core.c
@@ -417,8 +417,8 @@ static void __add_badblock_range(struct badblocks *bb, u64 ns_offset, u64 len)
 		set_badblock(bb, start_sector, num_sectors);
 }
 
-static void namespace_add_poison(struct list_head *poison_list,
-		struct badblocks *bb, struct resource *res)
+static void badblocks_populate(struct list_head *poison_list,
+		struct badblocks *bb, const struct resource *res)
 {
 	struct nd_poison *pl;
 
@@ -460,36 +460,35 @@ static void namespace_add_poison(struct list_head *poison_list,
 }
 
 /**
- * nvdimm_namespace_add_poison() - Convert a list of poison ranges to badblocks
- * @ndns:	the namespace containing poison ranges
- * @bb:		badblocks instance to populate
- * @offset:	offset at the start of the namespace before 'sector 0'
+ * nvdimm_badblocks_populate() - Convert a list of poison ranges to badblocks
+ * @region: parent region of the range to interrogate
+ * @bb: badblocks instance to populate
+ * @res: resource range to consider
  *
- * The poison list generated during NFIT initialization may contain multiple,
- * possibly overlapping ranges in the SPA (System Physical Address) space.
- * Compare each of these ranges to the namespace currently being initialized,
- * and add badblocks to the gendisk for all matching sub-ranges
+ * The poison list generated during bus initialization may contain
+ * multiple, possibly overlapping physical address ranges.  Compare each
+ * of these ranges to the resource range currently being initialized,
+ * and add badblocks entries for all matching sub-ranges
  */
-void nvdimm_namespace_add_poison(struct nd_namespace_common *ndns,
-		struct badblocks *bb, resource_size_t offset)
+void nvdimm_badblocks_populate(struct nd_region *nd_region,
+		struct badblocks *bb, const struct resource *res)
 {
-	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
-	struct nd_region *nd_region = to_nd_region(ndns->dev.parent);
 	struct nvdimm_bus *nvdimm_bus;
 	struct list_head *poison_list;
-	struct resource res = {
-		.start = nsio->res.start + offset,
-		.end = nsio->res.end,
-	};
 
-	nvdimm_bus = to_nvdimm_bus(nd_region->dev.parent);
+	if (!is_nd_pmem(&nd_region->dev)) {
+		dev_WARN_ONCE(&nd_region->dev, 1,
+				"%s only valid for pmem regions\n", __func__);
+		return;
+	}
+	nvdimm_bus = walk_to_nvdimm_bus(&nd_region->dev);
 	poison_list = &nvdimm_bus->poison_list;
 
 	nvdimm_bus_lock(&nvdimm_bus->dev);
-	namespace_add_poison(poison_list, bb, &res);
+	badblocks_populate(poison_list, bb, res);
 	nvdimm_bus_unlock(&nvdimm_bus->dev);
 }
-EXPORT_SYMBOL_GPL(nvdimm_namespace_add_poison);
+EXPORT_SYMBOL_GPL(nvdimm_badblocks_populate);
 
 static int add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
 {
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 1799bd97a9ce..875c524fafb0 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -266,8 +266,8 @@ int nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns);
 int nvdimm_namespace_detach_btt(struct nd_namespace_common *ndns);
 const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns,
 		char *name);
-void nvdimm_namespace_add_poison(struct nd_namespace_common *ndns,
-		struct badblocks *bb, resource_size_t offset);
+void nvdimm_badblocks_populate(struct nd_region *nd_region,
+		struct badblocks *bb, const struct resource *res);
 int nd_blk_region_init(struct nd_region *nd_region);
 void __nd_iostat_start(struct bio *bio, unsigned long *start);
 static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index ca5721c306bb..e27a293bd9cc 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -244,7 +244,9 @@ static void pmem_detach_disk(struct pmem_device *pmem)
 static int pmem_attach_disk(struct device *dev,
 		struct nd_namespace_common *ndns, struct pmem_device *pmem)
 {
+	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
 	int nid = dev_to_node(dev);
+	struct resource bb_res;
 	struct gendisk *disk;
 
 	blk_queue_make_request(pmem->pmem_queue, pmem_make_request);
@@ -271,8 +273,17 @@ static int pmem_attach_disk(struct device *dev,
 	devm_exit_badblocks(dev, &pmem->bb);
 	if (devm_init_badblocks(dev, &pmem->bb))
 		return -ENOMEM;
-	nvdimm_namespace_add_poison(ndns, &pmem->bb, pmem->data_offset);
-
+	bb_res.start = nsio->res.start + pmem->data_offset;
+	bb_res.end = nsio->res.end;
+	if (is_nd_pfn(dev)) {
+		struct nd_pfn *nd_pfn = to_nd_pfn(dev);
+		struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
+
+		bb_res.start += __le32_to_cpu(pfn_sb->start_pad);
+		bb_res.end -= __le32_to_cpu(pfn_sb->end_trunc);
+	}
+	nvdimm_badblocks_populate(to_nd_region(dev->parent), &pmem->bb,
+			&bb_res);
 	disk->bb = &pmem->bb;
 	add_disk(disk);
 	revalidate_disk(disk);
@@ -553,7 +564,7 @@ static int nd_pmem_probe(struct device *dev)
 	ndns->rw_bytes = pmem_rw_bytes;
 	if (devm_init_badblocks(dev, &pmem->bb))
 		return -ENOMEM;
-	nvdimm_namespace_add_poison(ndns, &pmem->bb, 0);
+	nvdimm_badblocks_populate(nd_region, &pmem->bb, &nsio->res);
 
 	if (is_nd_btt(dev)) {
 		/* btt allocates its own request_queue */
@@ -595,14 +606,25 @@ 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;
+	struct nd_region *nd_region = to_nd_region(dev->parent);
+	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+	struct resource res = {
+		.start = nsio->res.start + pmem->data_offset,
+		.end = nsio->res.end,
+	};
 
 	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);
+	if (is_nd_pfn(dev)) {
+		struct nd_pfn *nd_pfn = to_nd_pfn(dev);
+		struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
+
+		res.start += __le32_to_cpu(pfn_sb->start_pad);
+		res.end -= __le32_to_cpu(pfn_sb->end_trunc);
+	}
+
+	nvdimm_badblocks_populate(nd_region, &pmem->bb, &res);
 }
 
 MODULE_ALIAS("pmem");

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 02/13] libnvdimm, pmem: kill pmem->ndns
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
  2016-03-24  1:25 ` [PATCH 01/13] libnvdimm, pfn: fix nvdimm_namespace_add_poison() vs section alignment Dan Williams
@ 2016-03-24  1:25 ` Dan Williams
  2016-03-24 10:31   ` Johannes Thumshirn
  2016-03-24  1:25 ` [PATCH 03/13] libnvdimm, pfn, convert nd_pfn_probe() to devm Dan Williams
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:25 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: linux-kernel

We can derive the common namespace from other information.  We also do
not need to cache it because all the usages are in slow paths.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/blk.c  |    2 +-
 drivers/nvdimm/btt.c  |    3 +--
 drivers/nvdimm/nd.h   |    2 +-
 drivers/nvdimm/pmem.c |   40 ++++++++++++++++++++++------------------
 4 files changed, 25 insertions(+), 22 deletions(-)

diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
index e9ff9229d942..24649396b638 100644
--- a/drivers/nvdimm/blk.c
+++ b/drivers/nvdimm/blk.c
@@ -336,7 +336,7 @@ static int nd_blk_remove(struct device *dev)
 	struct nd_blk_device *blk_dev = dev_get_drvdata(dev);
 
 	if (is_nd_btt(dev))
-		nvdimm_namespace_detach_btt(to_nd_btt(dev)->ndns);
+		nvdimm_namespace_detach_btt(to_nd_btt(dev));
 	else
 		nd_blk_detach_disk(blk_dev);
 	kfree(blk_dev);
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index c32cbb593600..48e036621d05 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -1406,9 +1406,8 @@ int nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns)
 }
 EXPORT_SYMBOL(nvdimm_namespace_attach_btt);
 
-int nvdimm_namespace_detach_btt(struct nd_namespace_common *ndns)
+int nvdimm_namespace_detach_btt(struct nd_btt *nd_btt)
 {
-	struct nd_btt *nd_btt = to_nd_btt(ndns->claim);
 	struct btt *btt = nd_btt->btt;
 
 	btt_fini(btt);
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 875c524fafb0..b0a4ab91307b 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -263,7 +263,7 @@ struct resource *nvdimm_allocate_dpa(struct nvdimm_drvdata *ndd,
 resource_size_t nvdimm_namespace_capacity(struct nd_namespace_common *ndns);
 struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev);
 int nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns);
-int nvdimm_namespace_detach_btt(struct nd_namespace_common *ndns);
+int nvdimm_namespace_detach_btt(struct nd_btt *nd_btt);
 const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns,
 		char *name);
 void nvdimm_badblocks_populate(struct nd_region *nd_region,
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index e27a293bd9cc..b13b9095f620 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -35,7 +35,6 @@
 struct pmem_device {
 	struct request_queue	*pmem_queue;
 	struct gendisk		*pmem_disk;
-	struct nd_namespace_common *ndns;
 
 	/* One contiguous memory region per device */
 	phys_addr_t		phys_addr;
@@ -422,9 +421,8 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
 	return -ENXIO;
 }
 
-static int nvdimm_namespace_detach_pfn(struct nd_namespace_common *ndns)
+static int nvdimm_namespace_detach_pfn(struct nd_pfn *nd_pfn)
 {
-	struct nd_pfn *nd_pfn = to_nd_pfn(ndns->claim);
 	struct pmem_device *pmem;
 
 	/* free pmem disk */
@@ -523,7 +521,7 @@ static int __nvdimm_namespace_attach_pfn(struct nd_pfn *nd_pfn)
 
 	return rc;
  err:
-	nvdimm_namespace_detach_pfn(ndns);
+	nvdimm_namespace_detach_pfn(nd_pfn);
 	return rc;
 
 }
@@ -559,7 +557,6 @@ static int nd_pmem_probe(struct device *dev)
 	if (IS_ERR(pmem))
 		return PTR_ERR(pmem);
 
-	pmem->ndns = ndns;
 	dev_set_drvdata(dev, pmem);
 	ndns->rw_bytes = pmem_rw_bytes;
 	if (devm_init_badblocks(dev, &pmem->bb))
@@ -593,9 +590,9 @@ static int nd_pmem_remove(struct device *dev)
 	struct pmem_device *pmem = dev_get_drvdata(dev);
 
 	if (is_nd_btt(dev))
-		nvdimm_namespace_detach_btt(pmem->ndns);
+		nvdimm_namespace_detach_btt(to_nd_btt(dev));
 	else if (is_nd_pfn(dev))
-		nvdimm_namespace_detach_pfn(pmem->ndns);
+		nvdimm_namespace_detach_pfn(to_nd_pfn(dev));
 	else
 		pmem_detach_disk(pmem);
 
@@ -604,26 +601,33 @@ static int nd_pmem_remove(struct device *dev)
 
 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;
 	struct nd_region *nd_region = to_nd_region(dev->parent);
-	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
-	struct resource res = {
-		.start = nsio->res.start + pmem->data_offset,
-		.end = nsio->res.end,
-	};
+	struct pmem_device *pmem = dev_get_drvdata(dev);
+	resource_size_t offset = 0, end_trunc = 0;
+	struct nd_namespace_common *ndns;
+	struct nd_namespace_io *nsio;
+	struct resource res;
 
 	if (event != NVDIMM_REVALIDATE_POISON)
 		return;
 
-	if (is_nd_pfn(dev)) {
+	if (is_nd_btt(dev)) {
+		struct nd_btt *nd_btt = to_nd_btt(dev);
+
+		ndns = nd_btt->ndns;
+	} else if (is_nd_pfn(dev)) {
 		struct nd_pfn *nd_pfn = to_nd_pfn(dev);
 		struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
 
-		res.start += __le32_to_cpu(pfn_sb->start_pad);
-		res.end -= __le32_to_cpu(pfn_sb->end_trunc);
-	}
+		ndns = nd_pfn->ndns;
+		offset = pmem->data_offset + __le32_to_cpu(pfn_sb->start_pad);
+		end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
+	} else
+		ndns = to_ndns(dev);
 
+	nsio = to_nd_namespace_io(&ndns->dev);
+	res.start = nsio->res.start + offset;
+	res.end = nsio->res.end - end_trunc;
 	nvdimm_badblocks_populate(nd_region, &pmem->bb, &res);
 }
 

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 03/13] libnvdimm, pfn, convert nd_pfn_probe() to devm
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
  2016-03-24  1:25 ` [PATCH 01/13] libnvdimm, pfn: fix nvdimm_namespace_add_poison() vs section alignment Dan Williams
  2016-03-24  1:25 ` [PATCH 02/13] libnvdimm, pmem: kill pmem->ndns Dan Williams
@ 2016-03-24  1:25 ` Dan Williams
  2016-03-24 10:45   ` Johannes Thumshirn
  2016-03-24  1:25 ` [PATCH 04/13] libnvdimm, btt, convert nd_btt_probe() " Dan Williams
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:25 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Ross Zwisler, linux-kernel

Pass the device performing the probe so we can use a devm allocation for
the pfn superblock.

Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/nd.h       |    6 ++++--
 drivers/nvdimm/pfn_devs.c |   27 +++++++++++++--------------
 drivers/nvdimm/pmem.c     |   30 +++++++++---------------------
 3 files changed, 26 insertions(+), 37 deletions(-)

diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index b0a4ab91307b..c831caa3d60a 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -219,12 +219,14 @@ static inline struct device *nd_btt_create(struct nd_region *nd_region)
 
 struct nd_pfn *to_nd_pfn(struct device *dev);
 #if IS_ENABLED(CONFIG_NVDIMM_PFN)
-int nd_pfn_probe(struct nd_namespace_common *ndns, void *drvdata);
+int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
+		void *drvdata);
 bool is_nd_pfn(struct device *dev);
 struct device *nd_pfn_create(struct nd_region *nd_region);
 int nd_pfn_validate(struct nd_pfn *nd_pfn);
 #else
-static inline int nd_pfn_probe(struct nd_namespace_common *ndns, void *drvdata)
+static inline int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
+		void *drvdata)
 {
 	return -ENODEV;
 }
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 254d3bc13f70..63e2df3e052c 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -410,11 +410,12 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn)
 }
 EXPORT_SYMBOL(nd_pfn_validate);
 
-int nd_pfn_probe(struct nd_namespace_common *ndns, void *drvdata)
+int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
+		void *drvdata)
 {
 	int rc;
-	struct device *dev;
 	struct nd_pfn *nd_pfn;
+	struct device *pfn_dev;
 	struct nd_pfn_sb *pfn_sb;
 	struct nd_region *nd_region = to_nd_region(ndns->dev.parent);
 
@@ -422,24 +423,22 @@ int nd_pfn_probe(struct nd_namespace_common *ndns, void *drvdata)
 		return -ENODEV;
 
 	nvdimm_bus_lock(&ndns->dev);
-	dev = __nd_pfn_create(nd_region, ndns);
+	pfn_dev = __nd_pfn_create(nd_region, ndns);
 	nvdimm_bus_unlock(&ndns->dev);
-	if (!dev)
+	if (!pfn_dev)
 		return -ENOMEM;
-	dev_set_drvdata(dev, drvdata);
-	pfn_sb = kzalloc(sizeof(*pfn_sb), GFP_KERNEL);
-	nd_pfn = to_nd_pfn(dev);
+	dev_set_drvdata(pfn_dev, drvdata);
+	pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
+	nd_pfn = to_nd_pfn(pfn_dev);
 	nd_pfn->pfn_sb = pfn_sb;
 	rc = nd_pfn_validate(nd_pfn);
-	nd_pfn->pfn_sb = NULL;
-	kfree(pfn_sb);
-	dev_dbg(&ndns->dev, "%s: pfn: %s\n", __func__,
-			rc == 0 ? dev_name(dev) : "<none>");
+	dev_dbg(dev, "%s: pfn: %s\n", __func__,
+			rc == 0 ? dev_name(pfn_dev) : "<none>");
 	if (rc < 0) {
-		__nd_detach_ndns(dev, &nd_pfn->ndns);
-		put_device(dev);
+		__nd_detach_ndns(pfn_dev, &nd_pfn->ndns);
+		put_device(pfn_dev);
 	} else
-		__nd_device_register(&nd_pfn->dev);
+		__nd_device_register(pfn_dev);
 
 	return rc;
 }
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index b13b9095f620..77d94b42c32f 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -316,18 +316,19 @@ static int pmem_rw_bytes(struct nd_namespace_common *ndns,
 
 static int nd_pfn_init(struct nd_pfn *nd_pfn)
 {
-	struct nd_pfn_sb *pfn_sb = kzalloc(sizeof(*pfn_sb), GFP_KERNEL);
 	struct pmem_device *pmem = dev_get_drvdata(&nd_pfn->dev);
 	struct nd_namespace_common *ndns = nd_pfn->ndns;
 	u32 start_pad = 0, end_trunc = 0;
 	resource_size_t start, size;
 	struct nd_namespace_io *nsio;
 	struct nd_region *nd_region;
+	struct nd_pfn_sb *pfn_sb;
 	unsigned long npfns;
 	phys_addr_t offset;
 	u64 checksum;
 	int rc;
 
+	pfn_sb = devm_kzalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
 	if (!pfn_sb)
 		return -ENOMEM;
 
@@ -343,7 +344,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
 		dev_info(&nd_pfn->dev,
 				"%s is read-only, unable to init metadata\n",
 				dev_name(&nd_region->dev));
-		goto err;
+		return -ENXIO;
 	}
 
 	memset(pfn_sb, 0, sizeof(*pfn_sb));
@@ -388,12 +389,12 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
 	else if (nd_pfn->mode == PFN_MODE_RAM)
 		offset = ALIGN(start + SZ_8K, nd_pfn->align) - start;
 	else
-		goto err;
+		return -ENXIO;
 
 	if (offset + start_pad + end_trunc >= pmem->size) {
 		dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
 				dev_name(&ndns->dev));
-		goto err;
+		return -ENXIO;
 	}
 
 	npfns = (pmem->size - offset - start_pad - end_trunc) / SZ_4K;
@@ -410,30 +411,16 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
 	checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
 	pfn_sb->checksum = cpu_to_le64(checksum);
 
-	rc = nvdimm_write_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb));
-	if (rc)
-		goto err;
-
-	return 0;
- err:
-	nd_pfn->pfn_sb = NULL;
-	kfree(pfn_sb);
-	return -ENXIO;
+	return nvdimm_write_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb));
 }
 
-static int nvdimm_namespace_detach_pfn(struct nd_pfn *nd_pfn)
+static void nvdimm_namespace_detach_pfn(struct nd_pfn *nd_pfn)
 {
 	struct pmem_device *pmem;
 
 	/* free pmem disk */
 	pmem = dev_get_drvdata(&nd_pfn->dev);
 	pmem_detach_disk(pmem);
-
-	/* release nd_pfn resources */
-	kfree(nd_pfn->pfn_sb);
-	nd_pfn->pfn_sb = NULL;
-
-	return 0;
 }
 
 /*
@@ -573,7 +560,8 @@ static int nd_pmem_probe(struct device *dev)
 	if (is_nd_pfn(dev))
 		return nvdimm_namespace_attach_pfn(ndns);
 
-	if (nd_btt_probe(ndns, pmem) == 0 || nd_pfn_probe(ndns, pmem) == 0) {
+	if (nd_btt_probe(ndns, pmem) == 0
+			|| nd_pfn_probe(dev, ndns, pmem) == 0) {
 		/*
 		 * We'll come back as either btt-pmem, or pfn-pmem, so
 		 * drop the queue allocation for now.

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 04/13] libnvdimm, btt, convert nd_btt_probe() to devm
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
                   ` (2 preceding siblings ...)
  2016-03-24  1:25 ` [PATCH 03/13] libnvdimm, pfn, convert nd_pfn_probe() to devm Dan Williams
@ 2016-03-24  1:25 ` Dan Williams
  2016-03-24 11:05   ` Johannes Thumshirn
  2016-03-24  1:25 ` [PATCH 05/13] libnvdimm, blk: use devm_add_action to release bdev resources Dan Williams
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:25 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vishal Verma, linux-kernel

Pass the device performing the probe so we can use a devm allocation for
the btt superblock.

Cc: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/blk.c      |    2 +-
 drivers/nvdimm/btt.c      |   17 ++++++-----------
 drivers/nvdimm/btt_devs.c |   26 +++++++++++++-------------
 drivers/nvdimm/nd.h       |    6 ++++--
 drivers/nvdimm/pmem.c     |    2 +-
 5 files changed, 25 insertions(+), 28 deletions(-)

diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
index 24649396b638..c8215dc356cc 100644
--- a/drivers/nvdimm/blk.c
+++ b/drivers/nvdimm/blk.c
@@ -314,7 +314,7 @@ static int nd_blk_probe(struct device *dev)
 	ndns->rw_bytes = nd_blk_rw_bytes;
 	if (is_nd_btt(dev))
 		rc = nvdimm_namespace_attach_btt(ndns);
-	else if (nd_btt_probe(ndns, blk_dev) == 0) {
+	else if (nd_btt_probe(dev, ndns, blk_dev) == 0) {
 		/* we'll come back as btt-blk */
 		rc = -ENXIO;
 	} else
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 48e036621d05..a5ebbff46655 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -1306,7 +1306,7 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize,
 	struct btt *btt;
 	struct device *dev = &nd_btt->dev;
 
-	btt = kzalloc(sizeof(struct btt), GFP_KERNEL);
+	btt = devm_kzalloc(dev, sizeof(struct btt), GFP_KERNEL);
 	if (!btt)
 		return NULL;
 
@@ -1321,13 +1321,13 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize,
 	ret = discover_arenas(btt);
 	if (ret) {
 		dev_err(dev, "init: error in arena_discover: %d\n", ret);
-		goto out_free;
+		return NULL;
 	}
 
 	if (btt->init_state != INIT_READY && nd_region->ro) {
 		dev_info(dev, "%s is read-only, unable to init btt metadata\n",
 				dev_name(&nd_region->dev));
-		goto out_free;
+		return NULL;
 	} else if (btt->init_state != INIT_READY) {
 		btt->num_arenas = (rawsize / ARENA_MAX_SIZE) +
 			((rawsize % ARENA_MAX_SIZE) ? 1 : 0);
@@ -1337,29 +1337,25 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize,
 		ret = create_arenas(btt);
 		if (ret) {
 			dev_info(dev, "init: create_arenas: %d\n", ret);
-			goto out_free;
+			return NULL;
 		}
 
 		ret = btt_meta_init(btt);
 		if (ret) {
 			dev_err(dev, "init: error in meta_init: %d\n", ret);
-			goto out_free;
+			return NULL;
 		}
 	}
 
 	ret = btt_blk_init(btt);
 	if (ret) {
 		dev_err(dev, "init: error in blk_init: %d\n", ret);
-		goto out_free;
+		return NULL;
 	}
 
 	btt_debugfs_init(btt);
 
 	return btt;
-
- out_free:
-	kfree(btt);
-	return NULL;
 }
 
 /**
@@ -1377,7 +1373,6 @@ static void btt_fini(struct btt *btt)
 		btt_blk_cleanup(btt);
 		free_arenas(btt);
 		debugfs_remove_recursive(btt->debugfs_dir);
-		kfree(btt);
 	}
 }
 
diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c
index cb477518dd0e..1886171af80e 100644
--- a/drivers/nvdimm/btt_devs.c
+++ b/drivers/nvdimm/btt_devs.c
@@ -273,10 +273,11 @@ static int __nd_btt_probe(struct nd_btt *nd_btt,
 	return 0;
 }
 
-int nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata)
+int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns,
+		void *drvdata)
 {
 	int rc;
-	struct device *dev;
+	struct device *btt_dev;
 	struct btt_sb *btt_sb;
 	struct nd_region *nd_region = to_nd_region(ndns->dev.parent);
 
@@ -284,21 +285,20 @@ int nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata)
 		return -ENODEV;
 
 	nvdimm_bus_lock(&ndns->dev);
-	dev = __nd_btt_create(nd_region, 0, NULL, ndns);
+	btt_dev = __nd_btt_create(nd_region, 0, NULL, ndns);
 	nvdimm_bus_unlock(&ndns->dev);
-	if (!dev)
+	if (!btt_dev)
 		return -ENOMEM;
-	dev_set_drvdata(dev, drvdata);
-	btt_sb = kzalloc(sizeof(*btt_sb), GFP_KERNEL);
-	rc = __nd_btt_probe(to_nd_btt(dev), ndns, btt_sb);
-	kfree(btt_sb);
-	dev_dbg(&ndns->dev, "%s: btt: %s\n", __func__,
-			rc == 0 ? dev_name(dev) : "<none>");
+	dev_set_drvdata(btt_dev, drvdata);
+	btt_sb = devm_kzalloc(dev, sizeof(*btt_sb), GFP_KERNEL);
+	rc = __nd_btt_probe(to_nd_btt(btt_dev), ndns, btt_sb);
+	dev_dbg(dev, "%s: btt: %s\n", __func__,
+			rc == 0 ? dev_name(btt_dev) : "<none>");
 	if (rc < 0) {
-		struct nd_btt *nd_btt = to_nd_btt(dev);
+		struct nd_btt *nd_btt = to_nd_btt(btt_dev);
 
-		__nd_detach_ndns(dev, &nd_btt->ndns);
-		put_device(dev);
+		__nd_detach_ndns(btt_dev, &nd_btt->ndns);
+		put_device(btt_dev);
 	}
 
 	return rc;
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index c831caa3d60a..0fb14890ba26 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -197,11 +197,13 @@ struct nd_gen_sb {
 
 u64 nd_sb_checksum(struct nd_gen_sb *sb);
 #if IS_ENABLED(CONFIG_BTT)
-int nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata);
+int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns,
+		void *drvdata);
 bool is_nd_btt(struct device *dev);
 struct device *nd_btt_create(struct nd_region *nd_region);
 #else
-static inline int nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata)
+static inline int nd_btt_probe(struct device *dev,
+		struct nd_namespace_common *ndns, void *drvdata)
 {
 	return -ENODEV;
 }
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 77d94b42c32f..1e492c66d105 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -560,7 +560,7 @@ static int nd_pmem_probe(struct device *dev)
 	if (is_nd_pfn(dev))
 		return nvdimm_namespace_attach_pfn(ndns);
 
-	if (nd_btt_probe(ndns, pmem) == 0
+	if (nd_btt_probe(dev, ndns, pmem) == 0
 			|| nd_pfn_probe(dev, ndns, pmem) == 0) {
 		/*
 		 * We'll come back as either btt-pmem, or pfn-pmem, so

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 05/13] libnvdimm, blk: use devm_add_action to release bdev resources
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
                   ` (3 preceding siblings ...)
  2016-03-24  1:25 ` [PATCH 04/13] libnvdimm, btt, convert nd_btt_probe() " Dan Williams
@ 2016-03-24  1:25 ` Dan Williams
  2016-03-24 11:48   ` Johannes Thumshirn
  2016-03-24  1:25 ` [PATCH 06/13] libnvdimm, blk: use ->queuedata for driver private data Dan Williams
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:25 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Ross Zwisler, linux-kernel

Register a callback to clean up the request_queue and put the gendisk at
driver disable time.

Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/blk.c |   77 +++++++++++++++++++++++---------------------------
 1 file changed, 36 insertions(+), 41 deletions(-)

diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
index c8215dc356cc..27ff32a5e9cf 100644
--- a/drivers/nvdimm/blk.c
+++ b/drivers/nvdimm/blk.c
@@ -22,8 +22,6 @@
 #include "nd.h"
 
 struct nd_blk_device {
-	struct request_queue *queue;
-	struct gendisk *disk;
 	struct nd_namespace_blk *nsblk;
 	struct nd_blk_region *ndbr;
 	size_t disk_size;
@@ -235,29 +233,47 @@ static const struct block_device_operations nd_blk_fops = {
 	.revalidate_disk = nvdimm_revalidate_disk,
 };
 
-static int nd_blk_attach_disk(struct nd_namespace_common *ndns,
-		struct nd_blk_device *blk_dev)
+static void nd_blk_release_queue(void *q)
+{
+	blk_cleanup_queue(q);
+}
+
+static void nd_blk_release_disk(void *disk)
+{
+	del_gendisk(disk);
+	put_disk(disk);
+}
+
+static int nd_blk_attach_disk(struct device *dev,
+		struct nd_namespace_common *ndns, struct nd_blk_device *blk_dev)
 {
 	resource_size_t available_disk_size;
+	struct request_queue *q;
 	struct gendisk *disk;
 	u64 internal_nlba;
 
 	internal_nlba = div_u64(blk_dev->disk_size, blk_dev->internal_lbasize);
 	available_disk_size = internal_nlba * blk_dev->sector_size;
 
-	blk_dev->queue = blk_alloc_queue(GFP_KERNEL);
-	if (!blk_dev->queue)
+	q = blk_alloc_queue(GFP_KERNEL);
+	if (!q)
+		return -ENOMEM;
+	if (devm_add_action(dev, nd_blk_release_queue, q)) {
+		blk_cleanup_queue(q);
 		return -ENOMEM;
+	}
 
-	blk_queue_make_request(blk_dev->queue, nd_blk_make_request);
-	blk_queue_max_hw_sectors(blk_dev->queue, UINT_MAX);
-	blk_queue_bounce_limit(blk_dev->queue, BLK_BOUNCE_ANY);
-	blk_queue_logical_block_size(blk_dev->queue, blk_dev->sector_size);
-	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, blk_dev->queue);
+	blk_queue_make_request(q, nd_blk_make_request);
+	blk_queue_max_hw_sectors(q, UINT_MAX);
+	blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
+	blk_queue_logical_block_size(q, blk_dev->sector_size);
+	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
 
-	disk = blk_dev->disk = alloc_disk(0);
-	if (!disk) {
-		blk_cleanup_queue(blk_dev->queue);
+	disk = alloc_disk(0);
+	if (!disk)
+		return -ENOMEM;
+	if (devm_add_action(dev, nd_blk_release_disk, disk)) {
+		put_disk(disk);
 		return -ENOMEM;
 	}
 
@@ -265,7 +281,7 @@ static int nd_blk_attach_disk(struct nd_namespace_common *ndns,
 	disk->first_minor	= 0;
 	disk->fops		= &nd_blk_fops;
 	disk->private_data	= blk_dev;
-	disk->queue		= blk_dev->queue;
+	disk->queue		= q;
 	disk->flags		= GENHD_FL_EXT_DEVT;
 	nvdimm_namespace_disk_name(ndns, disk->disk_name);
 	set_capacity(disk, 0);
@@ -274,12 +290,8 @@ static int nd_blk_attach_disk(struct nd_namespace_common *ndns,
 	if (nd_blk_meta_size(blk_dev)) {
 		int rc = nd_integrity_init(disk, nd_blk_meta_size(blk_dev));
 
-		if (rc) {
-			del_gendisk(disk);
-			put_disk(disk);
-			blk_cleanup_queue(blk_dev->queue);
+		if (rc)
 			return rc;
-		}
 	}
 
 	set_capacity(disk, available_disk_size >> SECTOR_SHIFT);
@@ -292,13 +304,12 @@ static int nd_blk_probe(struct device *dev)
 	struct nd_namespace_common *ndns;
 	struct nd_namespace_blk *nsblk;
 	struct nd_blk_device *blk_dev;
-	int rc;
 
 	ndns = nvdimm_namespace_common_probe(dev);
 	if (IS_ERR(ndns))
 		return PTR_ERR(ndns);
 
-	blk_dev = kzalloc(sizeof(*blk_dev), GFP_KERNEL);
+	blk_dev = devm_kzalloc(dev, sizeof(*blk_dev), GFP_KERNEL);
 	if (!blk_dev)
 		return -ENOMEM;
 
@@ -313,34 +324,18 @@ static int nd_blk_probe(struct device *dev)
 
 	ndns->rw_bytes = nd_blk_rw_bytes;
 	if (is_nd_btt(dev))
-		rc = nvdimm_namespace_attach_btt(ndns);
+		return nvdimm_namespace_attach_btt(ndns);
 	else if (nd_btt_probe(dev, ndns, blk_dev) == 0) {
 		/* we'll come back as btt-blk */
-		rc = -ENXIO;
+		return -ENXIO;
 	} else
-		rc = nd_blk_attach_disk(ndns, blk_dev);
-	if (rc)
-		kfree(blk_dev);
-	return rc;
-}
-
-static void nd_blk_detach_disk(struct nd_blk_device *blk_dev)
-{
-	del_gendisk(blk_dev->disk);
-	put_disk(blk_dev->disk);
-	blk_cleanup_queue(blk_dev->queue);
+		return nd_blk_attach_disk(dev, ndns, blk_dev);
 }
 
 static int nd_blk_remove(struct device *dev)
 {
-	struct nd_blk_device *blk_dev = dev_get_drvdata(dev);
-
 	if (is_nd_btt(dev))
 		nvdimm_namespace_detach_btt(to_nd_btt(dev));
-	else
-		nd_blk_detach_disk(blk_dev);
-	kfree(blk_dev);
-
 	return 0;
 }
 

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 06/13] libnvdimm, blk: use ->queuedata for driver private data
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
                   ` (4 preceding siblings ...)
  2016-03-24  1:25 ` [PATCH 05/13] libnvdimm, blk: use devm_add_action to release bdev resources Dan Williams
@ 2016-03-24  1:25 ` Dan Williams
  2016-03-24 11:51   ` Johannes Thumshirn
  2016-03-24  1:25 ` [PATCH 07/13] libnvdimm, pmem: " Dan Williams
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:25 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: linux-kernel

Save a pointer chase by storing the driver private data in the
request_queue rather than the gendisk.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/blk.c |    6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
index 27ff32a5e9cf..c8635b3d88a8 100644
--- a/drivers/nvdimm/blk.c
+++ b/drivers/nvdimm/blk.c
@@ -159,8 +159,6 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev,
 
 static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio)
 {
-	struct block_device *bdev = bio->bi_bdev;
-	struct gendisk *disk = bdev->bd_disk;
 	struct bio_integrity_payload *bip;
 	struct nd_blk_device *blk_dev;
 	struct bvec_iter iter;
@@ -181,7 +179,7 @@ static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio)
 	}
 
 	bip = bio_integrity(bio);
-	blk_dev = disk->private_data;
+	blk_dev = q->queuedata;
 	rw = bio_data_dir(bio);
 	do_acct = nd_iostat_start(bio, &start);
 	bio_for_each_segment(bvec, bio, iter) {
@@ -268,6 +266,7 @@ static int nd_blk_attach_disk(struct device *dev,
 	blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
 	blk_queue_logical_block_size(q, blk_dev->sector_size);
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
+	q->queuedata = blk_dev;
 
 	disk = alloc_disk(0);
 	if (!disk)
@@ -280,7 +279,6 @@ static int nd_blk_attach_disk(struct device *dev,
 	disk->driverfs_dev	= &ndns->dev;
 	disk->first_minor	= 0;
 	disk->fops		= &nd_blk_fops;
-	disk->private_data	= blk_dev;
 	disk->queue		= q;
 	disk->flags		= GENHD_FL_EXT_DEVT;
 	nvdimm_namespace_disk_name(ndns, disk->disk_name);

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 07/13] libnvdimm, pmem: use ->queuedata for driver private data
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
                   ` (5 preceding siblings ...)
  2016-03-24  1:25 ` [PATCH 06/13] libnvdimm, blk: use ->queuedata for driver private data Dan Williams
@ 2016-03-24  1:25 ` Dan Williams
  2016-03-24 12:06   ` Johannes Thumshirn
  2016-03-24  1:26 ` [PATCH 08/13] libnvdimm, blk: move i/o infrastructure to nd_namespace_blk Dan Williams
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:25 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: linux-kernel

Save a pointer chase by storing the driver private data in the
request_queue rather than the gendisk.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/pmem.c |    9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 1e492c66d105..ff336dd26064 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -121,8 +121,7 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
 	unsigned long start;
 	struct bio_vec bvec;
 	struct bvec_iter iter;
-	struct block_device *bdev = bio->bi_bdev;
-	struct pmem_device *pmem = bdev->bd_disk->private_data;
+	struct pmem_device *pmem = q->queuedata;
 
 	do_acct = nd_iostat_start(bio, &start);
 	bio_for_each_segment(bvec, bio, iter) {
@@ -147,7 +146,7 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
 static int pmem_rw_page(struct block_device *bdev, sector_t sector,
 		       struct page *page, int rw)
 {
-	struct pmem_device *pmem = bdev->bd_disk->private_data;
+	struct pmem_device *pmem = bdev->bd_queue->queuedata;
 	int rc;
 
 	rc = pmem_do_bvec(pmem, page, PAGE_CACHE_SIZE, 0, rw, sector);
@@ -169,7 +168,7 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
 static long pmem_direct_access(struct block_device *bdev, sector_t sector,
 		      void __pmem **kaddr, pfn_t *pfn)
 {
-	struct pmem_device *pmem = bdev->bd_disk->private_data;
+	struct pmem_device *pmem = bdev->bd_queue->queuedata;
 	resource_size_t offset = sector * 512 + pmem->data_offset;
 
 	*kaddr = pmem->virt_addr + offset;
@@ -253,6 +252,7 @@ static int pmem_attach_disk(struct device *dev,
 	blk_queue_max_hw_sectors(pmem->pmem_queue, UINT_MAX);
 	blk_queue_bounce_limit(pmem->pmem_queue, BLK_BOUNCE_ANY);
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, pmem->pmem_queue);
+	pmem->pmem_queue->queuedata = pmem;
 
 	disk = alloc_disk_node(0, nid);
 	if (!disk) {
@@ -261,7 +261,6 @@ static int pmem_attach_disk(struct device *dev,
 	}
 
 	disk->fops		= &pmem_fops;
-	disk->private_data	= pmem;
 	disk->queue		= pmem->pmem_queue;
 	disk->flags		= GENHD_FL_EXT_DEVT;
 	nvdimm_namespace_disk_name(ndns, disk->disk_name);

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 08/13] libnvdimm, blk: move i/o infrastructure to nd_namespace_blk
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
                   ` (6 preceding siblings ...)
  2016-03-24  1:25 ` [PATCH 07/13] libnvdimm, pmem: " Dan Williams
@ 2016-03-24  1:26 ` Dan Williams
  2016-03-24 12:22   ` Johannes Thumshirn
  2016-03-25 22:02   ` [PATCH v2] " Dan Williams
  2016-03-24  1:26 ` [PATCH 09/13] libnvdimm, pmem: use devm_add_action to release bdev resources Dan Williams
                   ` (4 subsequent siblings)
  12 siblings, 2 replies; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:26 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: linux-kernel

Consolidate the information for issuing i/o to a blk-namespace, and
eliminate some pointer chasing.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/blk.c |  137 +++++++++++++++++++++++++-------------------------
 include/linux/nd.h   |    2 +
 2 files changed, 71 insertions(+), 68 deletions(-)

diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
index c8635b3d88a8..4c14ecdc792b 100644
--- a/drivers/nvdimm/blk.c
+++ b/drivers/nvdimm/blk.c
@@ -21,17 +21,19 @@
 #include <linux/sizes.h>
 #include "nd.h"
 
-struct nd_blk_device {
-	struct nd_namespace_blk *nsblk;
-	struct nd_blk_region *ndbr;
-	size_t disk_size;
-	u32 sector_size;
-	u32 internal_lbasize;
-};
+static u32 nsblk_meta_size(struct nd_namespace_blk *nsblk)
+{
+	return nsblk->lbasize - ((nsblk->lbasize >= 4096) ? 4096 : 512);
+}
 
-static u32 nd_blk_meta_size(struct nd_blk_device *blk_dev)
+static u32 nsblk_internal_lbasize(struct nd_namespace_blk *nsblk)
 {
-	return blk_dev->nsblk->lbasize - blk_dev->sector_size;
+	return roundup(nsblk->lbasize, INT_LBASIZE_ALIGNMENT);
+}
+
+static u32 nsblk_sector_size(struct nd_namespace_blk *nsblk)
+{
+	return nsblk->lbasize - nsblk_meta_size(nsblk);
 }
 
 static resource_size_t to_dev_offset(struct nd_namespace_blk *nsblk,
@@ -55,20 +57,29 @@ static resource_size_t to_dev_offset(struct nd_namespace_blk *nsblk,
 	return SIZE_MAX;
 }
 
+static struct nd_blk_region *to_ndbr(struct nd_namespace_blk *nsblk)
+{
+	struct nd_region *nd_region;
+	struct device *parent;
+
+	parent = nsblk->common.dev.parent;
+	nd_region = container_of(parent, struct nd_region, dev);
+	return container_of(nd_region, struct nd_blk_region, nd_region);
+}
+
 #ifdef CONFIG_BLK_DEV_INTEGRITY
-static int nd_blk_rw_integrity(struct nd_blk_device *blk_dev,
-				struct bio_integrity_payload *bip, u64 lba,
-				int rw)
+static int nd_blk_rw_integrity(struct nd_namespace_blk *nsblk,
+		struct bio_integrity_payload *bip, u64 lba, int rw)
 {
-	unsigned int len = nd_blk_meta_size(blk_dev);
+	struct nd_blk_region *ndbr = to_ndbr(nsblk);
+	unsigned int len = nsblk_meta_size(nsblk);
 	resource_size_t	dev_offset, ns_offset;
-	struct nd_namespace_blk *nsblk;
-	struct nd_blk_region *ndbr;
+	u32 internal_lbasize, sector_size;
 	int err = 0;
 
-	nsblk = blk_dev->nsblk;
-	ndbr = blk_dev->ndbr;
-	ns_offset = lba * blk_dev->internal_lbasize + blk_dev->sector_size;
+	internal_lbasize = nsblk_internal_lbasize(nsblk);
+	sector_size = nsblk_sector_size(nsblk);
+	ns_offset = lba * internal_lbasize + sector_size;
 	dev_offset = to_dev_offset(nsblk, ns_offset, len);
 	if (dev_offset == SIZE_MAX)
 		return -EIO;
@@ -102,25 +113,26 @@ static int nd_blk_rw_integrity(struct nd_blk_device *blk_dev,
 }
 
 #else /* CONFIG_BLK_DEV_INTEGRITY */
-static int nd_blk_rw_integrity(struct nd_blk_device *blk_dev,
-				struct bio_integrity_payload *bip, u64 lba,
-				int rw)
+static int nd_blk_rw_integrity(struct nd_namespace_blk *nsblk,
+		struct bio_integrity_payload *bip, u64 lba, int rw)
 {
 	return 0;
 }
 #endif
 
-static int nd_blk_do_bvec(struct nd_blk_device *blk_dev,
-			struct bio_integrity_payload *bip, struct page *page,
-			unsigned int len, unsigned int off, int rw,
-			sector_t sector)
+static int nsblk_do_bvec(struct nd_namespace_blk *nsblk,
+		struct bio_integrity_payload *bip, struct page *page,
+		unsigned int len, unsigned int off, int rw, sector_t sector)
 {
-	struct nd_blk_region *ndbr = blk_dev->ndbr;
+	struct nd_blk_region *ndbr = to_ndbr(nsblk);
 	resource_size_t	dev_offset, ns_offset;
+	u32 internal_lbasize, sector_size;
 	int err = 0;
 	void *iobuf;
 	u64 lba;
 
+	internal_lbasize = nsblk_internal_lbasize(nsblk);
+	sector_size = nsblk_sector_size(nsblk);
 	while (len) {
 		unsigned int cur_len;
 
@@ -130,11 +142,11 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev,
 		 * Block Window setup/move steps. the do_io routine is capable
 		 * of handling len <= PAGE_SIZE.
 		 */
-		cur_len = bip ? min(len, blk_dev->sector_size) : len;
+		cur_len = bip ? min(len, sector_size) : len;
 
-		lba = div_u64(sector << SECTOR_SHIFT, blk_dev->sector_size);
-		ns_offset = lba * blk_dev->internal_lbasize;
-		dev_offset = to_dev_offset(blk_dev->nsblk, ns_offset, cur_len);
+		lba = div_u64(sector << SECTOR_SHIFT, sector_size);
+		ns_offset = lba * internal_lbasize;
+		dev_offset = to_dev_offset(nsblk, ns_offset, cur_len);
 		if (dev_offset == SIZE_MAX)
 			return -EIO;
 
@@ -145,13 +157,13 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev,
 			return err;
 
 		if (bip) {
-			err = nd_blk_rw_integrity(blk_dev, bip, lba, rw);
+			err = nd_blk_rw_integrity(nsblk, bip, lba, rw);
 			if (err)
 				return err;
 		}
 		len -= cur_len;
 		off += cur_len;
-		sector += blk_dev->sector_size >> SECTOR_SHIFT;
+		sector += sector_size >> SECTOR_SHIFT;
 	}
 
 	return err;
@@ -160,7 +172,7 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev,
 static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio)
 {
 	struct bio_integrity_payload *bip;
-	struct nd_blk_device *blk_dev;
+	struct nd_namespace_blk *nsblk;
 	struct bvec_iter iter;
 	unsigned long start;
 	struct bio_vec bvec;
@@ -179,17 +191,17 @@ static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio)
 	}
 
 	bip = bio_integrity(bio);
-	blk_dev = q->queuedata;
+	nsblk = q->queuedata;
 	rw = bio_data_dir(bio);
 	do_acct = nd_iostat_start(bio, &start);
 	bio_for_each_segment(bvec, bio, iter) {
 		unsigned int len = bvec.bv_len;
 
 		BUG_ON(len > PAGE_SIZE);
-		err = nd_blk_do_bvec(blk_dev, bip, bvec.bv_page, len,
-					bvec.bv_offset, rw, iter.bi_sector);
+		err = nsblk_do_bvec(nsblk, bip, bvec.bv_page, len,
+				bvec.bv_offset, rw, iter.bi_sector);
 		if (err) {
-			dev_info(&blk_dev->nsblk->common.dev,
+			dev_dbg(&nsblk->common.dev,
 					"io error in %s sector %lld, len %d,\n",
 					(rw == READ) ? "READ" : "WRITE",
 					(unsigned long long) iter.bi_sector, len);
@@ -205,17 +217,16 @@ static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio)
 	return BLK_QC_T_NONE;
 }
 
-static int nd_blk_rw_bytes(struct nd_namespace_common *ndns,
+static int nsblk_rw_bytes(struct nd_namespace_common *ndns,
 		resource_size_t offset, void *iobuf, size_t n, int rw)
 {
-	struct nd_blk_device *blk_dev = dev_get_drvdata(ndns->claim);
-	struct nd_namespace_blk *nsblk = blk_dev->nsblk;
-	struct nd_blk_region *ndbr = blk_dev->ndbr;
+	struct nd_namespace_blk *nsblk = to_nd_namespace_blk(&ndns->dev);
+	struct nd_blk_region *ndbr = to_ndbr(nsblk);
 	resource_size_t	dev_offset;
 
 	dev_offset = to_dev_offset(nsblk, offset, n);
 
-	if (unlikely(offset + n > blk_dev->disk_size)) {
+	if (unlikely(offset + n > nsblk->size)) {
 		dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n");
 		return -EFAULT;
 	}
@@ -242,16 +253,16 @@ static void nd_blk_release_disk(void *disk)
 	put_disk(disk);
 }
 
-static int nd_blk_attach_disk(struct device *dev,
-		struct nd_namespace_common *ndns, struct nd_blk_device *blk_dev)
+static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
 {
+	struct device *dev = &nsblk->common.dev;
 	resource_size_t available_disk_size;
 	struct request_queue *q;
 	struct gendisk *disk;
 	u64 internal_nlba;
 
-	internal_nlba = div_u64(blk_dev->disk_size, blk_dev->internal_lbasize);
-	available_disk_size = internal_nlba * blk_dev->sector_size;
+	internal_nlba = div_u64(nsblk->size, nsblk_internal_lbasize(nsblk));
+	available_disk_size = internal_nlba * nsblk_sector_size(nsblk);
 
 	q = blk_alloc_queue(GFP_KERNEL);
 	if (!q)
@@ -264,9 +275,9 @@ static int nd_blk_attach_disk(struct device *dev,
 	blk_queue_make_request(q, nd_blk_make_request);
 	blk_queue_max_hw_sectors(q, UINT_MAX);
 	blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
-	blk_queue_logical_block_size(q, blk_dev->sector_size);
+	blk_queue_logical_block_size(q, nsblk_sector_size(nsblk));
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
-	q->queuedata = blk_dev;
+	q->queuedata = nsblk;
 
 	disk = alloc_disk(0);
 	if (!disk)
@@ -276,17 +287,17 @@ static int nd_blk_attach_disk(struct device *dev,
 		return -ENOMEM;
 	}
 
-	disk->driverfs_dev	= &ndns->dev;
+	disk->driverfs_dev	= dev;
 	disk->first_minor	= 0;
 	disk->fops		= &nd_blk_fops;
 	disk->queue		= q;
 	disk->flags		= GENHD_FL_EXT_DEVT;
-	nvdimm_namespace_disk_name(ndns, disk->disk_name);
+	nvdimm_namespace_disk_name(&nsblk->common, disk->disk_name);
 	set_capacity(disk, 0);
 	add_disk(disk);
 
-	if (nd_blk_meta_size(blk_dev)) {
-		int rc = nd_integrity_init(disk, nd_blk_meta_size(blk_dev));
+	if (nsblk_meta_size(nsblk)) {
+		int rc = nd_integrity_init(disk, nsblk_meta_size(nsblk));
 
 		if (rc)
 			return rc;
@@ -301,33 +312,23 @@ static int nd_blk_probe(struct device *dev)
 {
 	struct nd_namespace_common *ndns;
 	struct nd_namespace_blk *nsblk;
-	struct nd_blk_device *blk_dev;
 
 	ndns = nvdimm_namespace_common_probe(dev);
 	if (IS_ERR(ndns))
 		return PTR_ERR(ndns);
 
-	blk_dev = devm_kzalloc(dev, sizeof(*blk_dev), GFP_KERNEL);
-	if (!blk_dev)
-		return -ENOMEM;
-
 	nsblk = to_nd_namespace_blk(&ndns->dev);
-	blk_dev->disk_size = nvdimm_namespace_capacity(ndns);
-	blk_dev->ndbr = to_nd_blk_region(dev->parent);
-	blk_dev->nsblk = to_nd_namespace_blk(&ndns->dev);
-	blk_dev->internal_lbasize = roundup(nsblk->lbasize,
-						INT_LBASIZE_ALIGNMENT);
-	blk_dev->sector_size = ((nsblk->lbasize >= 4096) ? 4096 : 512);
-	dev_set_drvdata(dev, blk_dev);
-
-	ndns->rw_bytes = nd_blk_rw_bytes;
+	nsblk->size = nvdimm_namespace_capacity(ndns);
+	dev_set_drvdata(dev, nsblk);
+
+	ndns->rw_bytes = nsblk_rw_bytes;
 	if (is_nd_btt(dev))
 		return nvdimm_namespace_attach_btt(ndns);
-	else if (nd_btt_probe(dev, ndns, blk_dev) == 0) {
+	else if (nd_btt_probe(dev, ndns, nsblk) == 0) {
 		/* we'll come back as btt-blk */
 		return -ENXIO;
 	} else
-		return nd_blk_attach_disk(dev, ndns, blk_dev);
+		return nsblk_attach_disk(nsblk);
 }
 
 static int nd_blk_remove(struct device *dev)
diff --git a/include/linux/nd.h b/include/linux/nd.h
index 5489ab756d1a..5ea4aec7fd63 100644
--- a/include/linux/nd.h
+++ b/include/linux/nd.h
@@ -82,6 +82,7 @@ struct nd_namespace_pmem {
  * @uuid: namespace name supplied in the dimm label
  * @id: ida allocated id
  * @lbasize: blk namespaces have a native sector size when btt not present
+ * @size: sum of all the resource ranges allocated to this namespace
  * @num_resources: number of dpa extents to claim
  * @res: discontiguous dpa extents for given dimm
  */
@@ -91,6 +92,7 @@ struct nd_namespace_blk {
 	u8 *uuid;
 	int id;
 	unsigned long lbasize;
+	resource_size_t size;
 	int num_resources;
 	struct resource **res;
 };

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 09/13] libnvdimm, pmem: use devm_add_action to release bdev resources
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
                   ` (7 preceding siblings ...)
  2016-03-24  1:26 ` [PATCH 08/13] libnvdimm, blk: move i/o infrastructure to nd_namespace_blk Dan Williams
@ 2016-03-24  1:26 ` Dan Williams
  2016-03-24 12:35   ` Johannes Thumshirn
  2016-03-24  1:26 ` [PATCH 10/13] libnvdimm, pmem: clean up resource print / request Dan Williams
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:26 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Ross Zwisler, linux-kernel

Register a callback to clean up the request_queue and put the gendisk at
driver disable time.

Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/pmem.c |   88 ++++++++++++++++++++++---------------------------
 1 file changed, 39 insertions(+), 49 deletions(-)

diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index ff336dd26064..97bc91b944b7 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -184,6 +184,17 @@ static const struct block_device_operations pmem_fops = {
 	.revalidate_disk =	nvdimm_revalidate_disk,
 };
 
+static void pmem_release_queue(void *q)
+{
+	blk_cleanup_queue(q);
+}
+
+void pmem_release_disk(void *disk)
+{
+	del_gendisk(disk);
+	put_disk(disk);
+}
+
 static struct pmem_device *pmem_alloc(struct device *dev,
 		struct resource *res, int id)
 {
@@ -220,25 +231,22 @@ static struct pmem_device *pmem_alloc(struct device *dev,
 				pmem->phys_addr, pmem->size,
 				ARCH_MEMREMAP_PMEM);
 
-	if (IS_ERR(pmem->virt_addr)) {
+	/*
+	 * At release time the queue must be dead before
+	 * devm_memremap_pages is unwound
+	 */
+	if (devm_add_action(dev, pmem_release_queue, q)) {
 		blk_cleanup_queue(q);
-		return (void __force *) pmem->virt_addr;
+		return ERR_PTR(-ENOMEM);
 	}
 
+	if (IS_ERR(pmem->virt_addr))
+		return (void __force *) pmem->virt_addr;
+
 	pmem->pmem_queue = q;
 	return pmem;
 }
 
-static void pmem_detach_disk(struct pmem_device *pmem)
-{
-	if (!pmem->pmem_disk)
-		return;
-
-	del_gendisk(pmem->pmem_disk);
-	put_disk(pmem->pmem_disk);
-	blk_cleanup_queue(pmem->pmem_queue);
-}
-
 static int pmem_attach_disk(struct device *dev,
 		struct nd_namespace_common *ndns, struct pmem_device *pmem)
 {
@@ -255,8 +263,10 @@ static int pmem_attach_disk(struct device *dev,
 	pmem->pmem_queue->queuedata = pmem;
 
 	disk = alloc_disk_node(0, nid);
-	if (!disk) {
-		blk_cleanup_queue(pmem->pmem_queue);
+	if (!disk)
+		return -ENOMEM;
+	if (devm_add_action(dev, pmem_release_disk, disk)) {
+		put_disk(disk);
 		return -ENOMEM;
 	}
 
@@ -413,15 +423,6 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
 	return nvdimm_write_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb));
 }
 
-static void nvdimm_namespace_detach_pfn(struct nd_pfn *nd_pfn)
-{
-	struct pmem_device *pmem;
-
-	/* free pmem disk */
-	pmem = dev_get_drvdata(&nd_pfn->dev);
-	pmem_detach_disk(pmem);
-}
-
 /*
  * We hotplug memory at section granularity, pad the reserved area from
  * the previous section base to the namespace base address.
@@ -444,7 +445,6 @@ static unsigned long init_altmap_reserve(resource_size_t base)
 
 static int __nvdimm_namespace_attach_pfn(struct nd_pfn *nd_pfn)
 {
-	int rc;
 	struct resource res;
 	struct request_queue *q;
 	struct pmem_device *pmem;
@@ -481,35 +481,33 @@ static int __nvdimm_namespace_attach_pfn(struct nd_pfn *nd_pfn)
 		altmap = & __altmap;
 		altmap->free = PHYS_PFN(pmem->data_offset - SZ_8K);
 		altmap->alloc = 0;
-	} else {
-		rc = -ENXIO;
-		goto err;
-	}
+	} else
+		return -ENXIO;
 
 	/* establish pfn range for lookup, and switch to direct map */
 	q = pmem->pmem_queue;
 	memcpy(&res, &nsio->res, sizeof(res));
 	res.start += start_pad;
 	res.end -= end_trunc;
+	devm_remove_action(dev, pmem_release_queue, q);
 	devm_memunmap(dev, (void __force *) pmem->virt_addr);
 	pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &res,
 			&q->q_usage_counter, altmap);
 	pmem->pfn_flags |= PFN_MAP;
-	if (IS_ERR(pmem->virt_addr)) {
-		rc = PTR_ERR(pmem->virt_addr);
-		goto err;
+
+	/*
+	 * At release time the queue must be dead before
+	 * devm_memremap_pages is unwound
+	 */
+	if (devm_add_action(dev, pmem_release_queue, q)) {
+		blk_cleanup_queue(q);
+		return -ENOMEM;
 	}
+	if (IS_ERR(pmem->virt_addr))
+		return PTR_ERR(pmem->virt_addr);
 
 	/* attach pmem disk in "pfn-mode" */
-	rc = pmem_attach_disk(dev, ndns, pmem);
-	if (rc)
-		goto err;
-
-	return rc;
- err:
-	nvdimm_namespace_detach_pfn(nd_pfn);
-	return rc;
-
+	return pmem_attach_disk(dev, ndns, pmem);
 }
 
 static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
@@ -551,8 +549,8 @@ static int nd_pmem_probe(struct device *dev)
 
 	if (is_nd_btt(dev)) {
 		/* btt allocates its own request_queue */
+		devm_remove_action(dev, pmem_release_queue, pmem->pmem_queue);
 		blk_cleanup_queue(pmem->pmem_queue);
-		pmem->pmem_queue = NULL;
 		return nvdimm_namespace_attach_btt(ndns);
 	}
 
@@ -565,7 +563,6 @@ static int nd_pmem_probe(struct device *dev)
 		 * We'll come back as either btt-pmem, or pfn-pmem, so
 		 * drop the queue allocation for now.
 		 */
-		blk_cleanup_queue(pmem->pmem_queue);
 		return -ENXIO;
 	}
 
@@ -574,15 +571,8 @@ static int nd_pmem_probe(struct device *dev)
 
 static int nd_pmem_remove(struct device *dev)
 {
-	struct pmem_device *pmem = dev_get_drvdata(dev);
-
 	if (is_nd_btt(dev))
 		nvdimm_namespace_detach_btt(to_nd_btt(dev));
-	else if (is_nd_pfn(dev))
-		nvdimm_namespace_detach_pfn(to_nd_pfn(dev));
-	else
-		pmem_detach_disk(pmem);
-
 	return 0;
 }
 

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 10/13] libnvdimm, pmem: clean up resource print / request
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
                   ` (8 preceding siblings ...)
  2016-03-24  1:26 ` [PATCH 09/13] libnvdimm, pmem: use devm_add_action to release bdev resources Dan Williams
@ 2016-03-24  1:26 ` Dan Williams
  2016-03-24 13:42   ` Johannes Thumshirn
  2016-03-24  1:26 ` [PATCH 11/13] libnvdimm, pmem, pfn: make pmem_rw_bytes generic and refactor pfn setup Dan Williams
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:26 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: linux-kernel

The leading '0x' in front of %pa is redundant, also we can just use %pR
to simplify the print statement.  The request parameters can be directly
taken from the resource as well.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/pmem.c |    7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 97bc91b944b7..c9ae1673bb17 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -210,10 +210,9 @@ static struct pmem_device *pmem_alloc(struct device *dev,
 	if (!arch_has_wmb_pmem())
 		dev_warn(dev, "unable to guarantee persistence of writes\n");
 
-	if (!devm_request_mem_region(dev, pmem->phys_addr, pmem->size,
-			dev_name(dev))) {
-		dev_warn(dev, "could not reserve region [0x%pa:0x%zx]\n",
-				&pmem->phys_addr, pmem->size);
+	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 ERR_PTR(-EBUSY);
 	}
 

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 11/13] libnvdimm, pmem, pfn: make pmem_rw_bytes generic and refactor pfn setup
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
                   ` (9 preceding siblings ...)
  2016-03-24  1:26 ` [PATCH 10/13] libnvdimm, pmem: clean up resource print / request Dan Williams
@ 2016-03-24  1:26 ` Dan Williams
  2016-03-24 13:50   ` Johannes Thumshirn
  2016-03-25 22:13   ` [PATCH v2] " Dan Williams
  2016-03-24  1:26 ` [PATCH 12/13] libnvdimm, pmem, pfn: move pfn setup to the core Dan Williams
  2016-03-24  1:26 ` [PATCH 13/13] libnvdimm, pmem: kill ->pmem_queue and ->pmem_disk Dan Williams
  12 siblings, 2 replies; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:26 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: linux-kernel

In preparation for providing an alternative (to block device) access
mechanism to persistent memory, convert pmem_rw_bytes() to
nsio_rw_bytes().  This allows ->rw_bytes() functionality without
requiring a 'struct pmem_device' to be instantiated.

In other words, when ->rw_bytes() is in use i/o is driven through
'struct nd_namespace_io', otherwise it is driven through 'struct
pmem_device' and the block layer.  This consolidates the disjoint calls
to devm_exit_badblocks() and devm_memunmap() into a common
devm_nsio_disable() and cleans up the init path to use a unified
pmem_attach_disk() implementation.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/blk.c              |    2 
 drivers/nvdimm/btt_devs.c         |    4 -
 drivers/nvdimm/claim.c            |   61 ++++++++++
 drivers/nvdimm/nd.h               |   39 +++++-
 drivers/nvdimm/pfn_devs.c         |    4 -
 drivers/nvdimm/pmem.c             |  230 +++++++++++++------------------------
 include/linux/nd.h                |    9 +
 tools/testing/nvdimm/Kbuild       |    1 
 tools/testing/nvdimm/test/iomap.c |   27 +++-
 9 files changed, 207 insertions(+), 170 deletions(-)

diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
index 4c14ecdc792b..495e06d9f7e7 100644
--- a/drivers/nvdimm/blk.c
+++ b/drivers/nvdimm/blk.c
@@ -324,7 +324,7 @@ static int nd_blk_probe(struct device *dev)
 	ndns->rw_bytes = nsblk_rw_bytes;
 	if (is_nd_btt(dev))
 		return nvdimm_namespace_attach_btt(ndns);
-	else if (nd_btt_probe(dev, ndns, nsblk) == 0) {
+	else if (nd_btt_probe(dev, ndns) == 0) {
 		/* we'll come back as btt-blk */
 		return -ENXIO;
 	} else
diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c
index 1886171af80e..816d0dae6398 100644
--- a/drivers/nvdimm/btt_devs.c
+++ b/drivers/nvdimm/btt_devs.c
@@ -273,8 +273,7 @@ static int __nd_btt_probe(struct nd_btt *nd_btt,
 	return 0;
 }
 
-int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns,
-		void *drvdata)
+int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns)
 {
 	int rc;
 	struct device *btt_dev;
@@ -289,7 +288,6 @@ int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns,
 	nvdimm_bus_unlock(&ndns->dev);
 	if (!btt_dev)
 		return -ENOMEM;
-	dev_set_drvdata(btt_dev, drvdata);
 	btt_sb = devm_kzalloc(dev, sizeof(*btt_sb), GFP_KERNEL);
 	rc = __nd_btt_probe(to_nd_btt(btt_dev), ndns, btt_sb);
 	dev_dbg(dev, "%s: btt: %s\n", __func__,
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c
index e8f03b0e95e4..85159050a7a7 100644
--- a/drivers/nvdimm/claim.c
+++ b/drivers/nvdimm/claim.c
@@ -12,6 +12,7 @@
  */
 #include <linux/device.h>
 #include <linux/sizes.h>
+#include <linux/pmem.h>
 #include "nd-core.h"
 #include "pfn.h"
 #include "btt.h"
@@ -199,3 +200,63 @@ u64 nd_sb_checksum(struct nd_gen_sb *nd_gen_sb)
 	return sum;
 }
 EXPORT_SYMBOL(nd_sb_checksum);
+
+static int nsio_rw_bytes(struct nd_namespace_common *ndns,
+		resource_size_t offset, void *buf, size_t size, int rw)
+{
+	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+
+	if (unlikely(offset + size > nsio->size)) {
+		dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n");
+		return -EFAULT;
+	}
+
+	if (rw == READ) {
+		unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
+
+		if (unlikely(is_bad_pmem(&nsio->bb, offset / 512, sz_align)))
+			return -EIO;
+		memcpy_from_pmem(buf, nsio->addr + offset, size);
+	} else {
+		memcpy_to_pmem(nsio->addr + offset, buf, size);
+		wmb_pmem();
+	}
+
+	return 0;
+}
+
+int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)
+{
+	struct resource *res = &nsio->res;
+	struct nd_namespace_common *ndns = &nsio->common;
+
+	nsio->size = resource_size(res);
+	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;
+	}
+
+	ndns->rw_bytes = nsio_rw_bytes;
+	if (devm_init_badblocks(dev, &nsio->bb))
+		return -ENOMEM;
+	nvdimm_badblocks_populate(to_nd_region(ndns->dev.parent), &nsio->bb,
+			&nsio->res);
+
+	nsio->addr = devm_memremap(dev, res->start, resource_size(res),
+			ARCH_MEMREMAP_PMEM);
+	if (IS_ERR(nsio->addr))
+		return PTR_ERR(nsio->addr);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(devm_nsio_enable);
+
+void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio)
+{
+	struct resource *res = &nsio->res;
+
+	devm_memunmap(dev, nsio->addr);
+	devm_exit_badblocks(dev, &nsio->bb);
+	devm_release_mem_region(dev, res->start, resource_size(res));
+}
+EXPORT_SYMBOL_GPL(devm_nsio_disable);
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 0fb14890ba26..a42c823c0a67 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -13,6 +13,7 @@
 #ifndef __ND_H__
 #define __ND_H__
 #include <linux/libnvdimm.h>
+#include <linux/badblocks.h>
 #include <linux/blkdev.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
@@ -197,13 +198,12 @@ struct nd_gen_sb {
 
 u64 nd_sb_checksum(struct nd_gen_sb *sb);
 #if IS_ENABLED(CONFIG_BTT)
-int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns,
-		void *drvdata);
+int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns);
 bool is_nd_btt(struct device *dev);
 struct device *nd_btt_create(struct nd_region *nd_region);
 #else
 static inline int nd_btt_probe(struct device *dev,
-		struct nd_namespace_common *ndns, void *drvdata)
+		struct nd_namespace_common *ndns)
 {
 	return -ENODEV;
 }
@@ -221,14 +221,13 @@ static inline struct device *nd_btt_create(struct nd_region *nd_region)
 
 struct nd_pfn *to_nd_pfn(struct device *dev);
 #if IS_ENABLED(CONFIG_NVDIMM_PFN)
-int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
-		void *drvdata);
+int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns);
 bool is_nd_pfn(struct device *dev);
 struct device *nd_pfn_create(struct nd_region *nd_region);
 int nd_pfn_validate(struct nd_pfn *nd_pfn);
 #else
-static inline int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
-		void *drvdata)
+static inline int nd_pfn_probe(struct device *dev,
+		struct nd_namespace_common *ndns)
 {
 	return -ENODEV;
 }
@@ -272,6 +271,19 @@ const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns,
 		char *name);
 void nvdimm_badblocks_populate(struct nd_region *nd_region,
 		struct badblocks *bb, const struct resource *res);
+#if IS_ENABLED(CONFIG_ND_CLAIM)
+int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio);
+void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio);
+#else
+static inline int devm_nsio_enable(struct device *dev,
+		struct nd_namespace_io *nsio)
+{
+	return -ENXIO;
+}
+void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio)
+{
+}
+#endif
 int nd_blk_region_init(struct nd_region *nd_region);
 void __nd_iostat_start(struct bio *bio, unsigned long *start);
 static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
@@ -285,6 +297,19 @@ static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
 	return true;
 }
 void nd_iostat_end(struct bio *bio, unsigned long start);
+static inline bool is_bad_pmem(struct badblocks *bb, sector_t sector,
+		unsigned int len)
+{
+	if (bb->count) {
+		sector_t first_bad;
+		int num_bad;
+
+		return !!badblocks_check(bb, sector, len / 512, &first_bad,
+				&num_bad);
+	}
+
+	return false;
+}
 resource_size_t nd_namespace_blk_validate(struct nd_namespace_blk *nsblk);
 const u8 *nd_dev_to_uuid(struct device *dev);
 bool pmem_should_map_pages(struct device *dev);
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 63e2df3e052c..f8fd379501bf 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -410,8 +410,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn)
 }
 EXPORT_SYMBOL(nd_pfn_validate);
 
-int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
-		void *drvdata)
+int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns)
 {
 	int rc;
 	struct nd_pfn *nd_pfn;
@@ -427,7 +426,6 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
 	nvdimm_bus_unlock(&ndns->dev);
 	if (!pfn_dev)
 		return -ENOMEM;
-	dev_set_drvdata(pfn_dev, drvdata);
 	pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
 	nd_pfn = to_nd_pfn(pfn_dev);
 	nd_pfn->pfn_sb = pfn_sb;
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index c9ae1673bb17..03bfb3422da1 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -49,19 +49,6 @@ struct pmem_device {
 	struct badblocks	bb;
 };
 
-static bool is_bad_pmem(struct badblocks *bb, sector_t sector, unsigned int len)
-{
-	if (bb->count) {
-		sector_t first_bad;
-		int num_bad;
-
-		return !!badblocks_check(bb, sector, len / 512, &first_bad,
-				&num_bad);
-	}
-
-	return false;
-}
-
 static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
 		unsigned int len)
 {
@@ -195,16 +182,40 @@ void pmem_release_disk(void *disk)
 	put_disk(disk);
 }
 
-static struct pmem_device *pmem_alloc(struct device *dev,
-		struct resource *res, int id)
+static struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap);
+
+static int pmem_attach_disk(struct device *dev,
+		struct nd_namespace_common *ndns)
 {
+	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+	struct vmem_altmap __altmap, *altmap = NULL;
+	struct resource *res = &nsio->res;
+	struct nd_pfn *nd_pfn = NULL;
+	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 gendisk *disk;
+	void *addr;
+
+	/* while nsio_rw_bytes is active, parse a pfn info block if present */
+	if (is_nd_pfn(dev)) {
+		nd_pfn = to_nd_pfn(dev);
+		altmap = nvdimm_setup_pfn(nd_pfn, &pfn_res, &__altmap);
+		if (IS_ERR(altmap))
+			return PTR_ERR(altmap);
+	}
+
+	/* we're attaching a block device, disable raw namespace access */
+	devm_nsio_disable(dev, nsio);
 
 	pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL);
 	if (!pmem)
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 
+	dev_set_drvdata(dev, pmem);
 	pmem->phys_addr = res->start;
 	pmem->size = resource_size(res);
 	if (!arch_has_wmb_pmem())
@@ -213,22 +224,31 @@ static struct pmem_device *pmem_alloc(struct device *dev,
 	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 ERR_PTR(-EBUSY);
+		return -EBUSY;
 	}
 
 	q = blk_alloc_queue_node(GFP_KERNEL, dev_to_node(dev));
 	if (!q)
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
+	pmem->pmem_queue = q;
 
 	pmem->pfn_flags = PFN_DEV;
-	if (pmem_should_map_pages(dev)) {
-		pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, res,
+	if (is_nd_pfn(dev)) {
+		addr = devm_memremap_pages(dev, &pfn_res, &q->q_usage_counter,
+				altmap);
+		pfn_sb = nd_pfn->pfn_sb;
+		pmem->data_offset = le64_to_cpu(pfn_sb->dataoff);
+		pmem->pfn_pad = pfn_res.start - res->start + res->end
+			- pfn_res.end;
+		pmem->pfn_flags |= PFN_MAP;
+		res = &pfn_res; /* for badblocks populate */
+	} else if (pmem_should_map_pages(dev)) {
+		addr = devm_memremap_pages(dev, &nsio->res,
 				&q->q_usage_counter, NULL);
 		pmem->pfn_flags |= PFN_MAP;
 	} else
-		pmem->virt_addr = (void __pmem *) devm_memremap(dev,
-				pmem->phys_addr, pmem->size,
-				ARCH_MEMREMAP_PMEM);
+		addr = devm_memremap(dev, pmem->phys_addr,
+				pmem->size, ARCH_MEMREMAP_PMEM);
 
 	/*
 	 * At release time the queue must be dead before
@@ -236,23 +256,12 @@ static struct pmem_device *pmem_alloc(struct device *dev,
 	 */
 	if (devm_add_action(dev, pmem_release_queue, q)) {
 		blk_cleanup_queue(q);
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 	}
 
-	if (IS_ERR(pmem->virt_addr))
-		return (void __force *) pmem->virt_addr;
-
-	pmem->pmem_queue = q;
-	return pmem;
-}
-
-static int pmem_attach_disk(struct device *dev,
-		struct nd_namespace_common *ndns, struct pmem_device *pmem)
-{
-	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
-	int nid = dev_to_node(dev);
-	struct resource bb_res;
-	struct gendisk *disk;
+	if (IS_ERR(addr))
+		return PTR_ERR(addr);
+	pmem->virt_addr = (void __pmem *) addr;
 
 	blk_queue_make_request(pmem->pmem_queue, pmem_make_request);
 	blk_queue_physical_block_size(pmem->pmem_queue, PAGE_SIZE);
@@ -277,20 +286,9 @@ static int pmem_attach_disk(struct device *dev,
 	set_capacity(disk, (pmem->size - pmem->pfn_pad - pmem->data_offset)
 			/ 512);
 	pmem->pmem_disk = disk;
-	devm_exit_badblocks(dev, &pmem->bb);
 	if (devm_init_badblocks(dev, &pmem->bb))
 		return -ENOMEM;
-	bb_res.start = nsio->res.start + pmem->data_offset;
-	bb_res.end = nsio->res.end;
-	if (is_nd_pfn(dev)) {
-		struct nd_pfn *nd_pfn = to_nd_pfn(dev);
-		struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
-
-		bb_res.start += __le32_to_cpu(pfn_sb->start_pad);
-		bb_res.end -= __le32_to_cpu(pfn_sb->end_trunc);
-	}
-	nvdimm_badblocks_populate(to_nd_region(dev->parent), &pmem->bb,
-			&bb_res);
+	nvdimm_badblocks_populate(to_nd_region(dev->parent), &pmem->bb, res);
 	disk->bb = &pmem->bb;
 	add_disk(disk);
 	revalidate_disk(disk);
@@ -298,30 +296,6 @@ static int pmem_attach_disk(struct device *dev,
 	return 0;
 }
 
-static int pmem_rw_bytes(struct nd_namespace_common *ndns,
-		resource_size_t offset, void *buf, size_t size, int rw)
-{
-	struct pmem_device *pmem = dev_get_drvdata(ndns->claim);
-
-	if (unlikely(offset + size > pmem->size)) {
-		dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n");
-		return -EFAULT;
-	}
-
-	if (rw == READ) {
-		unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
-
-		if (unlikely(is_bad_pmem(&pmem->bb, offset / 512, sz_align)))
-			return -EIO;
-		memcpy_from_pmem(buf, pmem->virt_addr + offset, size);
-	} else {
-		memcpy_to_pmem(pmem->virt_addr + offset, buf, size);
-		wmb_pmem();
-	}
-
-	return 0;
-}
-
 static int nd_pfn_init(struct nd_pfn *nd_pfn)
 {
 	struct pmem_device *pmem = dev_get_drvdata(&nd_pfn->dev);
@@ -442,17 +416,14 @@ static unsigned long init_altmap_reserve(resource_size_t base)
 	return reserve;
 }
 
-static int __nvdimm_namespace_attach_pfn(struct nd_pfn *nd_pfn)
+static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap)
 {
-	struct resource res;
-	struct request_queue *q;
-	struct pmem_device *pmem;
-	struct vmem_altmap *altmap;
-	struct device *dev = &nd_pfn->dev;
 	struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
-	struct nd_namespace_common *ndns = nd_pfn->ndns;
+	u64 offset = le64_to_cpu(pfn_sb->dataoff);
 	u32 start_pad = __le32_to_cpu(pfn_sb->start_pad);
 	u32 end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
+	struct nd_namespace_common *ndns = nd_pfn->ndns;
 	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
 	resource_size_t base = nsio->res.start + start_pad;
 	struct vmem_altmap __altmap = {
@@ -460,112 +431,75 @@ static int __nvdimm_namespace_attach_pfn(struct nd_pfn *nd_pfn)
 		.reserve = init_altmap_reserve(base),
 	};
 
-	pmem = dev_get_drvdata(dev);
-	pmem->data_offset = le64_to_cpu(pfn_sb->dataoff);
-	pmem->pfn_pad = start_pad + end_trunc;
+	memcpy(res, &nsio->res, sizeof(*res));
+	res->start += start_pad;
+	res->end -= end_trunc;
+
 	nd_pfn->mode = le32_to_cpu(nd_pfn->pfn_sb->mode);
 	if (nd_pfn->mode == PFN_MODE_RAM) {
-		if (pmem->data_offset < SZ_8K)
-			return -EINVAL;
+		if (offset < SZ_8K)
+			return ERR_PTR(-EINVAL);
 		nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
 		altmap = NULL;
 	} else if (nd_pfn->mode == PFN_MODE_PMEM) {
-		nd_pfn->npfns = (pmem->size - pmem->pfn_pad - pmem->data_offset)
-			/ PAGE_SIZE;
+		nd_pfn->npfns = (resource_size(res) - offset) / PAGE_SIZE;
 		if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
 			dev_info(&nd_pfn->dev,
 					"number of pfns truncated from %lld to %ld\n",
 					le64_to_cpu(nd_pfn->pfn_sb->npfns),
 					nd_pfn->npfns);
-		altmap = & __altmap;
-		altmap->free = PHYS_PFN(pmem->data_offset - SZ_8K);
+		memcpy(altmap, &__altmap, sizeof(*altmap));
+		altmap->free = PHYS_PFN(offset - SZ_8K);
 		altmap->alloc = 0;
 	} else
-		return -ENXIO;
-
-	/* establish pfn range for lookup, and switch to direct map */
-	q = pmem->pmem_queue;
-	memcpy(&res, &nsio->res, sizeof(res));
-	res.start += start_pad;
-	res.end -= end_trunc;
-	devm_remove_action(dev, pmem_release_queue, q);
-	devm_memunmap(dev, (void __force *) pmem->virt_addr);
-	pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &res,
-			&q->q_usage_counter, altmap);
-	pmem->pfn_flags |= PFN_MAP;
-
-	/*
-	 * At release time the queue must be dead before
-	 * devm_memremap_pages is unwound
-	 */
-	if (devm_add_action(dev, pmem_release_queue, q)) {
-		blk_cleanup_queue(q);
-		return -ENOMEM;
-	}
-	if (IS_ERR(pmem->virt_addr))
-		return PTR_ERR(pmem->virt_addr);
+		return ERR_PTR(-ENXIO);
 
-	/* attach pmem disk in "pfn-mode" */
-	return pmem_attach_disk(dev, ndns, pmem);
+	return altmap;
 }
 
-static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
+/*
+ * Determine the effective resource range and vmem_altmap from an nd_pfn
+ * instance.
+ */
+static struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap)
 {
-	struct nd_pfn *nd_pfn = to_nd_pfn(ndns->claim);
 	int rc;
 
 	if (!nd_pfn->uuid || !nd_pfn->ndns)
-		return -ENODEV;
+		return ERR_PTR(-ENODEV);
 
 	rc = nd_pfn_init(nd_pfn);
 	if (rc)
-		return rc;
+		return ERR_PTR(rc);
+
 	/* we need a valid pfn_sb before we can init a vmem_altmap */
-	return __nvdimm_namespace_attach_pfn(nd_pfn);
+	return __nvdimm_setup_pfn(nd_pfn, res, altmap);
 }
 
 static int nd_pmem_probe(struct device *dev)
 {
-	struct nd_region *nd_region = to_nd_region(dev->parent);
 	struct nd_namespace_common *ndns;
-	struct nd_namespace_io *nsio;
-	struct pmem_device *pmem;
 
 	ndns = nvdimm_namespace_common_probe(dev);
 	if (IS_ERR(ndns))
 		return PTR_ERR(ndns);
 
-	nsio = to_nd_namespace_io(&ndns->dev);
-	pmem = pmem_alloc(dev, &nsio->res, nd_region->id);
-	if (IS_ERR(pmem))
-		return PTR_ERR(pmem);
-
-	dev_set_drvdata(dev, pmem);
-	ndns->rw_bytes = pmem_rw_bytes;
-	if (devm_init_badblocks(dev, &pmem->bb))
-		return -ENOMEM;
-	nvdimm_badblocks_populate(nd_region, &pmem->bb, &nsio->res);
+	if (devm_nsio_enable(dev, to_nd_namespace_io(&ndns->dev)))
+		return -ENXIO;
 
-	if (is_nd_btt(dev)) {
-		/* btt allocates its own request_queue */
-		devm_remove_action(dev, pmem_release_queue, pmem->pmem_queue);
-		blk_cleanup_queue(pmem->pmem_queue);
+	if (is_nd_btt(dev))
 		return nvdimm_namespace_attach_btt(ndns);
-	}
 
 	if (is_nd_pfn(dev))
-		return nvdimm_namespace_attach_pfn(ndns);
-
-	if (nd_btt_probe(dev, ndns, pmem) == 0
-			|| nd_pfn_probe(dev, ndns, pmem) == 0) {
-		/*
-		 * We'll come back as either btt-pmem, or pfn-pmem, so
-		 * drop the queue allocation for now.
-		 */
+		return pmem_attach_disk(dev, ndns);
+
+	/* if we find a valid info-block we'll come back as that personality */
+	if (nd_btt_probe(dev, ndns) == 0 || nd_pfn_probe(dev, ndns) == 0)
 		return -ENXIO;
-	}
 
-	return pmem_attach_disk(dev, ndns, pmem);
+	/* ...otherwise we're just a raw pmem device */
+	return pmem_attach_disk(dev, ndns);
 }
 
 static int nd_pmem_remove(struct device *dev)
diff --git a/include/linux/nd.h b/include/linux/nd.h
index 5ea4aec7fd63..aee2761d294c 100644
--- a/include/linux/nd.h
+++ b/include/linux/nd.h
@@ -15,6 +15,7 @@
 #include <linux/fs.h>
 #include <linux/ndctl.h>
 #include <linux/device.h>
+#include <linux/badblocks.h>
 
 enum nvdimm_event {
 	NVDIMM_REVALIDATE_POISON,
@@ -55,13 +56,19 @@ static inline struct nd_namespace_common *to_ndns(struct device *dev)
 }
 
 /**
- * struct nd_namespace_io - infrastructure for loading an nd_pmem instance
+ * struct nd_namespace_io - device representation of a persistent memory range
  * @dev: namespace device created by the nd region driver
  * @res: struct resource conversion of a NFIT SPA table
+ * @size: cached resource_size(@res) for fast path size checks
+ * @addr: virtual address to access the namespace range
+ * @bb: badblocks list for the namespace range
  */
 struct nd_namespace_io {
 	struct nd_namespace_common common;
 	struct resource res;
+	resource_size_t size;
+	void __pmem *addr;
+	struct badblocks bb;
 };
 
 /**
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild
index a34bfd0c8928..d5bc8c080b44 100644
--- a/tools/testing/nvdimm/Kbuild
+++ b/tools/testing/nvdimm/Kbuild
@@ -7,6 +7,7 @@ ldflags-y += --wrap=ioremap_nocache
 ldflags-y += --wrap=iounmap
 ldflags-y += --wrap=memunmap
 ldflags-y += --wrap=__devm_request_region
+ldflags-y += --wrap=__devm_release_region
 ldflags-y += --wrap=__request_region
 ldflags-y += --wrap=__release_region
 ldflags-y += --wrap=devm_memremap_pages
diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c
index 0c1a7e65bb81..c842095f2801 100644
--- a/tools/testing/nvdimm/test/iomap.c
+++ b/tools/testing/nvdimm/test/iomap.c
@@ -239,13 +239,11 @@ struct resource *__wrap___devm_request_region(struct device *dev,
 }
 EXPORT_SYMBOL(__wrap___devm_request_region);
 
-void __wrap___release_region(struct resource *parent, resource_size_t start,
-				resource_size_t n)
+static bool nfit_test_release_region(struct resource *parent,
+		resource_size_t start, resource_size_t n)
 {
-	struct nfit_test_resource *nfit_res;
-
 	if (parent == &iomem_resource) {
-		nfit_res = get_nfit_res(start);
+		struct nfit_test_resource *nfit_res = get_nfit_res(start);
 		if (nfit_res) {
 			struct resource *res = nfit_res->res + 1;
 
@@ -254,11 +252,26 @@ void __wrap___release_region(struct resource *parent, resource_size_t start,
 						__func__, start, n, res);
 			else
 				memset(res, 0, sizeof(*res));
-			return;
+			return true;
 		}
 	}
-	__release_region(parent, start, n);
+	return false;
+}
+
+void __wrap___release_region(struct resource *parent, resource_size_t start,
+		resource_size_t n)
+{
+	if (!nfit_test_release_region(parent, start, n))
+		__release_region(parent, start, n);
 }
 EXPORT_SYMBOL(__wrap___release_region);
 
+void __wrap___devm_release_region(struct device *dev, struct resource *parent,
+		resource_size_t start, resource_size_t n)
+{
+	if (!nfit_test_release_region(parent, start, n))
+		__devm_release_region(dev, parent, start, n);
+}
+EXPORT_SYMBOL(__wrap___devm_release_region);
+
 MODULE_LICENSE("GPL v2");

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 12/13] libnvdimm, pmem, pfn: move pfn setup to the core
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
                   ` (10 preceding siblings ...)
  2016-03-24  1:26 ` [PATCH 11/13] libnvdimm, pmem, pfn: make pmem_rw_bytes generic and refactor pfn setup Dan Williams
@ 2016-03-24  1:26 ` Dan Williams
  2016-03-24 14:36   ` Johannes Thumshirn
  2016-03-25 22:15   ` [PATCH v2] " Dan Williams
  2016-03-24  1:26 ` [PATCH 13/13] libnvdimm, pmem: kill ->pmem_queue and ->pmem_disk Dan Williams
  12 siblings, 2 replies; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:26 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: linux-kernel

Now that pmem internals have been disentangled from pfn setup, that code
can move to the core.  This is in preparation for adding another user of
the pfn-device capabilities.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/nd.h       |    7 ++
 drivers/nvdimm/pfn_devs.c |  183 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/nvdimm/pmem.c     |  184 ---------------------------------------------
 3 files changed, 190 insertions(+), 184 deletions(-)

diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index a42c823c0a67..8e563c4a3e8c 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -272,9 +272,16 @@ const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns,
 void nvdimm_badblocks_populate(struct nd_region *nd_region,
 		struct badblocks *bb, const struct resource *res);
 #if IS_ENABLED(CONFIG_ND_CLAIM)
+struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap);
 int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio);
 void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio);
 #else
+static inline struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap)
+{
+	return ERR_PTR(-ENXIO);
+}
 static inline int devm_nsio_enable(struct device *dev,
 		struct nd_namespace_io *nsio)
 {
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index f8fd379501bf..51a214ee75a7 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -10,6 +10,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  */
+#include <linux/memremap.h>
 #include <linux/blkdev.h>
 #include <linux/device.h>
 #include <linux/genhd.h>
@@ -441,3 +442,185 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns)
 	return rc;
 }
 EXPORT_SYMBOL(nd_pfn_probe);
+
+/*
+ * We hotplug memory at section granularity, pad the reserved area from
+ * the previous section base to the namespace base address.
+ */
+static unsigned long init_altmap_base(resource_size_t base)
+{
+	unsigned long base_pfn = PHYS_PFN(base);
+
+	return PFN_SECTION_ALIGN_DOWN(base_pfn);
+}
+
+static unsigned long init_altmap_reserve(resource_size_t base)
+{
+	unsigned long reserve = PHYS_PFN(SZ_8K);
+	unsigned long base_pfn = PHYS_PFN(base);
+
+	reserve += base_pfn - PFN_SECTION_ALIGN_DOWN(base_pfn);
+	return reserve;
+}
+
+static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap)
+{
+	struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
+	u64 offset = le64_to_cpu(pfn_sb->dataoff);
+	u32 start_pad = __le32_to_cpu(pfn_sb->start_pad);
+	u32 end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
+	struct nd_namespace_common *ndns = nd_pfn->ndns;
+	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+	resource_size_t base = nsio->res.start + start_pad;
+	struct vmem_altmap __altmap = {
+		.base_pfn = init_altmap_base(base),
+		.reserve = init_altmap_reserve(base),
+	};
+
+	memcpy(res, &nsio->res, sizeof(*res));
+	res->start += start_pad;
+	res->end -= end_trunc;
+
+	nd_pfn->mode = le32_to_cpu(nd_pfn->pfn_sb->mode);
+	if (nd_pfn->mode == PFN_MODE_RAM) {
+		if (offset < SZ_8K)
+			return ERR_PTR(-EINVAL);
+		nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
+		altmap = NULL;
+	} else if (nd_pfn->mode == PFN_MODE_PMEM) {
+		nd_pfn->npfns = (resource_size(res) - offset) / PAGE_SIZE;
+		if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
+			dev_info(&nd_pfn->dev,
+					"number of pfns truncated from %lld to %ld\n",
+					le64_to_cpu(nd_pfn->pfn_sb->npfns),
+					nd_pfn->npfns);
+		memcpy(altmap, &__altmap, sizeof(*altmap));
+		altmap->free = PHYS_PFN(offset - SZ_8K);
+		altmap->alloc = 0;
+	} else
+		return ERR_PTR(-ENXIO);
+
+	return altmap;
+}
+
+static int nd_pfn_init(struct nd_pfn *nd_pfn)
+{
+	struct nd_namespace_common *ndns = nd_pfn->ndns;
+	u32 start_pad = 0, end_trunc = 0;
+	resource_size_t start, size;
+	struct nd_namespace_io *nsio;
+	struct nd_region *nd_region;
+	struct nd_pfn_sb *pfn_sb;
+	unsigned long npfns;
+	phys_addr_t offset;
+	u64 checksum;
+	int rc;
+
+	pfn_sb = devm_kzalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
+	if (!pfn_sb)
+		return -ENOMEM;
+
+	nd_pfn->pfn_sb = pfn_sb;
+	rc = nd_pfn_validate(nd_pfn);
+	if (rc == -ENODEV)
+		/* no info block, do init */;
+	else
+		return rc;
+
+	nd_region = to_nd_region(nd_pfn->dev.parent);
+	if (nd_region->ro) {
+		dev_info(&nd_pfn->dev,
+				"%s is read-only, unable to init metadata\n",
+				dev_name(&nd_region->dev));
+		return -ENXIO;
+	}
+
+	memset(pfn_sb, 0, sizeof(*pfn_sb));
+
+	/*
+	 * Check if pmem collides with 'System RAM' when section aligned and
+	 * trim it accordingly
+	 */
+	nsio = to_nd_namespace_io(&ndns->dev);
+	start = PHYS_SECTION_ALIGN_DOWN(nsio->res.start);
+	size = resource_size(&nsio->res);
+	if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
+				IORES_DESC_NONE) == REGION_MIXED) {
+
+		start = nsio->res.start;
+		start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
+	}
+
+	start = nsio->res.start;
+	size = PHYS_SECTION_ALIGN_UP(start + size) - start;
+	if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
+				IORES_DESC_NONE) == REGION_MIXED) {
+		size = resource_size(&nsio->res);
+		end_trunc = start + size - PHYS_SECTION_ALIGN_DOWN(start + size);
+	}
+
+	if (start_pad + end_trunc)
+		dev_info(&nd_pfn->dev, "%s section collision, truncate %d bytes\n",
+				dev_name(&ndns->dev), start_pad + end_trunc);
+
+	/*
+	 * Note, we use 64 here for the standard size of struct page,
+	 * debugging options may cause it to be larger in which case the
+	 * implementation will limit the pfns advertised through
+	 * ->direct_access() to those that are included in the memmap.
+	 */
+	start += start_pad;
+	size = resource_size(&nsio->res);
+	npfns = (size - start_pad - end_trunc - SZ_8K) / SZ_4K;
+	if (nd_pfn->mode == PFN_MODE_PMEM)
+		offset = ALIGN(start + SZ_8K + 64 * npfns, nd_pfn->align)
+			- start;
+	else if (nd_pfn->mode == PFN_MODE_RAM)
+		offset = ALIGN(start + SZ_8K, nd_pfn->align) - start;
+	else
+		return -ENXIO;
+
+	if (offset + start_pad + end_trunc >= size) {
+		dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
+				dev_name(&ndns->dev));
+		return -ENXIO;
+	}
+
+	npfns = (size - offset - start_pad - end_trunc) / SZ_4K;
+	pfn_sb->mode = cpu_to_le32(nd_pfn->mode);
+	pfn_sb->dataoff = cpu_to_le64(offset);
+	pfn_sb->npfns = cpu_to_le64(npfns);
+	memcpy(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN);
+	memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
+	memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
+	pfn_sb->version_major = cpu_to_le16(1);
+	pfn_sb->version_minor = cpu_to_le16(1);
+	pfn_sb->start_pad = cpu_to_le32(start_pad);
+	pfn_sb->end_trunc = cpu_to_le32(end_trunc);
+	checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
+	pfn_sb->checksum = cpu_to_le64(checksum);
+
+	return nvdimm_write_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb));
+}
+
+/*
+ * Determine the effective resource range and vmem_altmap from an nd_pfn
+ * instance.
+ */
+struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap)
+{
+	int rc;
+
+	if (!nd_pfn->uuid || !nd_pfn->ndns)
+		return ERR_PTR(-ENODEV);
+
+	rc = nd_pfn_init(nd_pfn);
+	if (rc)
+		return ERR_PTR(rc);
+
+	/* we need a valid pfn_sb before we can init a vmem_altmap */
+	return __nvdimm_setup_pfn(nd_pfn, res, altmap);
+}
+EXPORT_SYMBOL_GPL(nvdimm_setup_pfn);
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 03bfb3422da1..616a16cd655b 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -182,9 +182,6 @@ void pmem_release_disk(void *disk)
 	put_disk(disk);
 }
 
-static struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
-		struct resource *res, struct vmem_altmap *altmap);
-
 static int pmem_attach_disk(struct device *dev,
 		struct nd_namespace_common *ndns)
 {
@@ -296,187 +293,6 @@ static int pmem_attach_disk(struct device *dev,
 	return 0;
 }
 
-static int nd_pfn_init(struct nd_pfn *nd_pfn)
-{
-	struct pmem_device *pmem = dev_get_drvdata(&nd_pfn->dev);
-	struct nd_namespace_common *ndns = nd_pfn->ndns;
-	u32 start_pad = 0, end_trunc = 0;
-	resource_size_t start, size;
-	struct nd_namespace_io *nsio;
-	struct nd_region *nd_region;
-	struct nd_pfn_sb *pfn_sb;
-	unsigned long npfns;
-	phys_addr_t offset;
-	u64 checksum;
-	int rc;
-
-	pfn_sb = devm_kzalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
-	if (!pfn_sb)
-		return -ENOMEM;
-
-	nd_pfn->pfn_sb = pfn_sb;
-	rc = nd_pfn_validate(nd_pfn);
-	if (rc == -ENODEV)
-		/* no info block, do init */;
-	else
-		return rc;
-
-	nd_region = to_nd_region(nd_pfn->dev.parent);
-	if (nd_region->ro) {
-		dev_info(&nd_pfn->dev,
-				"%s is read-only, unable to init metadata\n",
-				dev_name(&nd_region->dev));
-		return -ENXIO;
-	}
-
-	memset(pfn_sb, 0, sizeof(*pfn_sb));
-
-	/*
-	 * Check if pmem collides with 'System RAM' when section aligned and
-	 * trim it accordingly
-	 */
-	nsio = to_nd_namespace_io(&ndns->dev);
-	start = PHYS_SECTION_ALIGN_DOWN(nsio->res.start);
-	size = resource_size(&nsio->res);
-	if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
-				IORES_DESC_NONE) == REGION_MIXED) {
-
-		start = nsio->res.start;
-		start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
-	}
-
-	start = nsio->res.start;
-	size = PHYS_SECTION_ALIGN_UP(start + size) - start;
-	if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
-				IORES_DESC_NONE) == REGION_MIXED) {
-		size = resource_size(&nsio->res);
-		end_trunc = start + size - PHYS_SECTION_ALIGN_DOWN(start + size);
-	}
-
-	if (start_pad + end_trunc)
-		dev_info(&nd_pfn->dev, "%s section collision, truncate %d bytes\n",
-				dev_name(&ndns->dev), start_pad + end_trunc);
-
-	/*
-	 * Note, we use 64 here for the standard size of struct page,
-	 * debugging options may cause it to be larger in which case the
-	 * implementation will limit the pfns advertised through
-	 * ->direct_access() to those that are included in the memmap.
-	 */
-	start += start_pad;
-	npfns = (pmem->size - start_pad - end_trunc - SZ_8K) / SZ_4K;
-	if (nd_pfn->mode == PFN_MODE_PMEM)
-		offset = ALIGN(start + SZ_8K + 64 * npfns, nd_pfn->align)
-			- start;
-	else if (nd_pfn->mode == PFN_MODE_RAM)
-		offset = ALIGN(start + SZ_8K, nd_pfn->align) - start;
-	else
-		return -ENXIO;
-
-	if (offset + start_pad + end_trunc >= pmem->size) {
-		dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
-				dev_name(&ndns->dev));
-		return -ENXIO;
-	}
-
-	npfns = (pmem->size - offset - start_pad - end_trunc) / SZ_4K;
-	pfn_sb->mode = cpu_to_le32(nd_pfn->mode);
-	pfn_sb->dataoff = cpu_to_le64(offset);
-	pfn_sb->npfns = cpu_to_le64(npfns);
-	memcpy(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN);
-	memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
-	memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
-	pfn_sb->version_major = cpu_to_le16(1);
-	pfn_sb->version_minor = cpu_to_le16(1);
-	pfn_sb->start_pad = cpu_to_le32(start_pad);
-	pfn_sb->end_trunc = cpu_to_le32(end_trunc);
-	checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
-	pfn_sb->checksum = cpu_to_le64(checksum);
-
-	return nvdimm_write_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb));
-}
-
-/*
- * We hotplug memory at section granularity, pad the reserved area from
- * the previous section base to the namespace base address.
- */
-static unsigned long init_altmap_base(resource_size_t base)
-{
-	unsigned long base_pfn = PHYS_PFN(base);
-
-	return PFN_SECTION_ALIGN_DOWN(base_pfn);
-}
-
-static unsigned long init_altmap_reserve(resource_size_t base)
-{
-	unsigned long reserve = PHYS_PFN(SZ_8K);
-	unsigned long base_pfn = PHYS_PFN(base);
-
-	reserve += base_pfn - PFN_SECTION_ALIGN_DOWN(base_pfn);
-	return reserve;
-}
-
-static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
-		struct resource *res, struct vmem_altmap *altmap)
-{
-	struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
-	u64 offset = le64_to_cpu(pfn_sb->dataoff);
-	u32 start_pad = __le32_to_cpu(pfn_sb->start_pad);
-	u32 end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
-	struct nd_namespace_common *ndns = nd_pfn->ndns;
-	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
-	resource_size_t base = nsio->res.start + start_pad;
-	struct vmem_altmap __altmap = {
-		.base_pfn = init_altmap_base(base),
-		.reserve = init_altmap_reserve(base),
-	};
-
-	memcpy(res, &nsio->res, sizeof(*res));
-	res->start += start_pad;
-	res->end -= end_trunc;
-
-	nd_pfn->mode = le32_to_cpu(nd_pfn->pfn_sb->mode);
-	if (nd_pfn->mode == PFN_MODE_RAM) {
-		if (offset < SZ_8K)
-			return ERR_PTR(-EINVAL);
-		nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
-		altmap = NULL;
-	} else if (nd_pfn->mode == PFN_MODE_PMEM) {
-		nd_pfn->npfns = (resource_size(res) - offset) / PAGE_SIZE;
-		if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
-			dev_info(&nd_pfn->dev,
-					"number of pfns truncated from %lld to %ld\n",
-					le64_to_cpu(nd_pfn->pfn_sb->npfns),
-					nd_pfn->npfns);
-		memcpy(altmap, &__altmap, sizeof(*altmap));
-		altmap->free = PHYS_PFN(offset - SZ_8K);
-		altmap->alloc = 0;
-	} else
-		return ERR_PTR(-ENXIO);
-
-	return altmap;
-}
-
-/*
- * Determine the effective resource range and vmem_altmap from an nd_pfn
- * instance.
- */
-static struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
-		struct resource *res, struct vmem_altmap *altmap)
-{
-	int rc;
-
-	if (!nd_pfn->uuid || !nd_pfn->ndns)
-		return ERR_PTR(-ENODEV);
-
-	rc = nd_pfn_init(nd_pfn);
-	if (rc)
-		return ERR_PTR(rc);
-
-	/* we need a valid pfn_sb before we can init a vmem_altmap */
-	return __nvdimm_setup_pfn(nd_pfn, res, altmap);
-}
-
 static int nd_pmem_probe(struct device *dev)
 {
 	struct nd_namespace_common *ndns;

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 13/13] libnvdimm, pmem: kill ->pmem_queue and ->pmem_disk
  2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
                   ` (11 preceding siblings ...)
  2016-03-24  1:26 ` [PATCH 12/13] libnvdimm, pmem, pfn: move pfn setup to the core Dan Williams
@ 2016-03-24  1:26 ` Dan Williams
  2016-03-24 14:38   ` Johannes Thumshirn
  12 siblings, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-24  1:26 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: linux-kernel

The devm conversion obviates the need to continue to remember the queue
and disk locally in the driver.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/nvdimm/pmem.c |   21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 616a16cd655b..0cd7c6529497 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -33,9 +33,6 @@
 #include "nd.h"
 
 struct pmem_device {
-	struct request_queue	*pmem_queue;
-	struct gendisk		*pmem_disk;
-
 	/* One contiguous memory region per device */
 	phys_addr_t		phys_addr;
 	/* when non-zero this device is hosting a 'pfn' instance */
@@ -52,7 +49,7 @@ struct pmem_device {
 static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
 		unsigned int len)
 {
-	struct device *dev = disk_to_dev(pmem->pmem_disk);
+	struct device *dev = pmem->bb.dev;
 	sector_t sector;
 	long cleared;
 
@@ -227,7 +224,6 @@ static int pmem_attach_disk(struct device *dev,
 	q = blk_alloc_queue_node(GFP_KERNEL, dev_to_node(dev));
 	if (!q)
 		return -ENOMEM;
-	pmem->pmem_queue = q;
 
 	pmem->pfn_flags = PFN_DEV;
 	if (is_nd_pfn(dev)) {
@@ -260,12 +256,12 @@ static int pmem_attach_disk(struct device *dev,
 		return PTR_ERR(addr);
 	pmem->virt_addr = (void __pmem *) addr;
 
-	blk_queue_make_request(pmem->pmem_queue, pmem_make_request);
-	blk_queue_physical_block_size(pmem->pmem_queue, PAGE_SIZE);
-	blk_queue_max_hw_sectors(pmem->pmem_queue, UINT_MAX);
-	blk_queue_bounce_limit(pmem->pmem_queue, BLK_BOUNCE_ANY);
-	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, pmem->pmem_queue);
-	pmem->pmem_queue->queuedata = pmem;
+	blk_queue_make_request(q, pmem_make_request);
+	blk_queue_physical_block_size(q, PAGE_SIZE);
+	blk_queue_max_hw_sectors(q, UINT_MAX);
+	blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
+	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
+	q->queuedata = pmem;
 
 	disk = alloc_disk_node(0, nid);
 	if (!disk)
@@ -276,13 +272,12 @@ static int pmem_attach_disk(struct device *dev,
 	}
 
 	disk->fops		= &pmem_fops;
-	disk->queue		= pmem->pmem_queue;
+	disk->queue		= q;
 	disk->flags		= GENHD_FL_EXT_DEVT;
 	nvdimm_namespace_disk_name(ndns, disk->disk_name);
 	disk->driverfs_dev = dev;
 	set_capacity(disk, (pmem->size - pmem->pfn_pad - pmem->data_offset)
 			/ 512);
-	pmem->pmem_disk = disk;
 	if (devm_init_badblocks(dev, &pmem->bb))
 		return -ENOMEM;
 	nvdimm_badblocks_populate(to_nd_region(dev->parent), &pmem->bb, res);

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [PATCH 01/13] libnvdimm, pfn: fix nvdimm_namespace_add_poison() vs section alignment
  2016-03-24  1:25 ` [PATCH 01/13] libnvdimm, pfn: fix nvdimm_namespace_add_poison() vs section alignment Dan Williams
@ 2016-03-24 10:10   ` Johannes Thumshirn
  2016-03-24 14:48     ` Dan Williams
  0 siblings, 1 reply; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 10:10 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel, stable

On Mittwoch, 23. März 2016 18:25:26 CET Dan Williams wrote:
> When section alignment padding is in effect we need to shift / truncate
> the range that is queried for poison by the 'start_pad' or 'end_trunc'
> reservations.
> 
> It's easiest if we just pass in an adjusted resource range rather than
> deriving it from the passed in namespace.  With the resource range
> resolution pushed out to the caller we can also push the
> namespace-to-region lookup to the caller and drop the implicit pmem-type
> assumption about the passed in namespace object.
> 
> Cc: Vishal Verma <vishal.l.verma@intel.com>
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>

Does this really qualify for inclusion into stable?

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 02/13] libnvdimm, pmem: kill pmem->ndns
  2016-03-24  1:25 ` [PATCH 02/13] libnvdimm, pmem: kill pmem->ndns Dan Williams
@ 2016-03-24 10:31   ` Johannes Thumshirn
  0 siblings, 0 replies; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 10:31 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Mittwoch, 23. März 2016 18:25:32 CET Dan Williams wrote:
> We can derive the common namespace from other information.  We also do
> not need to cache it because all the usages are in slow paths.
> 
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 03/13] libnvdimm, pfn, convert nd_pfn_probe() to devm
  2016-03-24  1:25 ` [PATCH 03/13] libnvdimm, pfn, convert nd_pfn_probe() to devm Dan Williams
@ 2016-03-24 10:45   ` Johannes Thumshirn
  0 siblings, 0 replies; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 10:45 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Mittwoch, 23. März 2016 18:25:37 CET Dan Williams wrote:
> Pass the device performing the probe so we can use a devm allocation for
> the pfn superblock.
> 
> Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>

Looks OK to me.

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 04/13] libnvdimm, btt, convert nd_btt_probe() to devm
  2016-03-24  1:25 ` [PATCH 04/13] libnvdimm, btt, convert nd_btt_probe() " Dan Williams
@ 2016-03-24 11:05   ` Johannes Thumshirn
  0 siblings, 0 replies; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 11:05 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Mittwoch, 23. März 2016 18:25:42 CET Dan Williams wrote:
> Pass the device performing the probe so we can use a devm allocation for
> the btt superblock.
> 
> Cc: Vishal Verma <vishal.l.verma@intel.com>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 05/13] libnvdimm, blk: use devm_add_action to release bdev resources
  2016-03-24  1:25 ` [PATCH 05/13] libnvdimm, blk: use devm_add_action to release bdev resources Dan Williams
@ 2016-03-24 11:48   ` Johannes Thumshirn
  2016-03-24 15:14     ` Dan Williams
  0 siblings, 1 reply; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 11:48 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Mittwoch, 23. März 2016 18:25:47 CET Dan Williams wrote:
> Register a callback to clean up the request_queue and put the gendisk at
> driver disable time.
> 
> Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>

[...]

> 
>  static int nd_blk_remove(struct device *dev)
>  {
> -	struct nd_blk_device *blk_dev = dev_get_drvdata(dev);
> -
>  	if (is_nd_btt(dev))
>  		nvdimm_namespace_detach_btt(to_nd_btt(dev));
> -	else
> -		nd_blk_detach_disk(blk_dev);
> -	kfree(blk_dev);
> -
>  	return 0;
>  }
> 

Can't this be void?

> 
> _______________________________________________
> Linux-nvdimm mailing list
> Linux-nvdimm@lists.01.org
> https://lists.01.org/mailman/listinfo/linux-nvdimm


-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 06/13] libnvdimm, blk: use ->queuedata for driver private data
  2016-03-24  1:25 ` [PATCH 06/13] libnvdimm, blk: use ->queuedata for driver private data Dan Williams
@ 2016-03-24 11:51   ` Johannes Thumshirn
  0 siblings, 0 replies; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 11:51 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Mittwoch, 23. März 2016 18:25:52 CET Dan Williams wrote:
> Save a pointer chase by storing the driver private data in the
> request_queue rather than the gendisk.
> 
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 07/13] libnvdimm, pmem: use ->queuedata for driver private data
  2016-03-24  1:25 ` [PATCH 07/13] libnvdimm, pmem: " Dan Williams
@ 2016-03-24 12:06   ` Johannes Thumshirn
  0 siblings, 0 replies; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 12:06 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Mittwoch, 23. März 2016 18:25:58 CET Dan Williams wrote:
> Save a pointer chase by storing the driver private data in the
> request_queue rather than the gendisk.
> 
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 08/13] libnvdimm, blk: move i/o infrastructure to nd_namespace_blk
  2016-03-24  1:26 ` [PATCH 08/13] libnvdimm, blk: move i/o infrastructure to nd_namespace_blk Dan Williams
@ 2016-03-24 12:22   ` Johannes Thumshirn
  2016-03-24 15:21     ` Dan Williams
  2016-03-25 22:02   ` [PATCH v2] " Dan Williams
  1 sibling, 1 reply; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 12:22 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Mittwoch, 23. März 2016 18:26:03 CET Dan Williams wrote:
> Consolidate the information for issuing i/o to a blk-namespace, and
> eliminate some pointer chasing.
> 
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
[...]
>  		BUG_ON(len > PAGE_SIZE);
> -		err = nd_blk_do_bvec(blk_dev, bip, bvec.bv_page, len,
> -					bvec.bv_offset, rw, iter.bi_sector);
> +		err = nsblk_do_bvec(nsblk, bip, bvec.bv_page, len,
> +				bvec.bv_offset, rw, iter.bi_sector);
>  		if (err) {
> -			dev_info(&blk_dev->nsblk->common.dev,
> +			dev_dbg(&nsblk->common.dev,
>  					"io error in %s sector %lld, len %d,\n",
>  					(rw == READ) ? "READ" : "WRITE",
>  					(unsigned long long) iter.bi_sector, len);

Why is an I/O error suddently a debug message instead of an error?

Otherwise
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 09/13] libnvdimm, pmem: use devm_add_action to release bdev resources
  2016-03-24  1:26 ` [PATCH 09/13] libnvdimm, pmem: use devm_add_action to release bdev resources Dan Williams
@ 2016-03-24 12:35   ` Johannes Thumshirn
  0 siblings, 0 replies; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 12:35 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Mittwoch, 23. März 2016 18:26:08 CET Dan Williams wrote:
> Register a callback to clean up the request_queue and put the gendisk at
> driver disable time.
> 
> Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 10/13] libnvdimm, pmem: clean up resource print / request
  2016-03-24  1:26 ` [PATCH 10/13] libnvdimm, pmem: clean up resource print / request Dan Williams
@ 2016-03-24 13:42   ` Johannes Thumshirn
  0 siblings, 0 replies; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 13:42 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Mittwoch, 23. März 2016 18:26:13 CET Dan Williams wrote:
> The leading '0x' in front of %pa is redundant, also we can just use %pR
> to simplify the print statement.  The request parameters can be directly
> taken from the resource as well.
> 
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 11/13] libnvdimm, pmem, pfn: make pmem_rw_bytes generic and refactor pfn setup
  2016-03-24  1:26 ` [PATCH 11/13] libnvdimm, pmem, pfn: make pmem_rw_bytes generic and refactor pfn setup Dan Williams
@ 2016-03-24 13:50   ` Johannes Thumshirn
  2016-03-25 22:13   ` [PATCH v2] " Dan Williams
  1 sibling, 0 replies; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 13:50 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Mittwoch, 23. März 2016 18:26:18 CET Dan Williams wrote:
> In preparation for providing an alternative (to block device) access
> mechanism to persistent memory, convert pmem_rw_bytes() to
> nsio_rw_bytes().  This allows ->rw_bytes() functionality without
> requiring a 'struct pmem_device' to be instantiated.
> 
> In other words, when ->rw_bytes() is in use i/o is driven through
> 'struct nd_namespace_io', otherwise it is driven through 'struct
> pmem_device' and the block layer.  This consolidates the disjoint calls
> to devm_exit_badblocks() and devm_memunmap() into a common
> devm_nsio_disable() and cleans up the init path to use a unified
> pmem_attach_disk() implementation.
> 
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 12/13] libnvdimm, pmem, pfn: move pfn setup to the core
  2016-03-24  1:26 ` [PATCH 12/13] libnvdimm, pmem, pfn: move pfn setup to the core Dan Williams
@ 2016-03-24 14:36   ` Johannes Thumshirn
  2016-03-24 15:26     ` Dan Williams
  2016-03-25 22:15   ` [PATCH v2] " Dan Williams
  1 sibling, 1 reply; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 14:36 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Mittwoch, 23. März 2016 18:26:24 CET Dan Williams wrote:
> Now that pmem internals have been disentangled from pfn setup, that code
> can move to the core.  This is in preparation for adding another user of
> the pfn-device capabilities.
> 
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
>  drivers/nvdimm/nd.h       |    7 ++
>  drivers/nvdimm/pfn_devs.c |  183
> +++++++++++++++++++++++++++++++++++++++++++++ drivers/nvdimm/pmem.c     | 
> 184 --------------------------------------------- 3 files changed, 190
> insertions(+), 184 deletions(-)
> 
> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
> index a42c823c0a67..8e563c4a3e8c 100644
> --- a/drivers/nvdimm/nd.h
> +++ b/drivers/nvdimm/nd.h
> @@ -272,9 +272,16 @@ const char *nvdimm_namespace_disk_name(struct
> nd_namespace_common *ndns, void nvdimm_badblocks_populate(struct nd_region
> *nd_region,
>  		struct badblocks *bb, const struct resource *res);
>  #if IS_ENABLED(CONFIG_ND_CLAIM)
> +struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
> +		struct resource *res, struct vmem_altmap *altmap);
>  int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio);
>  void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio);
>  #else
> +static inline struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
> +		struct resource *res, struct vmem_altmap *altmap)
> +{
> +	return ERR_PTR(-ENXIO);
> +}
>  static inline int devm_nsio_enable(struct device *dev,
>  		struct nd_namespace_io *nsio)
>  {
> diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
> index f8fd379501bf..51a214ee75a7 100644
> --- a/drivers/nvdimm/pfn_devs.c
> +++ b/drivers/nvdimm/pfn_devs.c
> @@ -10,6 +10,7 @@
>   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>   * General Public License for more details.
>   */
> +#include <linux/memremap.h>
>  #include <linux/blkdev.h>
>  #include <linux/device.h>
>  #include <linux/genhd.h>
> @@ -441,3 +442,185 @@ int nd_pfn_probe(struct device *dev, struct
> nd_namespace_common *ndns) return rc;
>  }
>  EXPORT_SYMBOL(nd_pfn_probe);
> +
> +/*
> + * We hotplug memory at section granularity, pad the reserved area from
> + * the previous section base to the namespace base address.
> + */
> +static unsigned long init_altmap_base(resource_size_t base)
> +{
> +	unsigned long base_pfn = PHYS_PFN(base);
> +
> +	return PFN_SECTION_ALIGN_DOWN(base_pfn);
> +}
> +
> +static unsigned long init_altmap_reserve(resource_size_t base)
> +{
> +	unsigned long reserve = PHYS_PFN(SZ_8K);
> +	unsigned long base_pfn = PHYS_PFN(base);
> +
> +	reserve += base_pfn - PFN_SECTION_ALIGN_DOWN(base_pfn);
> +	return reserve;
> +}
> +
> +static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
> +		struct resource *res, struct vmem_altmap *altmap)
> +{
> +	struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
> +	u64 offset = le64_to_cpu(pfn_sb->dataoff);
> +	u32 start_pad = __le32_to_cpu(pfn_sb->start_pad);
> +	u32 end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
> +	struct nd_namespace_common *ndns = nd_pfn->ndns;
> +	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
> +	resource_size_t base = nsio->res.start + start_pad;
> +	struct vmem_altmap __altmap = {
> +		.base_pfn = init_altmap_base(base),
> +		.reserve = init_altmap_reserve(base),
> +	};
> +
> +	memcpy(res, &nsio->res, sizeof(*res));
> +	res->start += start_pad;
> +	res->end -= end_trunc;
> +
> +	nd_pfn->mode = le32_to_cpu(nd_pfn->pfn_sb->mode);
> +	if (nd_pfn->mode == PFN_MODE_RAM) {
> +		if (offset < SZ_8K)
> +			return ERR_PTR(-EINVAL);
> +		nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
> +		altmap = NULL;
> +	} else if (nd_pfn->mode == PFN_MODE_PMEM) {
> +		nd_pfn->npfns = (resource_size(res) - offset) / PAGE_SIZE;
> +		if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
> +			dev_info(&nd_pfn->dev,
> +					"number of pfns truncated from %lld to %ld\n",
> +					le64_to_cpu(nd_pfn->pfn_sb->npfns),
> +					nd_pfn->npfns);
> +		memcpy(altmap, &__altmap, sizeof(*altmap));
> +		altmap->free = PHYS_PFN(offset - SZ_8K);
> +		altmap->alloc = 0;
> +	} else
> +		return ERR_PTR(-ENXIO);
> +
> +	return altmap;
> +}
> +
> +static int nd_pfn_init(struct nd_pfn *nd_pfn)
> +{
> +	struct nd_namespace_common *ndns = nd_pfn->ndns;
> +	u32 start_pad = 0, end_trunc = 0;
> +	resource_size_t start, size;
> +	struct nd_namespace_io *nsio;
> +	struct nd_region *nd_region;
> +	struct nd_pfn_sb *pfn_sb;
> +	unsigned long npfns;
> +	phys_addr_t offset;
> +	u64 checksum;
> +	int rc;
> +
> +	pfn_sb = devm_kzalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
> +	if (!pfn_sb)
> +		return -ENOMEM;
> +
> +	nd_pfn->pfn_sb = pfn_sb;
> +	rc = nd_pfn_validate(nd_pfn);
> +	if (rc == -ENODEV)
> +		/* no info block, do init */;
> +	else
> +		return rc;

Why not:
if (rc != -ENODEV)
	return  rc;
/* no info block, do init */


> +
> +	nd_region = to_nd_region(nd_pfn->dev.parent);
> +	if (nd_region->ro) {
> +		dev_info(&nd_pfn->dev,
> +				"%s is read-only, unable to init metadata\n",
> +				dev_name(&nd_region->dev));
> +		return -ENXIO;
> +	}
> +
> +	memset(pfn_sb, 0, sizeof(*pfn_sb));
> +
> +	/*
> +	 * Check if pmem collides with 'System RAM' when section aligned and
> +	 * trim it accordingly
> +	 */
> +	nsio = to_nd_namespace_io(&ndns->dev);
> +	start = PHYS_SECTION_ALIGN_DOWN(nsio->res.start);
> +	size = resource_size(&nsio->res);
> +	if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
> +				IORES_DESC_NONE) == REGION_MIXED) {
> +
> +		start = nsio->res.start;
> +		start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
> +	}
> +
> +	start = nsio->res.start;
> +	size = PHYS_SECTION_ALIGN_UP(start + size) - start;
> +	if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
> +				IORES_DESC_NONE) == REGION_MIXED) {
> +		size = resource_size(&nsio->res);
> +		end_trunc = start + size - PHYS_SECTION_ALIGN_DOWN(start + size);
> +	}
> +
> +	if (start_pad + end_trunc)
> +		dev_info(&nd_pfn->dev, "%s section collision, truncate %d bytes\n",
> +				dev_name(&ndns->dev), start_pad + end_trunc);
> +
> +	/*
> +	 * Note, we use 64 here for the standard size of struct page,
> +	 * debugging options may cause it to be larger in which case the
> +	 * implementation will limit the pfns advertised through
> +	 * ->direct_access() to those that are included in the memmap.
> +	 */
> +	start += start_pad;
> +	size = resource_size(&nsio->res);
> +	npfns = (size - start_pad - end_trunc - SZ_8K) / SZ_4K;
> +	if (nd_pfn->mode == PFN_MODE_PMEM)
> +		offset = ALIGN(start + SZ_8K + 64 * npfns, nd_pfn->align)
> +			- start;
> +	else if (nd_pfn->mode == PFN_MODE_RAM)
> +		offset = ALIGN(start + SZ_8K, nd_pfn->align) - start;
> +	else
> +		return -ENXIO;
> +
> +	if (offset + start_pad + end_trunc >= size) {
> +		dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
> +				dev_name(&ndns->dev));
> +		return -ENXIO;
> +	}
> +
> +	npfns = (size - offset - start_pad - end_trunc) / SZ_4K;
> +	pfn_sb->mode = cpu_to_le32(nd_pfn->mode);
> +	pfn_sb->dataoff = cpu_to_le64(offset);
> +	pfn_sb->npfns = cpu_to_le64(npfns);
> +	memcpy(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN);
> +	memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
> +	memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
> +	pfn_sb->version_major = cpu_to_le16(1);
> +	pfn_sb->version_minor = cpu_to_le16(1);
> +	pfn_sb->start_pad = cpu_to_le32(start_pad);
> +	pfn_sb->end_trunc = cpu_to_le32(end_trunc);
> +	checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
> +	pfn_sb->checksum = cpu_to_le64(checksum);
> +
> +	return nvdimm_write_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb));
> +}
> +
> +/*
> + * Determine the effective resource range and vmem_altmap from an nd_pfn
> + * instance.
> + */
> +struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
> +		struct resource *res, struct vmem_altmap *altmap)
> +{
> +	int rc;
> +
> +	if (!nd_pfn->uuid || !nd_pfn->ndns)
> +		return ERR_PTR(-ENODEV);
> +
> +	rc = nd_pfn_init(nd_pfn);
> +	if (rc)
> +		return ERR_PTR(rc);
> +
> +	/* we need a valid pfn_sb before we can init a vmem_altmap */
> +	return __nvdimm_setup_pfn(nd_pfn, res, altmap);
> +}
> +EXPORT_SYMBOL_GPL(nvdimm_setup_pfn);
> diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
> index 03bfb3422da1..616a16cd655b 100644
> --- a/drivers/nvdimm/pmem.c
> +++ b/drivers/nvdimm/pmem.c
> @@ -182,9 +182,6 @@ void pmem_release_disk(void *disk)
>  	put_disk(disk);
>  }
> 
> -static struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
> -		struct resource *res, struct vmem_altmap *altmap);
> -
>  static int pmem_attach_disk(struct device *dev,
>  		struct nd_namespace_common *ndns)
>  {
> @@ -296,187 +293,6 @@ static int pmem_attach_disk(struct device *dev,
>  	return 0;
>  }
> 
> -static int nd_pfn_init(struct nd_pfn *nd_pfn)
> -{
> -	struct pmem_device *pmem = dev_get_drvdata(&nd_pfn->dev);
> -	struct nd_namespace_common *ndns = nd_pfn->ndns;
> -	u32 start_pad = 0, end_trunc = 0;
> -	resource_size_t start, size;
> -	struct nd_namespace_io *nsio;
> -	struct nd_region *nd_region;
> -	struct nd_pfn_sb *pfn_sb;
> -	unsigned long npfns;
> -	phys_addr_t offset;
> -	u64 checksum;
> -	int rc;
> -
> -	pfn_sb = devm_kzalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
> -	if (!pfn_sb)
> -		return -ENOMEM;
> -
> -	nd_pfn->pfn_sb = pfn_sb;
> -	rc = nd_pfn_validate(nd_pfn);
> -	if (rc == -ENODEV)
> -		/* no info block, do init */;
> -	else
> -		return rc;
> -
> -	nd_region = to_nd_region(nd_pfn->dev.parent);
> -	if (nd_region->ro) {
> -		dev_info(&nd_pfn->dev,
> -				"%s is read-only, unable to init metadata\n",
> -				dev_name(&nd_region->dev));
> -		return -ENXIO;
> -	}
> -
> -	memset(pfn_sb, 0, sizeof(*pfn_sb));
> -
> -	/*
> -	 * Check if pmem collides with 'System RAM' when section aligned and
> -	 * trim it accordingly
> -	 */
> -	nsio = to_nd_namespace_io(&ndns->dev);
> -	start = PHYS_SECTION_ALIGN_DOWN(nsio->res.start);
> -	size = resource_size(&nsio->res);
> -	if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
> -				IORES_DESC_NONE) == REGION_MIXED) {
> -
> -		start = nsio->res.start;
> -		start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
> -	}
> -
> -	start = nsio->res.start;
> -	size = PHYS_SECTION_ALIGN_UP(start + size) - start;
> -	if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
> -				IORES_DESC_NONE) == REGION_MIXED) {
> -		size = resource_size(&nsio->res);
> -		end_trunc = start + size - PHYS_SECTION_ALIGN_DOWN(start + size);
> -	}
> -
> -	if (start_pad + end_trunc)
> -		dev_info(&nd_pfn->dev, "%s section collision, truncate %d bytes\n",
> -				dev_name(&ndns->dev), start_pad + end_trunc);
> -
> -	/*
> -	 * Note, we use 64 here for the standard size of struct page,
> -	 * debugging options may cause it to be larger in which case the
> -	 * implementation will limit the pfns advertised through
> -	 * ->direct_access() to those that are included in the memmap.
> -	 */
> -	start += start_pad;
> -	npfns = (pmem->size - start_pad - end_trunc - SZ_8K) / SZ_4K;
> -	if (nd_pfn->mode == PFN_MODE_PMEM)
> -		offset = ALIGN(start + SZ_8K + 64 * npfns, nd_pfn->align)
> -			- start;
> -	else if (nd_pfn->mode == PFN_MODE_RAM)
> -		offset = ALIGN(start + SZ_8K, nd_pfn->align) - start;
> -	else
> -		return -ENXIO;
> -
> -	if (offset + start_pad + end_trunc >= pmem->size) {
> -		dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
> -				dev_name(&ndns->dev));
> -		return -ENXIO;
> -	}
> -
> -	npfns = (pmem->size - offset - start_pad - end_trunc) / SZ_4K;
> -	pfn_sb->mode = cpu_to_le32(nd_pfn->mode);
> -	pfn_sb->dataoff = cpu_to_le64(offset);
> -	pfn_sb->npfns = cpu_to_le64(npfns);
> -	memcpy(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN);
> -	memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
> -	memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
> -	pfn_sb->version_major = cpu_to_le16(1);
> -	pfn_sb->version_minor = cpu_to_le16(1);
> -	pfn_sb->start_pad = cpu_to_le32(start_pad);
> -	pfn_sb->end_trunc = cpu_to_le32(end_trunc);
> -	checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
> -	pfn_sb->checksum = cpu_to_le64(checksum);
> -
> -	return nvdimm_write_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb));
> -}
> -
> -/*
> - * We hotplug memory at section granularity, pad the reserved area from
> - * the previous section base to the namespace base address.
> - */
> -static unsigned long init_altmap_base(resource_size_t base)
> -{
> -	unsigned long base_pfn = PHYS_PFN(base);
> -
> -	return PFN_SECTION_ALIGN_DOWN(base_pfn);
> -}
> -
> -static unsigned long init_altmap_reserve(resource_size_t base)
> -{
> -	unsigned long reserve = PHYS_PFN(SZ_8K);
> -	unsigned long base_pfn = PHYS_PFN(base);
> -
> -	reserve += base_pfn - PFN_SECTION_ALIGN_DOWN(base_pfn);
> -	return reserve;
> -}
> -
> -static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
> -		struct resource *res, struct vmem_altmap *altmap)
> -{
> -	struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
> -	u64 offset = le64_to_cpu(pfn_sb->dataoff);
> -	u32 start_pad = __le32_to_cpu(pfn_sb->start_pad);
> -	u32 end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
> -	struct nd_namespace_common *ndns = nd_pfn->ndns;
> -	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
> -	resource_size_t base = nsio->res.start + start_pad;
> -	struct vmem_altmap __altmap = {
> -		.base_pfn = init_altmap_base(base),
> -		.reserve = init_altmap_reserve(base),
> -	};
> -
> -	memcpy(res, &nsio->res, sizeof(*res));
> -	res->start += start_pad;
> -	res->end -= end_trunc;
> -
> -	nd_pfn->mode = le32_to_cpu(nd_pfn->pfn_sb->mode);
> -	if (nd_pfn->mode == PFN_MODE_RAM) {
> -		if (offset < SZ_8K)
> -			return ERR_PTR(-EINVAL);
> -		nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
> -		altmap = NULL;
> -	} else if (nd_pfn->mode == PFN_MODE_PMEM) {
> -		nd_pfn->npfns = (resource_size(res) - offset) / PAGE_SIZE;
> -		if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
> -			dev_info(&nd_pfn->dev,
> -					"number of pfns truncated from %lld to %ld\n",
> -					le64_to_cpu(nd_pfn->pfn_sb->npfns),
> -					nd_pfn->npfns);
> -		memcpy(altmap, &__altmap, sizeof(*altmap));
> -		altmap->free = PHYS_PFN(offset - SZ_8K);
> -		altmap->alloc = 0;
> -	} else
> -		return ERR_PTR(-ENXIO);
> -
> -	return altmap;
> -}
> -
> -/*
> - * Determine the effective resource range and vmem_altmap from an nd_pfn
> - * instance.
> - */
> -static struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
> -		struct resource *res, struct vmem_altmap *altmap)
> -{
> -	int rc;
> -
> -	if (!nd_pfn->uuid || !nd_pfn->ndns)
> -		return ERR_PTR(-ENODEV);
> -
> -	rc = nd_pfn_init(nd_pfn);
> -	if (rc)
> -		return ERR_PTR(rc);
> -
> -	/* we need a valid pfn_sb before we can init a vmem_altmap */
> -	return __nvdimm_setup_pfn(nd_pfn, res, altmap);
> -}
> -
>  static int nd_pmem_probe(struct device *dev)
>  {
>  	struct nd_namespace_common *ndns;
> 
> _______________________________________________
> Linux-nvdimm mailing list
> Linux-nvdimm@lists.01.org
> https://lists.01.org/mailman/listinfo/linux-nvdimm


-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 13/13] libnvdimm, pmem: kill ->pmem_queue and ->pmem_disk
  2016-03-24  1:26 ` [PATCH 13/13] libnvdimm, pmem: kill ->pmem_queue and ->pmem_disk Dan Williams
@ 2016-03-24 14:38   ` Johannes Thumshirn
  0 siblings, 0 replies; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 14:38 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Mittwoch, 23. März 2016 18:26:29 CET Dan Williams wrote:
> The devm conversion obviates the need to continue to remember the queue
> and disk locally in the driver.
> 
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 01/13] libnvdimm, pfn: fix nvdimm_namespace_add_poison() vs section alignment
  2016-03-24 10:10   ` Johannes Thumshirn
@ 2016-03-24 14:48     ` Dan Williams
  0 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2016-03-24 14:48 UTC (permalink / raw)
  To: Johannes Thumshirn; +Cc: linux-nvdimm@lists.01.org, linux-kernel, stable

On Thu, Mar 24, 2016 at 3:10 AM, Johannes Thumshirn <jthumshirn@suse.de> wrote:
> On Mittwoch, 23. März 2016 18:25:26 CET Dan Williams wrote:
>> When section alignment padding is in effect we need to shift / truncate
>> the range that is queried for poison by the 'start_pad' or 'end_trunc'
>> reservations.
>>
>> It's easiest if we just pass in an adjusted resource range rather than
>> deriving it from the passed in namespace.  With the resource range
>> resolution pushed out to the caller we can also push the
>> namespace-to-region lookup to the caller and drop the implicit pmem-type
>> assumption about the passed in namespace object.
>>
>> Cc: Vishal Verma <vishal.l.verma@intel.com>
>> Cc: <stable@vger.kernel.org>
>> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
>
> Does this really qualify for inclusion into stable?

Depends on when we push it.  If we wait for the 4.7 merge window this
will be -stable material to fix 4.6.  The lack of urgency is driven by
the fact that there is still time to work with BIOS implementations to
address the 128MB alignment problem.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 05/13] libnvdimm, blk: use devm_add_action to release bdev resources
  2016-03-24 11:48   ` Johannes Thumshirn
@ 2016-03-24 15:14     ` Dan Williams
  2016-03-24 15:15       ` Johannes Thumshirn
  0 siblings, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-24 15:14 UTC (permalink / raw)
  To: Johannes Thumshirn; +Cc: linux-nvdimm@lists.01.org, linux-kernel

On Thu, Mar 24, 2016 at 4:48 AM, Johannes Thumshirn <jthumshirn@suse.de> wrote:
> On Mittwoch, 23. März 2016 18:25:47 CET Dan Williams wrote:
>> Register a callback to clean up the request_queue and put the gendisk at
>> driver disable time.
>>
>> Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
>> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
>
> [...]
>
>>
>>  static int nd_blk_remove(struct device *dev)
>>  {
>> -     struct nd_blk_device *blk_dev = dev_get_drvdata(dev);
>> -
>>       if (is_nd_btt(dev))
>>               nvdimm_namespace_detach_btt(to_nd_btt(dev));
>> -     else
>> -             nd_blk_detach_disk(blk_dev);
>> -     kfree(blk_dev);
>> -
>>       return 0;
>>  }
>>
>
> Can't this be void?
>

That's not how the core defines this:

struct device_driver {
...
        int (*remove) (struct device *dev);
...
};

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 05/13] libnvdimm, blk: use devm_add_action to release bdev resources
  2016-03-24 15:14     ` Dan Williams
@ 2016-03-24 15:15       ` Johannes Thumshirn
  2016-03-24 15:21         ` Dan Williams
  0 siblings, 1 reply; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 15:15 UTC (permalink / raw)
  To: Dan Williams; +Cc: linux-nvdimm@lists.01.org, linux-kernel

On Donnerstag, 24. März 2016 08:14:10 CET Dan Williams wrote:
> On Thu, Mar 24, 2016 at 4:48 AM, Johannes Thumshirn <jthumshirn@suse.de> 
wrote:
> > On Mittwoch, 23. März 2016 18:25:47 CET Dan Williams wrote:
> >> Register a callback to clean up the request_queue and put the gendisk at
> >> driver disable time.
> >> 
> >> Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
> >> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> > 
> > [...]
> > 
> >>  static int nd_blk_remove(struct device *dev)
> >>  {
> >> 
> >> -     struct nd_blk_device *blk_dev = dev_get_drvdata(dev);
> >> -
> >> 
> >>       if (is_nd_btt(dev))
> >>       
> >>               nvdimm_namespace_detach_btt(to_nd_btt(dev));
> >> 
> >> -     else
> >> -             nd_blk_detach_disk(blk_dev);
> >> -     kfree(blk_dev);
> >> -
> >> 
> >>       return 0;
> >>  
> >>  }
> > 
> > Can't this be void?
> 
> That's not how the core defines this:
> 
> struct device_driver {
> ...
>         int (*remove) (struct device *dev);
> ...
> };

Ah OK, didn't see this, sorry

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 08/13] libnvdimm, blk: move i/o infrastructure to nd_namespace_blk
  2016-03-24 12:22   ` Johannes Thumshirn
@ 2016-03-24 15:21     ` Dan Williams
  2016-03-24 15:22       ` Johannes Thumshirn
  0 siblings, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-24 15:21 UTC (permalink / raw)
  To: Johannes Thumshirn; +Cc: linux-nvdimm@lists.01.org, linux-kernel

On Thu, Mar 24, 2016 at 5:22 AM, Johannes Thumshirn <jthumshirn@suse.de> wrote:
> On Mittwoch, 23. März 2016 18:26:03 CET Dan Williams wrote:
>> Consolidate the information for issuing i/o to a blk-namespace, and
>> eliminate some pointer chasing.
>>
>> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
>> ---
> [...]
>>               BUG_ON(len > PAGE_SIZE);
>> -             err = nd_blk_do_bvec(blk_dev, bip, bvec.bv_page, len,
>> -                                     bvec.bv_offset, rw, iter.bi_sector);
>> +             err = nsblk_do_bvec(nsblk, bip, bvec.bv_page, len,
>> +                             bvec.bv_offset, rw, iter.bi_sector);
>>               if (err) {
>> -                     dev_info(&blk_dev->nsblk->common.dev,
>> +                     dev_dbg(&nsblk->common.dev,
>>                                       "io error in %s sector %lld, len %d,\n",
>>                                       (rw == READ) ? "READ" : "WRITE",
>>                                       (unsigned long long) iter.bi_sector, len);
>
> Why is an I/O error suddently a debug message instead of an error?

True, that's a jarring change not described in the log, should
probably be its own patch.  The rationale is that upper layers already
have error prints for failed commands and this one is redundant.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 05/13] libnvdimm, blk: use devm_add_action to release bdev resources
  2016-03-24 15:15       ` Johannes Thumshirn
@ 2016-03-24 15:21         ` Dan Williams
  0 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2016-03-24 15:21 UTC (permalink / raw)
  To: Johannes Thumshirn; +Cc: linux-nvdimm@lists.01.org, linux-kernel

On Thu, Mar 24, 2016 at 8:15 AM, Johannes Thumshirn <jthumshirn@suse.de> wrote:
> On Donnerstag, 24. März 2016 08:14:10 CET Dan Williams wrote:
>> On Thu, Mar 24, 2016 at 4:48 AM, Johannes Thumshirn <jthumshirn@suse.de>
> wrote:
>> > On Mittwoch, 23. März 2016 18:25:47 CET Dan Williams wrote:
>> >> Register a callback to clean up the request_queue and put the gendisk at
>> >> driver disable time.
>> >>
>> >> Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
>> >> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
>> >
>> > [...]
>> >
>> >>  static int nd_blk_remove(struct device *dev)
>> >>  {
>> >>
>> >> -     struct nd_blk_device *blk_dev = dev_get_drvdata(dev);
>> >> -
>> >>
>> >>       if (is_nd_btt(dev))
>> >>
>> >>               nvdimm_namespace_detach_btt(to_nd_btt(dev));
>> >>
>> >> -     else
>> >> -             nd_blk_detach_disk(blk_dev);
>> >> -     kfree(blk_dev);
>> >> -
>> >>
>> >>       return 0;
>> >>
>> >>  }
>> >
>> > Can't this be void?
>>
>> That's not how the core defines this:
>>
>> struct device_driver {
>> ...
>>         int (*remove) (struct device *dev);
>> ...
>> };
>
> Ah OK, didn't see this, sorry

No worries.  Thanks for the review!

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 08/13] libnvdimm, blk: move i/o infrastructure to nd_namespace_blk
  2016-03-24 15:21     ` Dan Williams
@ 2016-03-24 15:22       ` Johannes Thumshirn
  0 siblings, 0 replies; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-24 15:22 UTC (permalink / raw)
  To: Dan Williams; +Cc: linux-nvdimm@lists.01.org, linux-kernel

On Donnerstag, 24. März 2016 08:21:20 CET Dan Williams wrote:
> On Thu, Mar 24, 2016 at 5:22 AM, Johannes Thumshirn <jthumshirn@suse.de> 
wrote:
> > On Mittwoch, 23. März 2016 18:26:03 CET Dan Williams wrote:
> >> Consolidate the information for issuing i/o to a blk-namespace, and
> >> eliminate some pointer chasing.
> >> 
> >> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> >> ---
> > 
> > [...]
> > 
> >>               BUG_ON(len > PAGE_SIZE);
> >> 
> >> -             err = nd_blk_do_bvec(blk_dev, bip, bvec.bv_page, len,
> >> -                                     bvec.bv_offset, rw,
> >> iter.bi_sector);
> >> +             err = nsblk_do_bvec(nsblk, bip, bvec.bv_page, len,
> >> +                             bvec.bv_offset, rw, iter.bi_sector);
> >> 
> >>               if (err) {
> >> 
> >> -                     dev_info(&blk_dev->nsblk->common.dev,
> >> +                     dev_dbg(&nsblk->common.dev,
> >> 
> >>                                       "io error in %s sector %lld, len
> >>                                       %d,\n",
> >>                                       (rw == READ) ? "READ" : "WRITE",
> >>                                       (unsigned long long)
> >>                                       iter.bi_sector, len);
> > 
> > Why is an I/O error suddently a debug message instead of an error?
> 
> True, that's a jarring change not described in the log, should
> probably be its own patch.  The rationale is that upper layers already
> have error prints for failed commands and this one is redundant.

OK, thanks for the clarification

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 12/13] libnvdimm, pmem, pfn: move pfn setup to the core
  2016-03-24 14:36   ` Johannes Thumshirn
@ 2016-03-24 15:26     ` Dan Williams
  0 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2016-03-24 15:26 UTC (permalink / raw)
  To: Johannes Thumshirn; +Cc: linux-nvdimm@lists.01.org, linux-kernel

On Thu, Mar 24, 2016 at 7:36 AM, Johannes Thumshirn <jthumshirn@suse.de> wrote:
> On Mittwoch, 23. März 2016 18:26:24 CET Dan Williams wrote:
>> Now that pmem internals have been disentangled from pfn setup, that code
>> can move to the core.  This is in preparation for adding another user of
>> the pfn-device capabilities.
>>
>> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
[..]
>> diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
>> index f8fd379501bf..51a214ee75a7 100644
>> --- a/drivers/nvdimm/pfn_devs.c
>> +++ b/drivers/nvdimm/pfn_devs.c
[..]
>> +static int nd_pfn_init(struct nd_pfn *nd_pfn)
>> +{
>> +     struct nd_namespace_common *ndns = nd_pfn->ndns;
>> +     u32 start_pad = 0, end_trunc = 0;
>> +     resource_size_t start, size;
>> +     struct nd_namespace_io *nsio;
>> +     struct nd_region *nd_region;
>> +     struct nd_pfn_sb *pfn_sb;
>> +     unsigned long npfns;
>> +     phys_addr_t offset;
>> +     u64 checksum;
>> +     int rc;
>> +
>> +     pfn_sb = devm_kzalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
>> +     if (!pfn_sb)
>> +             return -ENOMEM;
>> +
>> +     nd_pfn->pfn_sb = pfn_sb;
>> +     rc = nd_pfn_validate(nd_pfn);
>> +     if (rc == -ENODEV)
>> +             /* no info block, do init */;
>> +     else
>> +             return rc;
>
> Why not:
> if (rc != -ENODEV)
>         return  rc;
> /* no info block, do init */

Looks good to me, will fix.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v2] libnvdimm, blk: move i/o infrastructure to nd_namespace_blk
  2016-03-24  1:26 ` [PATCH 08/13] libnvdimm, blk: move i/o infrastructure to nd_namespace_blk Dan Williams
  2016-03-24 12:22   ` Johannes Thumshirn
@ 2016-03-25 22:02   ` Dan Williams
  1 sibling, 0 replies; 38+ messages in thread
From: Dan Williams @ 2016-03-25 22:02 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: linux-kernel, Johannes Thumshirn

Consolidate the information for issuing i/o to a blk-namespace, and
eliminate some pointer chasing.

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Changes in v2:
 * rebased with the "dev_info => dev_dbg" change moved to its own patch.

 drivers/nvdimm/blk.c |  137 +++++++++++++++++++++++++-------------------------
 include/linux/nd.h   |    2 +
 2 files changed, 71 insertions(+), 68 deletions(-)

diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
index 26d039879ba2..4c14ecdc792b 100644
--- a/drivers/nvdimm/blk.c
+++ b/drivers/nvdimm/blk.c
@@ -21,17 +21,19 @@
 #include <linux/sizes.h>
 #include "nd.h"
 
-struct nd_blk_device {
-	struct nd_namespace_blk *nsblk;
-	struct nd_blk_region *ndbr;
-	size_t disk_size;
-	u32 sector_size;
-	u32 internal_lbasize;
-};
+static u32 nsblk_meta_size(struct nd_namespace_blk *nsblk)
+{
+	return nsblk->lbasize - ((nsblk->lbasize >= 4096) ? 4096 : 512);
+}
 
-static u32 nd_blk_meta_size(struct nd_blk_device *blk_dev)
+static u32 nsblk_internal_lbasize(struct nd_namespace_blk *nsblk)
 {
-	return blk_dev->nsblk->lbasize - blk_dev->sector_size;
+	return roundup(nsblk->lbasize, INT_LBASIZE_ALIGNMENT);
+}
+
+static u32 nsblk_sector_size(struct nd_namespace_blk *nsblk)
+{
+	return nsblk->lbasize - nsblk_meta_size(nsblk);
 }
 
 static resource_size_t to_dev_offset(struct nd_namespace_blk *nsblk,
@@ -55,20 +57,29 @@ static resource_size_t to_dev_offset(struct nd_namespace_blk *nsblk,
 	return SIZE_MAX;
 }
 
+static struct nd_blk_region *to_ndbr(struct nd_namespace_blk *nsblk)
+{
+	struct nd_region *nd_region;
+	struct device *parent;
+
+	parent = nsblk->common.dev.parent;
+	nd_region = container_of(parent, struct nd_region, dev);
+	return container_of(nd_region, struct nd_blk_region, nd_region);
+}
+
 #ifdef CONFIG_BLK_DEV_INTEGRITY
-static int nd_blk_rw_integrity(struct nd_blk_device *blk_dev,
-				struct bio_integrity_payload *bip, u64 lba,
-				int rw)
+static int nd_blk_rw_integrity(struct nd_namespace_blk *nsblk,
+		struct bio_integrity_payload *bip, u64 lba, int rw)
 {
-	unsigned int len = nd_blk_meta_size(blk_dev);
+	struct nd_blk_region *ndbr = to_ndbr(nsblk);
+	unsigned int len = nsblk_meta_size(nsblk);
 	resource_size_t	dev_offset, ns_offset;
-	struct nd_namespace_blk *nsblk;
-	struct nd_blk_region *ndbr;
+	u32 internal_lbasize, sector_size;
 	int err = 0;
 
-	nsblk = blk_dev->nsblk;
-	ndbr = blk_dev->ndbr;
-	ns_offset = lba * blk_dev->internal_lbasize + blk_dev->sector_size;
+	internal_lbasize = nsblk_internal_lbasize(nsblk);
+	sector_size = nsblk_sector_size(nsblk);
+	ns_offset = lba * internal_lbasize + sector_size;
 	dev_offset = to_dev_offset(nsblk, ns_offset, len);
 	if (dev_offset == SIZE_MAX)
 		return -EIO;
@@ -102,25 +113,26 @@ static int nd_blk_rw_integrity(struct nd_blk_device *blk_dev,
 }
 
 #else /* CONFIG_BLK_DEV_INTEGRITY */
-static int nd_blk_rw_integrity(struct nd_blk_device *blk_dev,
-				struct bio_integrity_payload *bip, u64 lba,
-				int rw)
+static int nd_blk_rw_integrity(struct nd_namespace_blk *nsblk,
+		struct bio_integrity_payload *bip, u64 lba, int rw)
 {
 	return 0;
 }
 #endif
 
-static int nd_blk_do_bvec(struct nd_blk_device *blk_dev,
-			struct bio_integrity_payload *bip, struct page *page,
-			unsigned int len, unsigned int off, int rw,
-			sector_t sector)
+static int nsblk_do_bvec(struct nd_namespace_blk *nsblk,
+		struct bio_integrity_payload *bip, struct page *page,
+		unsigned int len, unsigned int off, int rw, sector_t sector)
 {
-	struct nd_blk_region *ndbr = blk_dev->ndbr;
+	struct nd_blk_region *ndbr = to_ndbr(nsblk);
 	resource_size_t	dev_offset, ns_offset;
+	u32 internal_lbasize, sector_size;
 	int err = 0;
 	void *iobuf;
 	u64 lba;
 
+	internal_lbasize = nsblk_internal_lbasize(nsblk);
+	sector_size = nsblk_sector_size(nsblk);
 	while (len) {
 		unsigned int cur_len;
 
@@ -130,11 +142,11 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev,
 		 * Block Window setup/move steps. the do_io routine is capable
 		 * of handling len <= PAGE_SIZE.
 		 */
-		cur_len = bip ? min(len, blk_dev->sector_size) : len;
+		cur_len = bip ? min(len, sector_size) : len;
 
-		lba = div_u64(sector << SECTOR_SHIFT, blk_dev->sector_size);
-		ns_offset = lba * blk_dev->internal_lbasize;
-		dev_offset = to_dev_offset(blk_dev->nsblk, ns_offset, cur_len);
+		lba = div_u64(sector << SECTOR_SHIFT, sector_size);
+		ns_offset = lba * internal_lbasize;
+		dev_offset = to_dev_offset(nsblk, ns_offset, cur_len);
 		if (dev_offset == SIZE_MAX)
 			return -EIO;
 
@@ -145,13 +157,13 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev,
 			return err;
 
 		if (bip) {
-			err = nd_blk_rw_integrity(blk_dev, bip, lba, rw);
+			err = nd_blk_rw_integrity(nsblk, bip, lba, rw);
 			if (err)
 				return err;
 		}
 		len -= cur_len;
 		off += cur_len;
-		sector += blk_dev->sector_size >> SECTOR_SHIFT;
+		sector += sector_size >> SECTOR_SHIFT;
 	}
 
 	return err;
@@ -160,7 +172,7 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev,
 static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio)
 {
 	struct bio_integrity_payload *bip;
-	struct nd_blk_device *blk_dev;
+	struct nd_namespace_blk *nsblk;
 	struct bvec_iter iter;
 	unsigned long start;
 	struct bio_vec bvec;
@@ -179,17 +191,17 @@ static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio)
 	}
 
 	bip = bio_integrity(bio);
-	blk_dev = q->queuedata;
+	nsblk = q->queuedata;
 	rw = bio_data_dir(bio);
 	do_acct = nd_iostat_start(bio, &start);
 	bio_for_each_segment(bvec, bio, iter) {
 		unsigned int len = bvec.bv_len;
 
 		BUG_ON(len > PAGE_SIZE);
-		err = nd_blk_do_bvec(blk_dev, bip, bvec.bv_page, len,
-					bvec.bv_offset, rw, iter.bi_sector);
+		err = nsblk_do_bvec(nsblk, bip, bvec.bv_page, len,
+				bvec.bv_offset, rw, iter.bi_sector);
 		if (err) {
-			dev_dbg(&blk_dev->nsblk->common.dev,
+			dev_dbg(&nsblk->common.dev,
 					"io error in %s sector %lld, len %d,\n",
 					(rw == READ) ? "READ" : "WRITE",
 					(unsigned long long) iter.bi_sector, len);
@@ -205,17 +217,16 @@ static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio)
 	return BLK_QC_T_NONE;
 }
 
-static int nd_blk_rw_bytes(struct nd_namespace_common *ndns,
+static int nsblk_rw_bytes(struct nd_namespace_common *ndns,
 		resource_size_t offset, void *iobuf, size_t n, int rw)
 {
-	struct nd_blk_device *blk_dev = dev_get_drvdata(ndns->claim);
-	struct nd_namespace_blk *nsblk = blk_dev->nsblk;
-	struct nd_blk_region *ndbr = blk_dev->ndbr;
+	struct nd_namespace_blk *nsblk = to_nd_namespace_blk(&ndns->dev);
+	struct nd_blk_region *ndbr = to_ndbr(nsblk);
 	resource_size_t	dev_offset;
 
 	dev_offset = to_dev_offset(nsblk, offset, n);
 
-	if (unlikely(offset + n > blk_dev->disk_size)) {
+	if (unlikely(offset + n > nsblk->size)) {
 		dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n");
 		return -EFAULT;
 	}
@@ -242,16 +253,16 @@ static void nd_blk_release_disk(void *disk)
 	put_disk(disk);
 }
 
-static int nd_blk_attach_disk(struct device *dev,
-		struct nd_namespace_common *ndns, struct nd_blk_device *blk_dev)
+static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
 {
+	struct device *dev = &nsblk->common.dev;
 	resource_size_t available_disk_size;
 	struct request_queue *q;
 	struct gendisk *disk;
 	u64 internal_nlba;
 
-	internal_nlba = div_u64(blk_dev->disk_size, blk_dev->internal_lbasize);
-	available_disk_size = internal_nlba * blk_dev->sector_size;
+	internal_nlba = div_u64(nsblk->size, nsblk_internal_lbasize(nsblk));
+	available_disk_size = internal_nlba * nsblk_sector_size(nsblk);
 
 	q = blk_alloc_queue(GFP_KERNEL);
 	if (!q)
@@ -264,9 +275,9 @@ static int nd_blk_attach_disk(struct device *dev,
 	blk_queue_make_request(q, nd_blk_make_request);
 	blk_queue_max_hw_sectors(q, UINT_MAX);
 	blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
-	blk_queue_logical_block_size(q, blk_dev->sector_size);
+	blk_queue_logical_block_size(q, nsblk_sector_size(nsblk));
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
-	q->queuedata = blk_dev;
+	q->queuedata = nsblk;
 
 	disk = alloc_disk(0);
 	if (!disk)
@@ -276,17 +287,17 @@ static int nd_blk_attach_disk(struct device *dev,
 		return -ENOMEM;
 	}
 
-	disk->driverfs_dev	= &ndns->dev;
+	disk->driverfs_dev	= dev;
 	disk->first_minor	= 0;
 	disk->fops		= &nd_blk_fops;
 	disk->queue		= q;
 	disk->flags		= GENHD_FL_EXT_DEVT;
-	nvdimm_namespace_disk_name(ndns, disk->disk_name);
+	nvdimm_namespace_disk_name(&nsblk->common, disk->disk_name);
 	set_capacity(disk, 0);
 	add_disk(disk);
 
-	if (nd_blk_meta_size(blk_dev)) {
-		int rc = nd_integrity_init(disk, nd_blk_meta_size(blk_dev));
+	if (nsblk_meta_size(nsblk)) {
+		int rc = nd_integrity_init(disk, nsblk_meta_size(nsblk));
 
 		if (rc)
 			return rc;
@@ -301,33 +312,23 @@ static int nd_blk_probe(struct device *dev)
 {
 	struct nd_namespace_common *ndns;
 	struct nd_namespace_blk *nsblk;
-	struct nd_blk_device *blk_dev;
 
 	ndns = nvdimm_namespace_common_probe(dev);
 	if (IS_ERR(ndns))
 		return PTR_ERR(ndns);
 
-	blk_dev = devm_kzalloc(dev, sizeof(*blk_dev), GFP_KERNEL);
-	if (!blk_dev)
-		return -ENOMEM;
-
 	nsblk = to_nd_namespace_blk(&ndns->dev);
-	blk_dev->disk_size = nvdimm_namespace_capacity(ndns);
-	blk_dev->ndbr = to_nd_blk_region(dev->parent);
-	blk_dev->nsblk = to_nd_namespace_blk(&ndns->dev);
-	blk_dev->internal_lbasize = roundup(nsblk->lbasize,
-						INT_LBASIZE_ALIGNMENT);
-	blk_dev->sector_size = ((nsblk->lbasize >= 4096) ? 4096 : 512);
-	dev_set_drvdata(dev, blk_dev);
-
-	ndns->rw_bytes = nd_blk_rw_bytes;
+	nsblk->size = nvdimm_namespace_capacity(ndns);
+	dev_set_drvdata(dev, nsblk);
+
+	ndns->rw_bytes = nsblk_rw_bytes;
 	if (is_nd_btt(dev))
 		return nvdimm_namespace_attach_btt(ndns);
-	else if (nd_btt_probe(dev, ndns, blk_dev) == 0) {
+	else if (nd_btt_probe(dev, ndns, nsblk) == 0) {
 		/* we'll come back as btt-blk */
 		return -ENXIO;
 	} else
-		return nd_blk_attach_disk(dev, ndns, blk_dev);
+		return nsblk_attach_disk(nsblk);
 }
 
 static int nd_blk_remove(struct device *dev)
diff --git a/include/linux/nd.h b/include/linux/nd.h
index 5489ab756d1a..5ea4aec7fd63 100644
--- a/include/linux/nd.h
+++ b/include/linux/nd.h
@@ -82,6 +82,7 @@ struct nd_namespace_pmem {
  * @uuid: namespace name supplied in the dimm label
  * @id: ida allocated id
  * @lbasize: blk namespaces have a native sector size when btt not present
+ * @size: sum of all the resource ranges allocated to this namespace
  * @num_resources: number of dpa extents to claim
  * @res: discontiguous dpa extents for given dimm
  */
@@ -91,6 +92,7 @@ struct nd_namespace_blk {
 	u8 *uuid;
 	int id;
 	unsigned long lbasize;
+	resource_size_t size;
 	int num_resources;
 	struct resource **res;
 };

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v2] libnvdimm, pmem, pfn: make pmem_rw_bytes generic and refactor pfn setup
  2016-03-24  1:26 ` [PATCH 11/13] libnvdimm, pmem, pfn: make pmem_rw_bytes generic and refactor pfn setup Dan Williams
  2016-03-24 13:50   ` Johannes Thumshirn
@ 2016-03-25 22:13   ` Dan Williams
  1 sibling, 0 replies; 38+ messages in thread
From: Dan Williams @ 2016-03-25 22:13 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: linux-kernel, Johannes Thumshirn

In preparation for providing an alternative (to block device) access
mechanism to persistent memory, convert pmem_rw_bytes() to
nsio_rw_bytes().  This allows ->rw_bytes() functionality without
requiring a 'struct pmem_device' to be instantiated.

In other words, when ->rw_bytes() is in use i/o is driven through
'struct nd_namespace_io', otherwise it is driven through 'struct
pmem_device' and the block layer.  This consolidates the disjoint calls
to devm_exit_badblocks() and devm_memunmap() into a common
devm_nsio_disable() and cleans up the init path to use a unified
pmem_attach_disk() implementation.

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Changes in v2:
* Fixed the offset calculation for badblocks initialization, we need to
  add the pmem->data_offset which is not included in the resource range
  used for setting up devm_memremap_pages().

 drivers/nvdimm/blk.c              |    2 
 drivers/nvdimm/btt_devs.c         |    4 -
 drivers/nvdimm/claim.c            |   61 +++++++++
 drivers/nvdimm/nd.h               |   40 +++++-
 drivers/nvdimm/pfn_devs.c         |    4 -
 drivers/nvdimm/pmem.c             |  238 +++++++++++++------------------------
 include/linux/nd.h                |    9 +
 tools/testing/nvdimm/Kbuild       |    1 
 tools/testing/nvdimm/test/iomap.c |   27 +++-
 9 files changed, 212 insertions(+), 174 deletions(-)

diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
index 4c14ecdc792b..495e06d9f7e7 100644
--- a/drivers/nvdimm/blk.c
+++ b/drivers/nvdimm/blk.c
@@ -324,7 +324,7 @@ static int nd_blk_probe(struct device *dev)
 	ndns->rw_bytes = nsblk_rw_bytes;
 	if (is_nd_btt(dev))
 		return nvdimm_namespace_attach_btt(ndns);
-	else if (nd_btt_probe(dev, ndns, nsblk) == 0) {
+	else if (nd_btt_probe(dev, ndns) == 0) {
 		/* we'll come back as btt-blk */
 		return -ENXIO;
 	} else
diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c
index 1886171af80e..816d0dae6398 100644
--- a/drivers/nvdimm/btt_devs.c
+++ b/drivers/nvdimm/btt_devs.c
@@ -273,8 +273,7 @@ static int __nd_btt_probe(struct nd_btt *nd_btt,
 	return 0;
 }
 
-int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns,
-		void *drvdata)
+int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns)
 {
 	int rc;
 	struct device *btt_dev;
@@ -289,7 +288,6 @@ int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns,
 	nvdimm_bus_unlock(&ndns->dev);
 	if (!btt_dev)
 		return -ENOMEM;
-	dev_set_drvdata(btt_dev, drvdata);
 	btt_sb = devm_kzalloc(dev, sizeof(*btt_sb), GFP_KERNEL);
 	rc = __nd_btt_probe(to_nd_btt(btt_dev), ndns, btt_sb);
 	dev_dbg(dev, "%s: btt: %s\n", __func__,
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c
index e8f03b0e95e4..85159050a7a7 100644
--- a/drivers/nvdimm/claim.c
+++ b/drivers/nvdimm/claim.c
@@ -12,6 +12,7 @@
  */
 #include <linux/device.h>
 #include <linux/sizes.h>
+#include <linux/pmem.h>
 #include "nd-core.h"
 #include "pfn.h"
 #include "btt.h"
@@ -199,3 +200,63 @@ u64 nd_sb_checksum(struct nd_gen_sb *nd_gen_sb)
 	return sum;
 }
 EXPORT_SYMBOL(nd_sb_checksum);
+
+static int nsio_rw_bytes(struct nd_namespace_common *ndns,
+		resource_size_t offset, void *buf, size_t size, int rw)
+{
+	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+
+	if (unlikely(offset + size > nsio->size)) {
+		dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n");
+		return -EFAULT;
+	}
+
+	if (rw == READ) {
+		unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
+
+		if (unlikely(is_bad_pmem(&nsio->bb, offset / 512, sz_align)))
+			return -EIO;
+		memcpy_from_pmem(buf, nsio->addr + offset, size);
+	} else {
+		memcpy_to_pmem(nsio->addr + offset, buf, size);
+		wmb_pmem();
+	}
+
+	return 0;
+}
+
+int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)
+{
+	struct resource *res = &nsio->res;
+	struct nd_namespace_common *ndns = &nsio->common;
+
+	nsio->size = resource_size(res);
+	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;
+	}
+
+	ndns->rw_bytes = nsio_rw_bytes;
+	if (devm_init_badblocks(dev, &nsio->bb))
+		return -ENOMEM;
+	nvdimm_badblocks_populate(to_nd_region(ndns->dev.parent), &nsio->bb,
+			&nsio->res);
+
+	nsio->addr = devm_memremap(dev, res->start, resource_size(res),
+			ARCH_MEMREMAP_PMEM);
+	if (IS_ERR(nsio->addr))
+		return PTR_ERR(nsio->addr);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(devm_nsio_enable);
+
+void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio)
+{
+	struct resource *res = &nsio->res;
+
+	devm_memunmap(dev, nsio->addr);
+	devm_exit_badblocks(dev, &nsio->bb);
+	devm_release_mem_region(dev, res->start, resource_size(res));
+}
+EXPORT_SYMBOL_GPL(devm_nsio_disable);
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 0fb14890ba26..10e23fe49012 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -13,6 +13,7 @@
 #ifndef __ND_H__
 #define __ND_H__
 #include <linux/libnvdimm.h>
+#include <linux/badblocks.h>
 #include <linux/blkdev.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
@@ -197,13 +198,12 @@ struct nd_gen_sb {
 
 u64 nd_sb_checksum(struct nd_gen_sb *sb);
 #if IS_ENABLED(CONFIG_BTT)
-int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns,
-		void *drvdata);
+int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns);
 bool is_nd_btt(struct device *dev);
 struct device *nd_btt_create(struct nd_region *nd_region);
 #else
 static inline int nd_btt_probe(struct device *dev,
-		struct nd_namespace_common *ndns, void *drvdata)
+		struct nd_namespace_common *ndns)
 {
 	return -ENODEV;
 }
@@ -221,14 +221,13 @@ static inline struct device *nd_btt_create(struct nd_region *nd_region)
 
 struct nd_pfn *to_nd_pfn(struct device *dev);
 #if IS_ENABLED(CONFIG_NVDIMM_PFN)
-int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
-		void *drvdata);
+int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns);
 bool is_nd_pfn(struct device *dev);
 struct device *nd_pfn_create(struct nd_region *nd_region);
 int nd_pfn_validate(struct nd_pfn *nd_pfn);
 #else
-static inline int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
-		void *drvdata)
+static inline int nd_pfn_probe(struct device *dev,
+		struct nd_namespace_common *ndns)
 {
 	return -ENODEV;
 }
@@ -272,6 +271,20 @@ const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns,
 		char *name);
 void nvdimm_badblocks_populate(struct nd_region *nd_region,
 		struct badblocks *bb, const struct resource *res);
+#if IS_ENABLED(CONFIG_ND_CLAIM)
+int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio);
+void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio);
+#else
+static inline int devm_nsio_enable(struct device *dev,
+		struct nd_namespace_io *nsio)
+{
+	return -ENXIO;
+}
+static inline void devm_nsio_disable(struct device *dev,
+		struct nd_namespace_io *nsio)
+{
+}
+#endif
 int nd_blk_region_init(struct nd_region *nd_region);
 void __nd_iostat_start(struct bio *bio, unsigned long *start);
 static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
@@ -285,6 +298,19 @@ static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
 	return true;
 }
 void nd_iostat_end(struct bio *bio, unsigned long start);
+static inline bool is_bad_pmem(struct badblocks *bb, sector_t sector,
+		unsigned int len)
+{
+	if (bb->count) {
+		sector_t first_bad;
+		int num_bad;
+
+		return !!badblocks_check(bb, sector, len / 512, &first_bad,
+				&num_bad);
+	}
+
+	return false;
+}
 resource_size_t nd_namespace_blk_validate(struct nd_namespace_blk *nsblk);
 const u8 *nd_dev_to_uuid(struct device *dev);
 bool pmem_should_map_pages(struct device *dev);
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 63e2df3e052c..f8fd379501bf 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -410,8 +410,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn)
 }
 EXPORT_SYMBOL(nd_pfn_validate);
 
-int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
-		void *drvdata)
+int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns)
 {
 	int rc;
 	struct nd_pfn *nd_pfn;
@@ -427,7 +426,6 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
 	nvdimm_bus_unlock(&ndns->dev);
 	if (!pfn_dev)
 		return -ENOMEM;
-	dev_set_drvdata(pfn_dev, drvdata);
 	pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
 	nd_pfn = to_nd_pfn(pfn_dev);
 	nd_pfn->pfn_sb = pfn_sb;
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index c9ae1673bb17..904f904e2962 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -49,19 +49,6 @@ struct pmem_device {
 	struct badblocks	bb;
 };
 
-static bool is_bad_pmem(struct badblocks *bb, sector_t sector, unsigned int len)
-{
-	if (bb->count) {
-		sector_t first_bad;
-		int num_bad;
-
-		return !!badblocks_check(bb, sector, len / 512, &first_bad,
-				&num_bad);
-	}
-
-	return false;
-}
-
 static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
 		unsigned int len)
 {
@@ -195,16 +182,40 @@ void pmem_release_disk(void *disk)
 	put_disk(disk);
 }
 
-static struct pmem_device *pmem_alloc(struct device *dev,
-		struct resource *res, int id)
+static struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap);
+
+static int pmem_attach_disk(struct device *dev,
+		struct nd_namespace_common *ndns)
 {
+	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+	struct vmem_altmap __altmap, *altmap = NULL;
+	struct resource *res = &nsio->res;
+	struct nd_pfn *nd_pfn = NULL;
+	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 gendisk *disk;
+	void *addr;
+
+	/* while nsio_rw_bytes is active, parse a pfn info block if present */
+	if (is_nd_pfn(dev)) {
+		nd_pfn = to_nd_pfn(dev);
+		altmap = nvdimm_setup_pfn(nd_pfn, &pfn_res, &__altmap);
+		if (IS_ERR(altmap))
+			return PTR_ERR(altmap);
+	}
+
+	/* we're attaching a block device, disable raw namespace access */
+	devm_nsio_disable(dev, nsio);
 
 	pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL);
 	if (!pmem)
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 
+	dev_set_drvdata(dev, pmem);
 	pmem->phys_addr = res->start;
 	pmem->size = resource_size(res);
 	if (!arch_has_wmb_pmem())
@@ -213,22 +224,31 @@ static struct pmem_device *pmem_alloc(struct device *dev,
 	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 ERR_PTR(-EBUSY);
+		return -EBUSY;
 	}
 
 	q = blk_alloc_queue_node(GFP_KERNEL, dev_to_node(dev));
 	if (!q)
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
+	pmem->pmem_queue = q;
 
 	pmem->pfn_flags = PFN_DEV;
-	if (pmem_should_map_pages(dev)) {
-		pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, res,
+	if (is_nd_pfn(dev)) {
+		addr = devm_memremap_pages(dev, &pfn_res, &q->q_usage_counter,
+				altmap);
+		pfn_sb = nd_pfn->pfn_sb;
+		pmem->data_offset = le64_to_cpu(pfn_sb->dataoff);
+		pmem->pfn_pad = resource_size(res) - resource_size(&pfn_res);
+		pmem->pfn_flags |= PFN_MAP;
+		res = &pfn_res; /* for badblocks populate */
+		res->start += pmem->data_offset;
+	} else if (pmem_should_map_pages(dev)) {
+		addr = devm_memremap_pages(dev, &nsio->res,
 				&q->q_usage_counter, NULL);
 		pmem->pfn_flags |= PFN_MAP;
 	} else
-		pmem->virt_addr = (void __pmem *) devm_memremap(dev,
-				pmem->phys_addr, pmem->size,
-				ARCH_MEMREMAP_PMEM);
+		addr = devm_memremap(dev, pmem->phys_addr,
+				pmem->size, ARCH_MEMREMAP_PMEM);
 
 	/*
 	 * At release time the queue must be dead before
@@ -236,23 +256,12 @@ static struct pmem_device *pmem_alloc(struct device *dev,
 	 */
 	if (devm_add_action(dev, pmem_release_queue, q)) {
 		blk_cleanup_queue(q);
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 	}
 
-	if (IS_ERR(pmem->virt_addr))
-		return (void __force *) pmem->virt_addr;
-
-	pmem->pmem_queue = q;
-	return pmem;
-}
-
-static int pmem_attach_disk(struct device *dev,
-		struct nd_namespace_common *ndns, struct pmem_device *pmem)
-{
-	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
-	int nid = dev_to_node(dev);
-	struct resource bb_res;
-	struct gendisk *disk;
+	if (IS_ERR(addr))
+		return PTR_ERR(addr);
+	pmem->virt_addr = (void __pmem *) addr;
 
 	blk_queue_make_request(pmem->pmem_queue, pmem_make_request);
 	blk_queue_physical_block_size(pmem->pmem_queue, PAGE_SIZE);
@@ -277,20 +286,9 @@ static int pmem_attach_disk(struct device *dev,
 	set_capacity(disk, (pmem->size - pmem->pfn_pad - pmem->data_offset)
 			/ 512);
 	pmem->pmem_disk = disk;
-	devm_exit_badblocks(dev, &pmem->bb);
 	if (devm_init_badblocks(dev, &pmem->bb))
 		return -ENOMEM;
-	bb_res.start = nsio->res.start + pmem->data_offset;
-	bb_res.end = nsio->res.end;
-	if (is_nd_pfn(dev)) {
-		struct nd_pfn *nd_pfn = to_nd_pfn(dev);
-		struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
-
-		bb_res.start += __le32_to_cpu(pfn_sb->start_pad);
-		bb_res.end -= __le32_to_cpu(pfn_sb->end_trunc);
-	}
-	nvdimm_badblocks_populate(to_nd_region(dev->parent), &pmem->bb,
-			&bb_res);
+	nvdimm_badblocks_populate(to_nd_region(dev->parent), &pmem->bb, res);
 	disk->bb = &pmem->bb;
 	add_disk(disk);
 	revalidate_disk(disk);
@@ -298,33 +296,8 @@ static int pmem_attach_disk(struct device *dev,
 	return 0;
 }
 
-static int pmem_rw_bytes(struct nd_namespace_common *ndns,
-		resource_size_t offset, void *buf, size_t size, int rw)
-{
-	struct pmem_device *pmem = dev_get_drvdata(ndns->claim);
-
-	if (unlikely(offset + size > pmem->size)) {
-		dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n");
-		return -EFAULT;
-	}
-
-	if (rw == READ) {
-		unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
-
-		if (unlikely(is_bad_pmem(&pmem->bb, offset / 512, sz_align)))
-			return -EIO;
-		memcpy_from_pmem(buf, pmem->virt_addr + offset, size);
-	} else {
-		memcpy_to_pmem(pmem->virt_addr + offset, buf, size);
-		wmb_pmem();
-	}
-
-	return 0;
-}
-
 static int nd_pfn_init(struct nd_pfn *nd_pfn)
 {
-	struct pmem_device *pmem = dev_get_drvdata(&nd_pfn->dev);
 	struct nd_namespace_common *ndns = nd_pfn->ndns;
 	u32 start_pad = 0, end_trunc = 0;
 	resource_size_t start, size;
@@ -390,7 +363,8 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
 	 * ->direct_access() to those that are included in the memmap.
 	 */
 	start += start_pad;
-	npfns = (pmem->size - start_pad - end_trunc - SZ_8K) / SZ_4K;
+	size = resource_size(&nsio->res);
+	npfns = (size - start_pad - end_trunc - SZ_8K) / SZ_4K;
 	if (nd_pfn->mode == PFN_MODE_PMEM)
 		offset = ALIGN(start + SZ_8K + 64 * npfns, nd_pfn->align)
 			- start;
@@ -399,13 +373,13 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
 	else
 		return -ENXIO;
 
-	if (offset + start_pad + end_trunc >= pmem->size) {
+	if (offset + start_pad + end_trunc >= size) {
 		dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
 				dev_name(&ndns->dev));
 		return -ENXIO;
 	}
 
-	npfns = (pmem->size - offset - start_pad - end_trunc) / SZ_4K;
+	npfns = (size - offset - start_pad - end_trunc) / SZ_4K;
 	pfn_sb->mode = cpu_to_le32(nd_pfn->mode);
 	pfn_sb->dataoff = cpu_to_le64(offset);
 	pfn_sb->npfns = cpu_to_le64(npfns);
@@ -442,17 +416,14 @@ static unsigned long init_altmap_reserve(resource_size_t base)
 	return reserve;
 }
 
-static int __nvdimm_namespace_attach_pfn(struct nd_pfn *nd_pfn)
+static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap)
 {
-	struct resource res;
-	struct request_queue *q;
-	struct pmem_device *pmem;
-	struct vmem_altmap *altmap;
-	struct device *dev = &nd_pfn->dev;
 	struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
-	struct nd_namespace_common *ndns = nd_pfn->ndns;
+	u64 offset = le64_to_cpu(pfn_sb->dataoff);
 	u32 start_pad = __le32_to_cpu(pfn_sb->start_pad);
 	u32 end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
+	struct nd_namespace_common *ndns = nd_pfn->ndns;
 	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
 	resource_size_t base = nsio->res.start + start_pad;
 	struct vmem_altmap __altmap = {
@@ -460,112 +431,75 @@ static int __nvdimm_namespace_attach_pfn(struct nd_pfn *nd_pfn)
 		.reserve = init_altmap_reserve(base),
 	};
 
-	pmem = dev_get_drvdata(dev);
-	pmem->data_offset = le64_to_cpu(pfn_sb->dataoff);
-	pmem->pfn_pad = start_pad + end_trunc;
+	memcpy(res, &nsio->res, sizeof(*res));
+	res->start += start_pad;
+	res->end -= end_trunc;
+
 	nd_pfn->mode = le32_to_cpu(nd_pfn->pfn_sb->mode);
 	if (nd_pfn->mode == PFN_MODE_RAM) {
-		if (pmem->data_offset < SZ_8K)
-			return -EINVAL;
+		if (offset < SZ_8K)
+			return ERR_PTR(-EINVAL);
 		nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
 		altmap = NULL;
 	} else if (nd_pfn->mode == PFN_MODE_PMEM) {
-		nd_pfn->npfns = (pmem->size - pmem->pfn_pad - pmem->data_offset)
-			/ PAGE_SIZE;
+		nd_pfn->npfns = (resource_size(res) - offset) / PAGE_SIZE;
 		if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
 			dev_info(&nd_pfn->dev,
 					"number of pfns truncated from %lld to %ld\n",
 					le64_to_cpu(nd_pfn->pfn_sb->npfns),
 					nd_pfn->npfns);
-		altmap = & __altmap;
-		altmap->free = PHYS_PFN(pmem->data_offset - SZ_8K);
+		memcpy(altmap, &__altmap, sizeof(*altmap));
+		altmap->free = PHYS_PFN(offset - SZ_8K);
 		altmap->alloc = 0;
 	} else
-		return -ENXIO;
-
-	/* establish pfn range for lookup, and switch to direct map */
-	q = pmem->pmem_queue;
-	memcpy(&res, &nsio->res, sizeof(res));
-	res.start += start_pad;
-	res.end -= end_trunc;
-	devm_remove_action(dev, pmem_release_queue, q);
-	devm_memunmap(dev, (void __force *) pmem->virt_addr);
-	pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &res,
-			&q->q_usage_counter, altmap);
-	pmem->pfn_flags |= PFN_MAP;
+		return ERR_PTR(-ENXIO);
 
-	/*
-	 * At release time the queue must be dead before
-	 * devm_memremap_pages is unwound
-	 */
-	if (devm_add_action(dev, pmem_release_queue, q)) {
-		blk_cleanup_queue(q);
-		return -ENOMEM;
-	}
-	if (IS_ERR(pmem->virt_addr))
-		return PTR_ERR(pmem->virt_addr);
-
-	/* attach pmem disk in "pfn-mode" */
-	return pmem_attach_disk(dev, ndns, pmem);
+	return altmap;
 }
 
-static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
+/*
+ * Determine the effective resource range and vmem_altmap from an nd_pfn
+ * instance.
+ */
+static struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap)
 {
-	struct nd_pfn *nd_pfn = to_nd_pfn(ndns->claim);
 	int rc;
 
 	if (!nd_pfn->uuid || !nd_pfn->ndns)
-		return -ENODEV;
+		return ERR_PTR(-ENODEV);
 
 	rc = nd_pfn_init(nd_pfn);
 	if (rc)
-		return rc;
+		return ERR_PTR(rc);
+
 	/* we need a valid pfn_sb before we can init a vmem_altmap */
-	return __nvdimm_namespace_attach_pfn(nd_pfn);
+	return __nvdimm_setup_pfn(nd_pfn, res, altmap);
 }
 
 static int nd_pmem_probe(struct device *dev)
 {
-	struct nd_region *nd_region = to_nd_region(dev->parent);
 	struct nd_namespace_common *ndns;
-	struct nd_namespace_io *nsio;
-	struct pmem_device *pmem;
 
 	ndns = nvdimm_namespace_common_probe(dev);
 	if (IS_ERR(ndns))
 		return PTR_ERR(ndns);
 
-	nsio = to_nd_namespace_io(&ndns->dev);
-	pmem = pmem_alloc(dev, &nsio->res, nd_region->id);
-	if (IS_ERR(pmem))
-		return PTR_ERR(pmem);
-
-	dev_set_drvdata(dev, pmem);
-	ndns->rw_bytes = pmem_rw_bytes;
-	if (devm_init_badblocks(dev, &pmem->bb))
-		return -ENOMEM;
-	nvdimm_badblocks_populate(nd_region, &pmem->bb, &nsio->res);
+	if (devm_nsio_enable(dev, to_nd_namespace_io(&ndns->dev)))
+		return -ENXIO;
 
-	if (is_nd_btt(dev)) {
-		/* btt allocates its own request_queue */
-		devm_remove_action(dev, pmem_release_queue, pmem->pmem_queue);
-		blk_cleanup_queue(pmem->pmem_queue);
+	if (is_nd_btt(dev))
 		return nvdimm_namespace_attach_btt(ndns);
-	}
 
 	if (is_nd_pfn(dev))
-		return nvdimm_namespace_attach_pfn(ndns);
-
-	if (nd_btt_probe(dev, ndns, pmem) == 0
-			|| nd_pfn_probe(dev, ndns, pmem) == 0) {
-		/*
-		 * We'll come back as either btt-pmem, or pfn-pmem, so
-		 * drop the queue allocation for now.
-		 */
+		return pmem_attach_disk(dev, ndns);
+
+	/* if we find a valid info-block we'll come back as that personality */
+	if (nd_btt_probe(dev, ndns) == 0 || nd_pfn_probe(dev, ndns) == 0)
 		return -ENXIO;
-	}
 
-	return pmem_attach_disk(dev, ndns, pmem);
+	/* ...otherwise we're just a raw pmem device */
+	return pmem_attach_disk(dev, ndns);
 }
 
 static int nd_pmem_remove(struct device *dev)
diff --git a/include/linux/nd.h b/include/linux/nd.h
index 5ea4aec7fd63..aee2761d294c 100644
--- a/include/linux/nd.h
+++ b/include/linux/nd.h
@@ -15,6 +15,7 @@
 #include <linux/fs.h>
 #include <linux/ndctl.h>
 #include <linux/device.h>
+#include <linux/badblocks.h>
 
 enum nvdimm_event {
 	NVDIMM_REVALIDATE_POISON,
@@ -55,13 +56,19 @@ static inline struct nd_namespace_common *to_ndns(struct device *dev)
 }
 
 /**
- * struct nd_namespace_io - infrastructure for loading an nd_pmem instance
+ * struct nd_namespace_io - device representation of a persistent memory range
  * @dev: namespace device created by the nd region driver
  * @res: struct resource conversion of a NFIT SPA table
+ * @size: cached resource_size(@res) for fast path size checks
+ * @addr: virtual address to access the namespace range
+ * @bb: badblocks list for the namespace range
  */
 struct nd_namespace_io {
 	struct nd_namespace_common common;
 	struct resource res;
+	resource_size_t size;
+	void __pmem *addr;
+	struct badblocks bb;
 };
 
 /**
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild
index a34bfd0c8928..d5bc8c080b44 100644
--- a/tools/testing/nvdimm/Kbuild
+++ b/tools/testing/nvdimm/Kbuild
@@ -7,6 +7,7 @@ ldflags-y += --wrap=ioremap_nocache
 ldflags-y += --wrap=iounmap
 ldflags-y += --wrap=memunmap
 ldflags-y += --wrap=__devm_request_region
+ldflags-y += --wrap=__devm_release_region
 ldflags-y += --wrap=__request_region
 ldflags-y += --wrap=__release_region
 ldflags-y += --wrap=devm_memremap_pages
diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c
index 0c1a7e65bb81..c842095f2801 100644
--- a/tools/testing/nvdimm/test/iomap.c
+++ b/tools/testing/nvdimm/test/iomap.c
@@ -239,13 +239,11 @@ struct resource *__wrap___devm_request_region(struct device *dev,
 }
 EXPORT_SYMBOL(__wrap___devm_request_region);
 
-void __wrap___release_region(struct resource *parent, resource_size_t start,
-				resource_size_t n)
+static bool nfit_test_release_region(struct resource *parent,
+		resource_size_t start, resource_size_t n)
 {
-	struct nfit_test_resource *nfit_res;
-
 	if (parent == &iomem_resource) {
-		nfit_res = get_nfit_res(start);
+		struct nfit_test_resource *nfit_res = get_nfit_res(start);
 		if (nfit_res) {
 			struct resource *res = nfit_res->res + 1;
 
@@ -254,11 +252,26 @@ void __wrap___release_region(struct resource *parent, resource_size_t start,
 						__func__, start, n, res);
 			else
 				memset(res, 0, sizeof(*res));
-			return;
+			return true;
 		}
 	}
-	__release_region(parent, start, n);
+	return false;
+}
+
+void __wrap___release_region(struct resource *parent, resource_size_t start,
+		resource_size_t n)
+{
+	if (!nfit_test_release_region(parent, start, n))
+		__release_region(parent, start, n);
 }
 EXPORT_SYMBOL(__wrap___release_region);
 
+void __wrap___devm_release_region(struct device *dev, struct resource *parent,
+		resource_size_t start, resource_size_t n)
+{
+	if (!nfit_test_release_region(parent, start, n))
+		__devm_release_region(dev, parent, start, n);
+}
+EXPORT_SYMBOL(__wrap___devm_release_region);
+
 MODULE_LICENSE("GPL v2");

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v2] libnvdimm, pmem, pfn: move pfn setup to the core
  2016-03-24  1:26 ` [PATCH 12/13] libnvdimm, pmem, pfn: move pfn setup to the core Dan Williams
  2016-03-24 14:36   ` Johannes Thumshirn
@ 2016-03-25 22:15   ` Dan Williams
  2016-03-29  8:30     ` Johannes Thumshirn
  1 sibling, 1 reply; 38+ messages in thread
From: Dan Williams @ 2016-03-25 22:15 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: linux-kernel

Now that pmem internals have been disentangled from pfn setup, that code
can move to the core.  This is in preparation for adding another user of
the pfn-device capabilities.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Changes in v2:
* Cleaned up the -ENODEV checking in nd_pfn_init() (Johannes)

 drivers/nvdimm/nd.h       |    7 ++
 drivers/nvdimm/pfn_devs.c |  181 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/nvdimm/pmem.c     |  184 ---------------------------------------------
 3 files changed, 188 insertions(+), 184 deletions(-)

diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 10e23fe49012..6c36509662e4 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -272,9 +272,16 @@ const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns,
 void nvdimm_badblocks_populate(struct nd_region *nd_region,
 		struct badblocks *bb, const struct resource *res);
 #if IS_ENABLED(CONFIG_ND_CLAIM)
+struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap);
 int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio);
 void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio);
 #else
+static inline struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap)
+{
+	return ERR_PTR(-ENXIO);
+}
 static inline int devm_nsio_enable(struct device *dev,
 		struct nd_namespace_io *nsio)
 {
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index f8fd379501bf..92468d30099e 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -10,6 +10,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  */
+#include <linux/memremap.h>
 #include <linux/blkdev.h>
 #include <linux/device.h>
 #include <linux/genhd.h>
@@ -441,3 +442,183 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns)
 	return rc;
 }
 EXPORT_SYMBOL(nd_pfn_probe);
+
+/*
+ * We hotplug memory at section granularity, pad the reserved area from
+ * the previous section base to the namespace base address.
+ */
+static unsigned long init_altmap_base(resource_size_t base)
+{
+	unsigned long base_pfn = PHYS_PFN(base);
+
+	return PFN_SECTION_ALIGN_DOWN(base_pfn);
+}
+
+static unsigned long init_altmap_reserve(resource_size_t base)
+{
+	unsigned long reserve = PHYS_PFN(SZ_8K);
+	unsigned long base_pfn = PHYS_PFN(base);
+
+	reserve += base_pfn - PFN_SECTION_ALIGN_DOWN(base_pfn);
+	return reserve;
+}
+
+static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap)
+{
+	struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
+	u64 offset = le64_to_cpu(pfn_sb->dataoff);
+	u32 start_pad = __le32_to_cpu(pfn_sb->start_pad);
+	u32 end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
+	struct nd_namespace_common *ndns = nd_pfn->ndns;
+	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+	resource_size_t base = nsio->res.start + start_pad;
+	struct vmem_altmap __altmap = {
+		.base_pfn = init_altmap_base(base),
+		.reserve = init_altmap_reserve(base),
+	};
+
+	memcpy(res, &nsio->res, sizeof(*res));
+	res->start += start_pad;
+	res->end -= end_trunc;
+
+	nd_pfn->mode = le32_to_cpu(nd_pfn->pfn_sb->mode);
+	if (nd_pfn->mode == PFN_MODE_RAM) {
+		if (offset < SZ_8K)
+			return ERR_PTR(-EINVAL);
+		nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
+		altmap = NULL;
+	} else if (nd_pfn->mode == PFN_MODE_PMEM) {
+		nd_pfn->npfns = (resource_size(res) - offset) / PAGE_SIZE;
+		if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
+			dev_info(&nd_pfn->dev,
+					"number of pfns truncated from %lld to %ld\n",
+					le64_to_cpu(nd_pfn->pfn_sb->npfns),
+					nd_pfn->npfns);
+		memcpy(altmap, &__altmap, sizeof(*altmap));
+		altmap->free = PHYS_PFN(offset - SZ_8K);
+		altmap->alloc = 0;
+	} else
+		return ERR_PTR(-ENXIO);
+
+	return altmap;
+}
+
+static int nd_pfn_init(struct nd_pfn *nd_pfn)
+{
+	struct nd_namespace_common *ndns = nd_pfn->ndns;
+	u32 start_pad = 0, end_trunc = 0;
+	resource_size_t start, size;
+	struct nd_namespace_io *nsio;
+	struct nd_region *nd_region;
+	struct nd_pfn_sb *pfn_sb;
+	unsigned long npfns;
+	phys_addr_t offset;
+	u64 checksum;
+	int rc;
+
+	pfn_sb = devm_kzalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
+	if (!pfn_sb)
+		return -ENOMEM;
+
+	nd_pfn->pfn_sb = pfn_sb;
+	rc = nd_pfn_validate(nd_pfn);
+	if (rc != -ENODEV)
+		return rc;
+
+	/* no info block, do init */;
+	nd_region = to_nd_region(nd_pfn->dev.parent);
+	if (nd_region->ro) {
+		dev_info(&nd_pfn->dev,
+				"%s is read-only, unable to init metadata\n",
+				dev_name(&nd_region->dev));
+		return -ENXIO;
+	}
+
+	memset(pfn_sb, 0, sizeof(*pfn_sb));
+
+	/*
+	 * Check if pmem collides with 'System RAM' when section aligned and
+	 * trim it accordingly
+	 */
+	nsio = to_nd_namespace_io(&ndns->dev);
+	start = PHYS_SECTION_ALIGN_DOWN(nsio->res.start);
+	size = resource_size(&nsio->res);
+	if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
+				IORES_DESC_NONE) == REGION_MIXED) {
+		start = nsio->res.start;
+		start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
+	}
+
+	start = nsio->res.start;
+	size = PHYS_SECTION_ALIGN_UP(start + size) - start;
+	if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
+				IORES_DESC_NONE) == REGION_MIXED) {
+		size = resource_size(&nsio->res);
+		end_trunc = start + size - PHYS_SECTION_ALIGN_DOWN(start + size);
+	}
+
+	if (start_pad + end_trunc)
+		dev_info(&nd_pfn->dev, "%s section collision, truncate %d bytes\n",
+				dev_name(&ndns->dev), start_pad + end_trunc);
+
+	/*
+	 * Note, we use 64 here for the standard size of struct page,
+	 * debugging options may cause it to be larger in which case the
+	 * implementation will limit the pfns advertised through
+	 * ->direct_access() to those that are included in the memmap.
+	 */
+	start += start_pad;
+	size = resource_size(&nsio->res);
+	npfns = (size - start_pad - end_trunc - SZ_8K) / SZ_4K;
+	if (nd_pfn->mode == PFN_MODE_PMEM)
+		offset = ALIGN(start + SZ_8K + 64 * npfns, nd_pfn->align)
+			- start;
+	else if (nd_pfn->mode == PFN_MODE_RAM)
+		offset = ALIGN(start + SZ_8K, nd_pfn->align) - start;
+	else
+		return -ENXIO;
+
+	if (offset + start_pad + end_trunc >= size) {
+		dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
+				dev_name(&ndns->dev));
+		return -ENXIO;
+	}
+
+	npfns = (size - offset - start_pad - end_trunc) / SZ_4K;
+	pfn_sb->mode = cpu_to_le32(nd_pfn->mode);
+	pfn_sb->dataoff = cpu_to_le64(offset);
+	pfn_sb->npfns = cpu_to_le64(npfns);
+	memcpy(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN);
+	memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
+	memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
+	pfn_sb->version_major = cpu_to_le16(1);
+	pfn_sb->version_minor = cpu_to_le16(1);
+	pfn_sb->start_pad = cpu_to_le32(start_pad);
+	pfn_sb->end_trunc = cpu_to_le32(end_trunc);
+	checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
+	pfn_sb->checksum = cpu_to_le64(checksum);
+
+	return nvdimm_write_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb));
+}
+
+/*
+ * Determine the effective resource range and vmem_altmap from an nd_pfn
+ * instance.
+ */
+struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
+		struct resource *res, struct vmem_altmap *altmap)
+{
+	int rc;
+
+	if (!nd_pfn->uuid || !nd_pfn->ndns)
+		return ERR_PTR(-ENODEV);
+
+	rc = nd_pfn_init(nd_pfn);
+	if (rc)
+		return ERR_PTR(rc);
+
+	/* we need a valid pfn_sb before we can init a vmem_altmap */
+	return __nvdimm_setup_pfn(nd_pfn, res, altmap);
+}
+EXPORT_SYMBOL_GPL(nvdimm_setup_pfn);
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 904f904e2962..ccbb58699c8f 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -182,9 +182,6 @@ void pmem_release_disk(void *disk)
 	put_disk(disk);
 }
 
-static struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
-		struct resource *res, struct vmem_altmap *altmap);
-
 static int pmem_attach_disk(struct device *dev,
 		struct nd_namespace_common *ndns)
 {
@@ -296,187 +293,6 @@ static int pmem_attach_disk(struct device *dev,
 	return 0;
 }
 
-static int nd_pfn_init(struct nd_pfn *nd_pfn)
-{
-	struct nd_namespace_common *ndns = nd_pfn->ndns;
-	u32 start_pad = 0, end_trunc = 0;
-	resource_size_t start, size;
-	struct nd_namespace_io *nsio;
-	struct nd_region *nd_region;
-	struct nd_pfn_sb *pfn_sb;
-	unsigned long npfns;
-	phys_addr_t offset;
-	u64 checksum;
-	int rc;
-
-	pfn_sb = devm_kzalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
-	if (!pfn_sb)
-		return -ENOMEM;
-
-	nd_pfn->pfn_sb = pfn_sb;
-	rc = nd_pfn_validate(nd_pfn);
-	if (rc == -ENODEV)
-		/* no info block, do init */;
-	else
-		return rc;
-
-	nd_region = to_nd_region(nd_pfn->dev.parent);
-	if (nd_region->ro) {
-		dev_info(&nd_pfn->dev,
-				"%s is read-only, unable to init metadata\n",
-				dev_name(&nd_region->dev));
-		return -ENXIO;
-	}
-
-	memset(pfn_sb, 0, sizeof(*pfn_sb));
-
-	/*
-	 * Check if pmem collides with 'System RAM' when section aligned and
-	 * trim it accordingly
-	 */
-	nsio = to_nd_namespace_io(&ndns->dev);
-	start = PHYS_SECTION_ALIGN_DOWN(nsio->res.start);
-	size = resource_size(&nsio->res);
-	if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
-				IORES_DESC_NONE) == REGION_MIXED) {
-
-		start = nsio->res.start;
-		start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
-	}
-
-	start = nsio->res.start;
-	size = PHYS_SECTION_ALIGN_UP(start + size) - start;
-	if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
-				IORES_DESC_NONE) == REGION_MIXED) {
-		size = resource_size(&nsio->res);
-		end_trunc = start + size - PHYS_SECTION_ALIGN_DOWN(start + size);
-	}
-
-	if (start_pad + end_trunc)
-		dev_info(&nd_pfn->dev, "%s section collision, truncate %d bytes\n",
-				dev_name(&ndns->dev), start_pad + end_trunc);
-
-	/*
-	 * Note, we use 64 here for the standard size of struct page,
-	 * debugging options may cause it to be larger in which case the
-	 * implementation will limit the pfns advertised through
-	 * ->direct_access() to those that are included in the memmap.
-	 */
-	start += start_pad;
-	size = resource_size(&nsio->res);
-	npfns = (size - start_pad - end_trunc - SZ_8K) / SZ_4K;
-	if (nd_pfn->mode == PFN_MODE_PMEM)
-		offset = ALIGN(start + SZ_8K + 64 * npfns, nd_pfn->align)
-			- start;
-	else if (nd_pfn->mode == PFN_MODE_RAM)
-		offset = ALIGN(start + SZ_8K, nd_pfn->align) - start;
-	else
-		return -ENXIO;
-
-	if (offset + start_pad + end_trunc >= size) {
-		dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
-				dev_name(&ndns->dev));
-		return -ENXIO;
-	}
-
-	npfns = (size - offset - start_pad - end_trunc) / SZ_4K;
-	pfn_sb->mode = cpu_to_le32(nd_pfn->mode);
-	pfn_sb->dataoff = cpu_to_le64(offset);
-	pfn_sb->npfns = cpu_to_le64(npfns);
-	memcpy(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN);
-	memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
-	memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
-	pfn_sb->version_major = cpu_to_le16(1);
-	pfn_sb->version_minor = cpu_to_le16(1);
-	pfn_sb->start_pad = cpu_to_le32(start_pad);
-	pfn_sb->end_trunc = cpu_to_le32(end_trunc);
-	checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
-	pfn_sb->checksum = cpu_to_le64(checksum);
-
-	return nvdimm_write_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb));
-}
-
-/*
- * We hotplug memory at section granularity, pad the reserved area from
- * the previous section base to the namespace base address.
- */
-static unsigned long init_altmap_base(resource_size_t base)
-{
-	unsigned long base_pfn = PHYS_PFN(base);
-
-	return PFN_SECTION_ALIGN_DOWN(base_pfn);
-}
-
-static unsigned long init_altmap_reserve(resource_size_t base)
-{
-	unsigned long reserve = PHYS_PFN(SZ_8K);
-	unsigned long base_pfn = PHYS_PFN(base);
-
-	reserve += base_pfn - PFN_SECTION_ALIGN_DOWN(base_pfn);
-	return reserve;
-}
-
-static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
-		struct resource *res, struct vmem_altmap *altmap)
-{
-	struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
-	u64 offset = le64_to_cpu(pfn_sb->dataoff);
-	u32 start_pad = __le32_to_cpu(pfn_sb->start_pad);
-	u32 end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
-	struct nd_namespace_common *ndns = nd_pfn->ndns;
-	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
-	resource_size_t base = nsio->res.start + start_pad;
-	struct vmem_altmap __altmap = {
-		.base_pfn = init_altmap_base(base),
-		.reserve = init_altmap_reserve(base),
-	};
-
-	memcpy(res, &nsio->res, sizeof(*res));
-	res->start += start_pad;
-	res->end -= end_trunc;
-
-	nd_pfn->mode = le32_to_cpu(nd_pfn->pfn_sb->mode);
-	if (nd_pfn->mode == PFN_MODE_RAM) {
-		if (offset < SZ_8K)
-			return ERR_PTR(-EINVAL);
-		nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
-		altmap = NULL;
-	} else if (nd_pfn->mode == PFN_MODE_PMEM) {
-		nd_pfn->npfns = (resource_size(res) - offset) / PAGE_SIZE;
-		if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
-			dev_info(&nd_pfn->dev,
-					"number of pfns truncated from %lld to %ld\n",
-					le64_to_cpu(nd_pfn->pfn_sb->npfns),
-					nd_pfn->npfns);
-		memcpy(altmap, &__altmap, sizeof(*altmap));
-		altmap->free = PHYS_PFN(offset - SZ_8K);
-		altmap->alloc = 0;
-	} else
-		return ERR_PTR(-ENXIO);
-
-	return altmap;
-}
-
-/*
- * Determine the effective resource range and vmem_altmap from an nd_pfn
- * instance.
- */
-static struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
-		struct resource *res, struct vmem_altmap *altmap)
-{
-	int rc;
-
-	if (!nd_pfn->uuid || !nd_pfn->ndns)
-		return ERR_PTR(-ENODEV);
-
-	rc = nd_pfn_init(nd_pfn);
-	if (rc)
-		return ERR_PTR(rc);
-
-	/* we need a valid pfn_sb before we can init a vmem_altmap */
-	return __nvdimm_setup_pfn(nd_pfn, res, altmap);
-}
-
 static int nd_pmem_probe(struct device *dev)
 {
 	struct nd_namespace_common *ndns;

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [PATCH v2] libnvdimm, pmem, pfn: move pfn setup to the core
  2016-03-25 22:15   ` [PATCH v2] " Dan Williams
@ 2016-03-29  8:30     ` Johannes Thumshirn
  0 siblings, 0 replies; 38+ messages in thread
From: Johannes Thumshirn @ 2016-03-29  8:30 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Dan Williams, linux-kernel

On Freitag, 25. März 2016 15:15:30 CEST Dan Williams wrote:
> Now that pmem internals have been disentangled from pfn setup, that code
> can move to the core.  This is in preparation for adding another user of
> the pfn-device capabilities.
> 
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
> Changes in v2:
> * Cleaned up the -ENODEV checking in nd_pfn_init() (Johannes)

Looks good,

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>

-- 
Johannes Thumshirn                                          Storage
jthumshirn@suse.de                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2016-03-29  8:30 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-24  1:25 [PATCH 00/13] prep for device-dax, untangle pfn-device setup Dan Williams
2016-03-24  1:25 ` [PATCH 01/13] libnvdimm, pfn: fix nvdimm_namespace_add_poison() vs section alignment Dan Williams
2016-03-24 10:10   ` Johannes Thumshirn
2016-03-24 14:48     ` Dan Williams
2016-03-24  1:25 ` [PATCH 02/13] libnvdimm, pmem: kill pmem->ndns Dan Williams
2016-03-24 10:31   ` Johannes Thumshirn
2016-03-24  1:25 ` [PATCH 03/13] libnvdimm, pfn, convert nd_pfn_probe() to devm Dan Williams
2016-03-24 10:45   ` Johannes Thumshirn
2016-03-24  1:25 ` [PATCH 04/13] libnvdimm, btt, convert nd_btt_probe() " Dan Williams
2016-03-24 11:05   ` Johannes Thumshirn
2016-03-24  1:25 ` [PATCH 05/13] libnvdimm, blk: use devm_add_action to release bdev resources Dan Williams
2016-03-24 11:48   ` Johannes Thumshirn
2016-03-24 15:14     ` Dan Williams
2016-03-24 15:15       ` Johannes Thumshirn
2016-03-24 15:21         ` Dan Williams
2016-03-24  1:25 ` [PATCH 06/13] libnvdimm, blk: use ->queuedata for driver private data Dan Williams
2016-03-24 11:51   ` Johannes Thumshirn
2016-03-24  1:25 ` [PATCH 07/13] libnvdimm, pmem: " Dan Williams
2016-03-24 12:06   ` Johannes Thumshirn
2016-03-24  1:26 ` [PATCH 08/13] libnvdimm, blk: move i/o infrastructure to nd_namespace_blk Dan Williams
2016-03-24 12:22   ` Johannes Thumshirn
2016-03-24 15:21     ` Dan Williams
2016-03-24 15:22       ` Johannes Thumshirn
2016-03-25 22:02   ` [PATCH v2] " Dan Williams
2016-03-24  1:26 ` [PATCH 09/13] libnvdimm, pmem: use devm_add_action to release bdev resources Dan Williams
2016-03-24 12:35   ` Johannes Thumshirn
2016-03-24  1:26 ` [PATCH 10/13] libnvdimm, pmem: clean up resource print / request Dan Williams
2016-03-24 13:42   ` Johannes Thumshirn
2016-03-24  1:26 ` [PATCH 11/13] libnvdimm, pmem, pfn: make pmem_rw_bytes generic and refactor pfn setup Dan Williams
2016-03-24 13:50   ` Johannes Thumshirn
2016-03-25 22:13   ` [PATCH v2] " Dan Williams
2016-03-24  1:26 ` [PATCH 12/13] libnvdimm, pmem, pfn: move pfn setup to the core Dan Williams
2016-03-24 14:36   ` Johannes Thumshirn
2016-03-24 15:26     ` Dan Williams
2016-03-25 22:15   ` [PATCH v2] " Dan Williams
2016-03-29  8:30     ` Johannes Thumshirn
2016-03-24  1:26 ` [PATCH 13/13] libnvdimm, pmem: kill ->pmem_queue and ->pmem_disk Dan Williams
2016-03-24 14:38   ` Johannes Thumshirn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).