Commit 0e3b0d12 authored by Dan Williams's avatar Dan Williams

libnvdimm, namespace: allow multiple pmem-namespaces per region at scan time

If label scanning finds multiple valid pmem namespaces allow them to be
surfaced rather than fail namespace scanning. Support for creating
multiple namespaces per region is saved for a later patch.

Note that this adds some new error messages to clarify which of the pmem
namespaces in the set are potentially impacted by invalid labels.
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent bd4cd745
...@@ -29,7 +29,10 @@ static void namespace_io_release(struct device *dev) ...@@ -29,7 +29,10 @@ static void namespace_io_release(struct device *dev)
static void namespace_pmem_release(struct device *dev) static void namespace_pmem_release(struct device *dev)
{ {
struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev); struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev);
struct nd_region *nd_region = to_nd_region(dev->parent);
if (nspm->id >= 0)
ida_simple_remove(&nd_region->ns_ida, nspm->id);
kfree(nspm->alt_name); kfree(nspm->alt_name);
kfree(nspm->uuid); kfree(nspm->uuid);
kfree(nspm); kfree(nspm);
...@@ -833,13 +836,45 @@ static int grow_dpa_allocation(struct nd_region *nd_region, ...@@ -833,13 +836,45 @@ static int grow_dpa_allocation(struct nd_region *nd_region,
return 0; return 0;
} }
static void nd_namespace_pmem_set_size(struct nd_region *nd_region, static void nd_namespace_pmem_set_resource(struct nd_region *nd_region,
struct nd_namespace_pmem *nspm, resource_size_t size) struct nd_namespace_pmem *nspm, resource_size_t size)
{ {
struct resource *res = &nspm->nsio.res; struct resource *res = &nspm->nsio.res;
resource_size_t offset = 0;
res->start = nd_region->ndr_start; if (size && !nspm->uuid) {
res->end = nd_region->ndr_start + size - 1; WARN_ON_ONCE(1);
size = 0;
}
if (size && nspm->uuid) {
struct nd_mapping *nd_mapping = &nd_region->mapping[0];
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
struct nd_label_id label_id;
struct resource *res;
if (!ndd) {
size = 0;
goto out;
}
nd_label_gen_id(&label_id, nspm->uuid, 0);
/* calculate a spa offset from the dpa allocation offset */
for_each_dpa_resource(ndd, res)
if (strcmp(res->name, label_id.id) == 0) {
offset = (res->start - nd_mapping->start)
* nd_region->ndr_mappings;
goto out;
}
WARN_ON_ONCE(1);
size = 0;
}
out:
res->start = nd_region->ndr_start + offset;
res->end = res->start + size - 1;
} }
static bool uuid_not_set(const u8 *uuid, struct device *dev, const char *where) static bool uuid_not_set(const u8 *uuid, struct device *dev, const char *where)
...@@ -930,7 +965,7 @@ static ssize_t __size_store(struct device *dev, unsigned long long val) ...@@ -930,7 +965,7 @@ static ssize_t __size_store(struct device *dev, unsigned long long val)
if (is_namespace_pmem(dev)) { if (is_namespace_pmem(dev)) {
struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev); struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev);
nd_namespace_pmem_set_size(nd_region, nspm, nd_namespace_pmem_set_resource(nd_region, nspm,
val * nd_region->ndr_mappings); val * nd_region->ndr_mappings);
} else if (is_namespace_blk(dev)) { } else if (is_namespace_blk(dev)) {
struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev); struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev);
...@@ -1546,6 +1581,7 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) ...@@ -1546,6 +1581,7 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id)
for (i = 0; i < nd_region->ndr_mappings; i++) { for (i = 0; i < nd_region->ndr_mappings; i++) {
struct nd_mapping *nd_mapping = &nd_region->mapping[i]; struct nd_mapping *nd_mapping = &nd_region->mapping[i];
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
struct nd_namespace_label *nd_label = NULL; struct nd_namespace_label *nd_label = NULL;
u64 hw_start, hw_end, pmem_start, pmem_end; u64 hw_start, hw_end, pmem_start, pmem_end;
struct nd_label_ent *label_ent; struct nd_label_ent *label_ent;
...@@ -1573,10 +1609,14 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) ...@@ -1573,10 +1609,14 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id)
hw_end = hw_start + nd_mapping->size; hw_end = hw_start + nd_mapping->size;
pmem_start = __le64_to_cpu(nd_label->dpa); pmem_start = __le64_to_cpu(nd_label->dpa);
pmem_end = pmem_start + __le64_to_cpu(nd_label->rawsize); pmem_end = pmem_start + __le64_to_cpu(nd_label->rawsize);
if (pmem_start == hw_start && pmem_end <= hw_end) if (pmem_start >= hw_start && pmem_start < hw_end
&& pmem_end <= hw_end && pmem_end > hw_start)
/* pass */; /* pass */;
else else {
dev_dbg(&nd_region->dev, "%s invalid label for %pUb\n",
dev_name(ndd->dev), nd_label->uuid);
return -EINVAL; return -EINVAL;
}
/* move recently validated label to the front of the list */ /* move recently validated label to the front of the list */
list_move(&label_ent->list, &nd_mapping->labels); list_move(&label_ent->list, &nd_mapping->labels);
...@@ -1618,6 +1658,7 @@ struct device *create_namespace_pmem(struct nd_region *nd_region, ...@@ -1618,6 +1658,7 @@ struct device *create_namespace_pmem(struct nd_region *nd_region,
if (!nspm) if (!nspm)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
nspm->id = -1;
dev = &nspm->nsio.common.dev; dev = &nspm->nsio.common.dev;
dev->type = &namespace_pmem_device_type; dev->type = &namespace_pmem_device_type;
dev->parent = &nd_region->dev; dev->parent = &nd_region->dev;
...@@ -1629,11 +1670,15 @@ struct device *create_namespace_pmem(struct nd_region *nd_region, ...@@ -1629,11 +1670,15 @@ struct device *create_namespace_pmem(struct nd_region *nd_region,
if (!has_uuid_at_pos(nd_region, nd_label->uuid, cookie, i)) if (!has_uuid_at_pos(nd_region, nd_label->uuid, cookie, i))
break; break;
if (i < nd_region->ndr_mappings) { if (i < nd_region->ndr_mappings) {
struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]);
/* /*
* Give up if we don't find an instance of a uuid at each * Give up if we don't find an instance of a uuid at each
* position (from 0 to nd_region->ndr_mappings - 1), or if we * position (from 0 to nd_region->ndr_mappings - 1), or if we
* find a dimm with two instances of the same uuid. * find a dimm with two instances of the same uuid.
*/ */
dev_err(&nd_region->dev, "%s missing label for %pUb\n",
dev_name(ndd->dev), nd_label->uuid);
rc = -EINVAL; rc = -EINVAL;
goto err; goto err;
} }
...@@ -1679,7 +1724,7 @@ struct device *create_namespace_pmem(struct nd_region *nd_region, ...@@ -1679,7 +1724,7 @@ struct device *create_namespace_pmem(struct nd_region *nd_region,
goto err; goto err;
} }
nd_namespace_pmem_set_size(nd_region, nspm, size); nd_namespace_pmem_set_resource(nd_region, nspm, size);
return dev; return dev;
err: err:
...@@ -1961,23 +2006,31 @@ static struct device **scan_labels(struct nd_region *nd_region) ...@@ -1961,23 +2006,31 @@ static struct device **scan_labels(struct nd_region *nd_region)
goto err; goto err;
dev = &nspm->nsio.common.dev; dev = &nspm->nsio.common.dev;
dev->type = &namespace_pmem_device_type; dev->type = &namespace_pmem_device_type;
nd_namespace_pmem_set_size(nd_region, nspm, 0); nd_namespace_pmem_set_resource(nd_region, nspm, 0);
} }
dev->parent = &nd_region->dev; dev->parent = &nd_region->dev;
devs[count++] = dev; devs[count++] = dev;
} else if (is_nd_pmem(&nd_region->dev)) { } else if (is_nd_pmem(&nd_region->dev)) {
/* clean unselected labels */ /* clean unselected labels */
for (i = 0; i < nd_region->ndr_mappings; i++) { for (i = 0; i < nd_region->ndr_mappings; i++) {
struct list_head *l, *e;
LIST_HEAD(list);
int j;
nd_mapping = &nd_region->mapping[i]; nd_mapping = &nd_region->mapping[i];
if (list_empty(&nd_mapping->labels)) { if (list_empty(&nd_mapping->labels)) {
WARN_ON(1); WARN_ON(1);
continue; continue;
} }
label_ent = list_first_entry(&nd_mapping->labels,
typeof(*label_ent), list); j = count;
list_del(&label_ent->list); list_for_each_safe(l, e, &nd_mapping->labels) {
if (!j--)
break;
list_move_tail(l, &list);
}
nd_mapping_free_labels(nd_mapping); nd_mapping_free_labels(nd_mapping);
list_add(&label_ent->list, &nd_mapping->labels); list_splice_init(&list, &nd_mapping->labels);
} }
} }
...@@ -2117,6 +2170,13 @@ int nd_region_register_namespaces(struct nd_region *nd_region, int *err) ...@@ -2117,6 +2170,13 @@ int nd_region_register_namespaces(struct nd_region *nd_region, int *err)
id = ida_simple_get(&nd_region->ns_ida, 0, 0, id = ida_simple_get(&nd_region->ns_ida, 0, 0,
GFP_KERNEL); GFP_KERNEL);
nsblk->id = id; nsblk->id = id;
} else if (type == ND_DEVICE_NAMESPACE_PMEM) {
struct nd_namespace_pmem *nspm;
nspm = to_nd_namespace_pmem(dev);
id = ida_simple_get(&nd_region->ns_ida, 0, 0,
GFP_KERNEL);
nspm->id = id;
} else } else
id = i; id = i;
......
...@@ -77,11 +77,13 @@ struct nd_namespace_io { ...@@ -77,11 +77,13 @@ struct nd_namespace_io {
* @nsio: device and system physical address range to drive * @nsio: device and system physical address range to drive
* @alt_name: namespace name supplied in the dimm label * @alt_name: namespace name supplied in the dimm label
* @uuid: namespace name supplied in the dimm label * @uuid: namespace name supplied in the dimm label
* @id: ida allocated id
*/ */
struct nd_namespace_pmem { struct nd_namespace_pmem {
struct nd_namespace_io nsio; struct nd_namespace_io nsio;
char *alt_name; char *alt_name;
u8 *uuid; u8 *uuid;
int id;
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment