[PATCH 14/21] nd: namespace indices: read and validate
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
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 =