[PATCH v2 17/20] libnd: write blk label set

2015-04-28 Thread Dan Williams
After 'uuid', 'size', 'sector_size', and optionally 'alt_name' have been
set to valid values the labels on the dimm can be updated.  The
difference with the pmem case is that blk namespaces are limited to one
dimm and can cover discontiguous ranges in dpa space.

Also, after allocating label slots, it is useful for userspace to know
how many slots are left.  Export this information in sysfs.

Cc: Greg KH 
Cc: Neil Brown 
Signed-off-by: Dan Williams 
---
 drivers/block/nd/bus.c|4 
 drivers/block/nd/dimm_devs.c  |   25 +++
 drivers/block/nd/label.c  |  297 +++--
 drivers/block/nd/label.h  |5 +
 drivers/block/nd/namespace_devs.c |   57 +++
 drivers/block/nd/nd-private.h |1 
 6 files changed, 367 insertions(+), 22 deletions(-)

diff --git a/drivers/block/nd/bus.c b/drivers/block/nd/bus.c
index 819259e92468..6c272f245f4e 100644
--- a/drivers/block/nd/bus.c
+++ b/drivers/block/nd/bus.c
@@ -136,6 +136,10 @@ static void nd_async_device_unregister(void *d, 
async_cookie_t cookie)
 {
struct device *dev = d;
 
+   /* flush bus operations before delete */
+   nd_bus_lock(dev);
+   nd_bus_unlock(dev);
+
device_unregister(dev);
put_device(dev);
 }
diff --git a/drivers/block/nd/dimm_devs.c b/drivers/block/nd/dimm_devs.c
index 358b2a06d680..4b225c8b7d0a 100644
--- a/drivers/block/nd/dimm_devs.c
+++ b/drivers/block/nd/dimm_devs.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include "nd-private.h"
+#include "label.h"
 #include "nd.h"
 
 static DEFINE_IDA(dimm_ida);
@@ -262,9 +263,33 @@ static ssize_t state_show(struct device *dev, struct 
device_attribute *attr,
 }
 static DEVICE_ATTR_RO(state);
 
+static ssize_t available_slots_show(struct device *dev,
+   struct device_attribute *attr, char *buf)
+{
+   struct nd_dimm_drvdata *ndd = dev_get_drvdata(dev);
+   ssize_t rc;
+   u32 nfree;
+
+   if (!ndd)
+   return -ENXIO;
+
+   nd_bus_lock(dev);
+   nfree = nd_label_nfree(ndd);
+   if (nfree - 1 > nfree) {
+   dev_WARN_ONCE(dev, 1, "we ate our last label?\n");
+   nfree = 0;
+   } else
+   nfree--;
+   rc = sprintf(buf, "%d\n", nfree);
+   nd_bus_unlock(dev);
+   return rc;
+}
+static DEVICE_ATTR_RO(available_slots);
+
 static struct attribute *nd_dimm_attributes[] = {
_attr_state.attr,
_attr_commands.attr,
+   _attr_available_slots.attr,
NULL,
 };
 
diff --git a/drivers/block/nd/label.c b/drivers/block/nd/label.c
index 78898b642191..069c26d50ed1 100644
--- a/drivers/block/nd/label.c
+++ b/drivers/block/nd/label.c
@@ -58,7 +58,7 @@ size_t sizeof_namespace_index(struct nd_dimm_drvdata *ndd)
return ndd->nsindex_size;
 }
 
-static int nd_dimm_num_label_slots(struct nd_dimm_drvdata *ndd)
+int nd_dimm_num_label_slots(struct nd_dimm_drvdata *ndd)
 {
return ndd->nsarea.config_size / 129;
 }
@@ -416,7 +416,7 @@ u32 nd_label_nfree(struct nd_dimm_drvdata *ndd)
WARN_ON(!is_nd_bus_locked(ndd->dev));
 
if (!preamble_next(ndd, , , ))
-   return 0;
+   return nd_dimm_num_label_slots(ndd);
 
return bitmap_weight(free, nslot);
 }
@@ -553,22 +553,270 @@ static int __pmem_label_update(struct nd_region 
*nd_region,
return 0;
 }
 
-static int init_labels(struct nd_mapping *nd_mapping)
+static void del_label(struct nd_mapping *nd_mapping, int l)
+{
+   struct nd_namespace_label __iomem *next_label, __iomem *nd_label;
+   struct nd_dimm_drvdata *ndd = to_ndd(nd_mapping);
+   unsigned int slot;
+   int j;
+
+   nd_label = nd_get_label(nd_mapping->labels, l);
+   slot = to_slot(ndd, nd_label);
+   dev_vdbg(ndd->dev, "%s: clear: %d\n", __func__, slot);
+
+   for (j = l; (next_label = nd_get_label(nd_mapping->labels, j + 1)); j++)
+   nd_set_label(nd_mapping->labels, next_label, j);
+   nd_set_label(nd_mapping->labels, NULL, j);
+}
+
+static bool is_old_resource(struct resource *res, struct resource **list, int 
n)
 {
int i;
+
+   if (res->flags & DPA_RESOURCE_ADJUSTED)
+   return false;
+   for (i = 0; i < n; i++)
+   if (res == list[i])
+   return true;
+   return false;
+}
+
+static struct resource *to_resource(struct nd_dimm_drvdata *ndd,
+   struct nd_namespace_label __iomem *nd_label)
+{
+   struct resource *res;
+
+   for_each_dpa_resource(ndd, res) {
+   if (res->start != readq(_label->dpa))
+   continue;
+   if (resource_size(res) != readq(_label->rawsize))
+   continue;
+   return res;
+   }
+
+   return NULL;
+}
+
+/*
+ * 1/ Account all the labels that can be freed after this update
+ * 2/ Allocate and write the label to the staging (next) index
+ * 3/ Record the resources in the namespace device
+ */
+static int 

[PATCH v2 17/20] libnd: write blk label set

2015-04-28 Thread Dan Williams
After 'uuid', 'size', 'sector_size', and optionally 'alt_name' have been
set to valid values the labels on the dimm can be updated.  The
difference with the pmem case is that blk namespaces are limited to one
dimm and can cover discontiguous ranges in dpa space.

Also, after allocating label slots, it is useful for userspace to know
how many slots are left.  Export this information in sysfs.

Cc: Greg KH gre...@linuxfoundation.org
Cc: Neil Brown ne...@suse.de
Signed-off-by: Dan Williams dan.j.willi...@intel.com
---
 drivers/block/nd/bus.c|4 
 drivers/block/nd/dimm_devs.c  |   25 +++
 drivers/block/nd/label.c  |  297 +++--
 drivers/block/nd/label.h  |5 +
 drivers/block/nd/namespace_devs.c |   57 +++
 drivers/block/nd/nd-private.h |1 
 6 files changed, 367 insertions(+), 22 deletions(-)

diff --git a/drivers/block/nd/bus.c b/drivers/block/nd/bus.c
index 819259e92468..6c272f245f4e 100644
--- a/drivers/block/nd/bus.c
+++ b/drivers/block/nd/bus.c
@@ -136,6 +136,10 @@ static void nd_async_device_unregister(void *d, 
async_cookie_t cookie)
 {
struct device *dev = d;
 
+   /* flush bus operations before delete */
+   nd_bus_lock(dev);
+   nd_bus_unlock(dev);
+
device_unregister(dev);
put_device(dev);
 }
diff --git a/drivers/block/nd/dimm_devs.c b/drivers/block/nd/dimm_devs.c
index 358b2a06d680..4b225c8b7d0a 100644
--- a/drivers/block/nd/dimm_devs.c
+++ b/drivers/block/nd/dimm_devs.c
@@ -19,6 +19,7 @@
 #include linux/fs.h
 #include linux/mm.h
 #include nd-private.h
+#include label.h
 #include nd.h
 
 static DEFINE_IDA(dimm_ida);
