[PATCH 14/21] nd: namespace indices: read and validate

2015-04-17 Thread Dan Williams
On media label format consists of two index blocks followed by an array
of labels.  None of these structures are ever updated in place.  A
sequence number tracks the current active index and the next one to
write, while labels are written to free slots.

++
||
|  nsindex0  |
||
++
||
|  nsindex1  |
||
++
|   label0   |
++
|   label1   |
++
||
 nslot...
||
++
|   labelN   |
++

After reading valid labels, store the dpa ranges they claim into
per-dimm resource trees.

Signed-off-by: Dan Williams 
---
 drivers/block/nd/Makefile|1 
 drivers/block/nd/dimm.c  |   25 +++-
 drivers/block/nd/dimm_devs.c |6 +
 drivers/block/nd/label.c |  291 ++
 drivers/block/nd/label.h |  129 +++
 drivers/block/nd/nd.h|   45 ++
 include/uapi/linux/ndctl.h   |1 
 7 files changed, 495 insertions(+), 3 deletions(-)
 create mode 100644 drivers/block/nd/label.c
 create mode 100644 drivers/block/nd/label.h

diff --git a/drivers/block/nd/Makefile b/drivers/block/nd/Makefile
index c0194d52e5ad..93856f1c9dbd 100644
--- a/drivers/block/nd/Makefile
+++ b/drivers/block/nd/Makefile
@@ -27,5 +27,6 @@ nd-y += dimm.o
 nd-y += region_devs.o
 nd-y += region.o
 nd-y += namespace_devs.o
+nd-y += label.o
 
 nd_pmem-y := pmem.o
diff --git a/drivers/block/nd/dimm.c b/drivers/block/nd/dimm.c
index 7e043c0c1bf5..ccc96d8fe2e7 100644
--- a/drivers/block/nd/dimm.c
+++ b/drivers/block/nd/dimm.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include "label.h"
 #include "nd.h"
 
 static bool force_enable_dimms;
@@ -53,6 +54,12 @@ static int nd_dimm_probe(struct device *dev)
return -ENOMEM;
 
dev_set_drvdata(dev, ndd);
+   ndd->dpa.name = dev_name(dev);
+   ndd->ns_current = -1;
+   ndd->ns_next = -1;
+   ndd->dpa.start = 0;
+   ndd->dpa.end = -1;
+   ndd->dev = dev;
 
rc = nd_dimm_init_nsarea(ndd);
if (rc)
@@ -64,18 +71,34 @@ static int nd_dimm_probe(struct device *dev)
 
dev_dbg(dev, "config data size: %d\n", ndd->nsarea.config_size);
 
+   nd_bus_lock(dev);
+   ndd->ns_current = nd_label_validate(ndd);
+   ndd->ns_next = nd_label_next_nsindex(ndd->ns_current);
+   nd_label_copy(ndd, to_next_namespace_index(ndd),
+   to_current_namespace_index(ndd));
+   rc = nd_label_reserve_dpa(ndd);
+   nd_bus_unlock(dev);
+
+   if (rc)
+   goto err;
+
return 0;
 
  err:
free_data(ndd);
return rc;
-
 }
 
 static int nd_dimm_remove(struct device *dev)
 {
struct nd_dimm_drvdata *ndd = dev_get_drvdata(dev);
+   struct resource *res, *_r;
 
+   nd_bus_lock(dev);
+   dev_set_drvdata(dev, NULL);
+   for_each_dpa_resource_safe(ndd, res, _r)
+   __release_region(>dpa, res->start, resource_size(res));
+   nd_bus_unlock(dev);
free_data(ndd);
 
return 0;
diff --git a/drivers/block/nd/dimm_devs.c b/drivers/block/nd/dimm_devs.c
index 6192d9c82b9b..652dee210fe8 100644
--- a/drivers/block/nd/dimm_devs.c
+++ b/drivers/block/nd/dimm_devs.c
@@ -94,8 +94,12 @@ int nd_dimm_init_config_data(struct nd_dimm_drvdata *ndd)
if (ndd->data)
return 0;
 
-   if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0)
+   if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0
+   || ndd->nsarea.config_size < ND_LABEL_MIN_SIZE) {
+   dev_dbg(ndd->dev, "failed to init config data area: (%d:%d)\n",
+   ndd->nsarea.max_xfer, ndd->nsarea.config_size);
return -ENXIO;
+   }
 
