diff mbox

[7/9] block, badblocks, pmem: introduce devm_alloc_badblocks

Message ID 20160106072324.40900.56605.stgit@dwillia2-desk3.amr.corp.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dan Williams Jan. 6, 2016, 7:23 a.m. UTC
Provide a devres interface for allocating a badblocks instance.  The
pmem driver has several scenarios where it will be beneficial to have
this structure automatically freed when the device is disabled / fails
probe.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 block/badblocks.c         |   74 ++++++++++++++++++++++++++++++---------------
 drivers/nvdimm/core.c     |   12 ++++---
 drivers/nvdimm/pmem.c     |    1 -
 include/linux/badblocks.h |    2 +
 4 files changed, 59 insertions(+), 30 deletions(-)
diff mbox

Patch

diff --git a/block/badblocks.c b/block/badblocks.c
index 0d5030aae715..82978a68a438 100644
--- a/block/badblocks.c
+++ b/block/badblocks.c
@@ -17,6 +17,7 @@ 
 
 #include <linux/badblocks.h>
 #include <linux/seqlock.h>
+#include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/stddef.h>
@@ -522,21 +523,26 @@  ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
 }
 EXPORT_SYMBOL_GPL(badblocks_store);
 
-struct badblocks *badblocks_alloc(void)
+static int __badblocks_init(struct device *dev, struct badblocks *bb,
+		int enable)
 {
-	struct badblocks *bb;
-	int rc;
-
-	bb = kzalloc(sizeof(*bb), GFP_KERNEL);
-	if (!bb)
-		return ERR_PTR(-ENOMEM);
+	bb->count = 0;
+	if (enable)
+		bb->shift = 0;
+	else
+		bb->shift = -1;
+	if (dev)
+		bb->page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL);
+	else
+		bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (bb->page == (u64 *)0) {
+		bb->shift = -1;
+		return -ENOMEM;
+	}
+	seqlock_init(&bb->lock);
 
-	rc = badblocks_init(bb, 1);
-	if (rc)
-		return ERR_PTR(rc);
-	return bb;
+	return 0;
 }
-EXPORT_SYMBOL_GPL(badblocks_alloc);
 
 /**
  * badblocks_init() - initialize the badblocks structure
@@ -549,21 +555,41 @@  EXPORT_SYMBOL_GPL(badblocks_alloc);
  */
 int badblocks_init(struct badblocks *bb, int enable)
 {
-	bb->count = 0;
-	if (enable)
-		bb->shift = 0;
+	return __badblocks_init(NULL, bb, enable);
+}
+EXPORT_SYMBOL_GPL(badblocks_init);
+
+static struct badblocks *__badblocks_alloc(struct device *dev)
+{
+	struct badblocks *bb;
+	int rc;
+
+	if (dev)
+		bb = devm_kzalloc(dev, sizeof(*bb), GFP_KERNEL);
 	else
-		bb->shift = -1;
-	bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL);
-	if (bb->page == (u64 *)0) {
-		bb->shift = -1;
-		return -ENOMEM;
-	}
-	seqlock_init(&bb->lock);
+		bb = kzalloc(sizeof(*bb), GFP_KERNEL);
+	if (!bb)
+		return ERR_PTR(-ENOMEM);
 
-	return 0;
+	rc = __badblocks_init(dev, bb, 1);
+	if (rc)
+		return ERR_PTR(rc);
+	return bb;
 }
-EXPORT_SYMBOL_GPL(badblocks_init);
+
+struct badblocks *badblocks_alloc(void)
+{
+	return __badblocks_alloc(NULL);
+}
+EXPORT_SYMBOL_GPL(badblocks_alloc);
+
+struct badblocks *devm_alloc_badblocks(struct device *dev)
+{
+	if (!dev)
+		return ERR_PTR(-EINVAL);
+	return __badblocks_alloc(dev);
+}
+EXPORT_SYMBOL_GPL(devm_alloc_badblocks);
 
 /**
  * badblocks_free() - free the badblocks structure
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
index c31a699aaed9..d07fb900bdf2 100644
--- a/drivers/nvdimm/core.c
+++ b/drivers/nvdimm/core.c
@@ -363,6 +363,7 @@  EXPORT_SYMBOL_GPL(__nvdimm_bus_register);
 
 /**
  * __add_badblock_range() - Convert a physical address range to bad sectors
+ * @dev:	host device for allocations
  * @bb:		badblocks instance to establish / extend
  * @ns_offset:	namespace offset where the error range begins (in bytes)
  * @len:	number of bytes of poison to be added
@@ -371,8 +372,8 @@  EXPORT_SYMBOL_GPL(__nvdimm_bus_register);
  * the bounds of physical addresses for this namespace, i.e. lies in the
  * interval [ns_start, ns_start + ns_size)
  */
-static int __add_badblock_range(struct badblocks **bb, u64 ns_offset,
-		u64 len)
+static int __add_badblock_range(struct device *dev, struct badblocks **bb,
+		u64 ns_offset, u64 len)
 {
 	const unsigned int sector_size = 512;
 	sector_t start_sector;
@@ -386,7 +387,7 @@  static int __add_badblock_range(struct badblocks **bb, u64 ns_offset,
 		num_sectors++;
 
 	if (!*bb) {
-		*bb = badblocks_alloc();
+		*bb = devm_alloc_badblocks(dev);
 		if (IS_ERR(*bb))
 			return PTR_ERR(*bb);
 	}
@@ -472,7 +473,8 @@  struct badblocks *nvdimm_namespace_badblocks(struct nd_namespace_common *ndns,
 			else
 				len = ns_start + ns_size - pl->start;
 
-			rc = __add_badblock_range(&bb, start - ns_start, len);
+			rc = __add_badblock_range(&ndns->dev, &bb,
+					start - ns_start, len);
 			if (rc)
 				return ERR_PTR(rc);
 			dev_info(&nvdimm_bus->dev,
@@ -489,7 +491,7 @@  struct badblocks *nvdimm_namespace_badblocks(struct nd_namespace_common *ndns,
 			else
 				len = ns_size;
 
-			rc = __add_badblock_range(&bb, 0, len);
+			rc = __add_badblock_range(&ndns->dev, &bb, 0, len);
 			if (rc)
 				return ERR_PTR(rc);
 			dev_info(&nvdimm_bus->dev,
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 082d6ae11d48..0d1f307175b2 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -185,7 +185,6 @@  static void pmem_detach_disk(struct pmem_device *pmem)
 	if (!disk)
 		return;
 
-	badblocks_free(disk->bb);
 	del_gendisk_queue(disk);
 	put_disk(disk);
 }
diff --git a/include/linux/badblocks.h b/include/linux/badblocks.h
index e74aae7c66e2..75b4a346fb5a 100644
--- a/include/linux/badblocks.h
+++ b/include/linux/badblocks.h
@@ -49,6 +49,8 @@  ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
 			int unack);
 int badblocks_init(struct badblocks *bb, int enable);
 struct badblocks *badblocks_alloc(void);
+struct device;
+struct badblocks *devm_alloc_badblocks(struct device *dev);
 void badblocks_free(struct badblocks *bb);
 
 #endif