@@ -262,9 +263,33 @@ static ssize_t state_show(struct device *dev, struct 
device_attribute *attr,
 }
 static DEVICE_ATTR_RO(state);
 
+static ssize_t available_slots_show(struct device *dev,
+   struct device_attribute *attr, char *buf)
+{
+   struct nd_dimm_drvdata *ndd = dev_get_drvdata(dev);
+   ssize_t rc;
+   u32 nfree;
+
+   if (!ndd)
+   return -ENXIO;
+
+   nd_bus_lock(dev);
+   nfree = nd_label_nfree(ndd);
+   if (nfree - 1  nfree) {
+   dev_WARN_ONCE(dev, 1, we ate our last label?\n);
+   nfree = 0;
+   } else
+   nfree--;
+   rc = sprintf(buf, %d\n, nfree);
+   nd_bus_unlock(dev);
+   return rc;
+}
+static DEVICE_ATTR_RO(available_slots);
+
 static struct attribute *nd_dimm_attributes[] = {
dev_attr_state.attr,
dev_attr_commands.attr,
+   dev_attr_available_slots.attr,
NULL,
 };
 
diff --git a/drivers/block/nd/label.c b/drivers/block/nd/label.c
index 78898b642191..069c26d50ed1 100644
--- a/drivers/block/nd/label.c
+++ b/drivers/block/nd/label.c
@@ -58,7 +58,7 @@ size_t sizeof_namespace_index(struct nd_dimm_drvdata *ndd)
return ndd-nsindex_size;
 }
 
-static int nd_dimm_num_label_slots(struct nd_dimm_drvdata *ndd)
+int nd_dimm_num_label_slots(struct nd_dimm_drvdata *ndd)
 {
return ndd-nsarea.config_size / 129;
 }
@@ -416,7 +416,7 @@ u32 nd_label_nfree(struct nd_dimm_drvdata *ndd)
WARN_ON(!is_nd_bus_locked(ndd-dev));
 
if (!preamble_next(ndd, nsindex, free, nslot))
-   return 0;
+   return nd_dimm_num_label_slots(ndd);
 
return bitmap_weight(free, nslot);
 }
@@ -553,22 +553,270 @@ static int __pmem_label_update(struct nd_region 
*nd_region,
return 0;
 }
 
-static int init_labels(struct nd_mapping *nd_mapping)
+static void del_label(struct nd_mapping *nd_mapping, int l)
+{
+   struct nd_namespace_label __iomem *next_label, __iomem *nd_label;
+   struct nd_dimm_drvdata *ndd = to_ndd(nd_mapping);
+   unsigned int slot;
+   int j;
+
+   nd_label = nd_get_label(nd_mapping-labels, l);
+   slot = to_slot(ndd, nd_label);
+   dev_vdbg(ndd-dev, %s: clear: %d\n, __func__, slot);
+
+   for (j = l; (next_label = nd_get_label(nd_mapping-labels, j + 1)); j++)
+   nd_set_label(nd_mapping-labels, next_label, j);
+   nd_set_label(nd_mapping-labels, NULL, j);
+}
+
+static bool is_old_resource(struct resource *res, struct resource **list, int 
n)
 {
int i;
+
+   if (res-flags  DPA_RESOURCE_ADJUSTED)
+   return false;
+   for (i = 0; i  n; i++)
+   if (res == list[i])
+   return true;
+   return false;
+}
+
+static struct resource *to_resource(struct nd_dimm_drvdata *ndd,
+   struct nd_namespace_label __iomem *nd_label)
+{
+   struct resource *res;
+
+   for_each_dpa_resource(ndd, res) {
+   if (res-start != readq(nd_label-dpa))
+   continue;
+   if (resource_size(res) != readq(nd_label-rawsize))
+   continue;
+   return res;
+   }
+
+   return NULL;
+}
+
+/*
+ * 1/ Account all the labels that can be freed after this update
+ * 2/ Allocate and write the label to the