ndd->data = kmalloc(ndd->nsarea.config_size, GFP_KERNEL);
if (!ndd->data)
diff --git a/drivers/block/nd/label.c b/drivers/block/nd/label.c
new file mode 100644
index ..e791ea8bbdde
--- /dev/null
+++ b/drivers/block/nd/label.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include 
+#include 
+#include 
+#include 
+#include "nd-private.h"
+#include "label.h"
+#include "nd.h"
+
+#include 
+
+static u32 best_seq(u32 a, u32 b)
+{
+   a &= NSINDEX_SEQ_MASK;
+   b &= NSINDEX_SEQ_MASK;
+
+   if (a == 0 || a == b)
+   return b;
+   else if (b == 0)
+  

[PATCH 14/21] nd: namespace indices: read and validate

2015-04-17 Thread Dan Williams
On media label format consists of two index blocks followed by an array
of labels.  None of these structures are ever updated in place.  A
sequence number tracks the current active index and the next one to
write, while labels are written to free slots.

++
||
|  nsindex0  |
||
++
||
|  nsindex1  |
||
++
|   label0   |
++
|   label1   |
++
||
 nslot...
||
++
|   labelN   |
++

After reading valid labels, store the dpa ranges they claim into
per-dimm resource trees.

Signed-off-by: Dan Williams dan.j.willi...@intel.com
---
 drivers/block/nd/Makefile|1 
 drivers/block/nd/dimm.c  |   25 +++-
 drivers/block/nd/dimm_devs.c |6 +
 drivers/block/nd/label.c |  291 ++
 drivers/block/nd/label.h |  129 +++
 drivers/block/nd/nd.h|   45 ++
 include/uapi/linux/ndctl.h   |1 
 7 files changed, 495 insertions(+), 3 deletions(-)
 create mode 100644 drivers/block/nd/label.c
 create mode 100644 drivers/block/nd/label.h

diff --git a/drivers/block/nd/Makefile b/drivers/block/nd/Makefile
index c0194d52e5ad..93856f1c9dbd 100644
--- a/drivers/block/nd/Makefile
+++ b/drivers/block/nd/Makefile
@@ -27,5 +27,6 @@ nd-y += dimm.o
 nd-y += region_devs.o
 nd-y += region.o
 nd-y += namespace_devs.o
+nd-y += label.o
 
 nd_pmem-y := pmem.o
diff --git a/drivers/block/nd/dimm.c b/drivers/block/nd/dimm.c
index 7e043c0c1bf5..ccc96d8fe2e7 100644
--- a/drivers/block/nd/dimm.c
+++ b/drivers/block/nd/dimm.c
@@ -18,6 +18,7 @@
 #include linux/slab.h
 #include linux/mm.h
 #include linux/nd.h
+#include label.h
 #include nd.h
 
 static bool force_enable_dimms;
@@ -53,6 +54,12 @@ static int nd_dimm_probe(struct device *dev)
return -ENOMEM;
 
dev_set_drvdata(dev, ndd);
+   ndd-dpa.name = dev_name(dev);
+   ndd-ns_current = -1;
+   ndd-ns_next = -1;
+   ndd-dpa.start = 0;
+   ndd-dpa.end = -1;
+   ndd-dev = dev;
 
rc = nd_dimm_init_nsarea(ndd);
if (rc)
@@ -64,18 +71,34 @@ static int nd_dimm_probe(struct device *dev)
 
dev_dbg(dev, config data size: %d\n, ndd-nsarea.config_size);
 
+   nd_bus_lock(dev);
+   ndd-ns_current = nd_label_validate(ndd);
+   ndd-ns_next = nd_label_next_nsindex(ndd-ns_current);
+   nd_label_copy(ndd, to_next_namespace_index(ndd),
+   to_current_namespace_index(ndd));
+   rc = nd_label_reserve_dpa(ndd);
+   nd_bus_unlock(dev);
+
+   if (rc)
+   goto err;
+
return 0;
 
  err:
free_data(ndd);
return rc;
-
 }
 
 static int nd_dimm_remove(struct device *dev)
 {
struct nd_dimm_drvdata *ndd = dev_get_drvdata(dev);
+   struct resource *res, *_r;
 
+   nd_bus_lock(dev);
+   dev_set_drvdata(dev, NULL);
+   for_each_dpa_resource_safe(ndd, res, _r)
+   __release_region(ndd-dpa, res-start, resource_size(res));
+   nd_bus_unlock(dev);
free_data(ndd);
 
return 0;
diff --git a/drivers/block/nd/dimm_devs.c b/drivers/block/nd/dimm_devs.c
index 6192d9c82b9b..652dee210fe8 100644
--- a/drivers/block/nd/dimm_devs.c
+++ b/drivers/block/nd/dimm_devs.c
@@ -94,8 +94,12 @@ int nd_dimm_init_config_data(struct nd_dimm_drvdata *ndd)
if (ndd-data)
return 0;
 
-   if (ndd-nsarea.status || ndd-nsarea.max_xfer == 0)
+   if (ndd-nsarea.status || ndd-nsarea.max_xfer == 0
+   || ndd-nsarea.config_size  ND_LABEL_MIN_SIZE) {
+   dev_dbg(ndd-dev, failed to init config data area: (%d:%d)\n,
+   ndd-nsarea.max_xfer, ndd-nsarea.config_size);
return -ENXIO;
+   }
 
ndd-data = kmalloc(ndd-nsarea.config_size, GFP_KERNEL);
if (!ndd-data)
diff --git a/drivers/block/nd/label.c b/drivers/block/nd/label.c
new file mode 100644
index ..e791ea8bbdde
--- /dev/null
+++ b/drivers/block/nd/label.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include linux/device.h
+#include linux/ndctl.h
+#include linux/io.h
+#include linux/nd.h
+#include nd-private.h
+#include label.h
+#include nd.h
+
+#include asm-generic/io-64-nonatomic-lo-hi.h
+
+static u32 best_seq(u32 a, u32 b)
+{
+   a = NSINDEX_SEQ_MASK;
+   b =