Skip to content

Commit 0e3b0d1

Browse files
committed
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: Dan Williams <[email protected]>
1 parent bd4cd74 commit 0e3b0d1

File tree

2 files changed

+74
-12
lines changed

2 files changed

+74
-12
lines changed

drivers/nvdimm/namespace_devs.c

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ static void namespace_io_release(struct device *dev)
2929
static void namespace_pmem_release(struct device *dev)
3030
{
3131
struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev);
32+
struct nd_region *nd_region = to_nd_region(dev->parent);
3233

34+
if (nspm->id >= 0)
35+
ida_simple_remove(&nd_region->ns_ida, nspm->id);
3336
kfree(nspm->alt_name);
3437
kfree(nspm->uuid);
3538
kfree(nspm);
@@ -833,13 +836,45 @@ static int grow_dpa_allocation(struct nd_region *nd_region,
833836
return 0;
834837
}
835838

836-
static void nd_namespace_pmem_set_size(struct nd_region *nd_region,
839+
static void nd_namespace_pmem_set_resource(struct nd_region *nd_region,
837840
struct nd_namespace_pmem *nspm, resource_size_t size)
838841
{
839842
struct resource *res = &nspm->nsio.res;
843+
resource_size_t offset = 0;
840844

841-
res->start = nd_region->ndr_start;
842-
res->end = nd_region->ndr_start + size - 1;
845+
if (size && !nspm->uuid) {
846+
WARN_ON_ONCE(1);
847+
size = 0;
848+
}
849+
850+
if (size && nspm->uuid) {
851+
struct nd_mapping *nd_mapping = &nd_region->mapping[0];
852+
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
853+
struct nd_label_id label_id;
854+
struct resource *res;
855+
856+
if (!ndd) {
857+
size = 0;
858+
goto out;
859+
}
860+
861+
nd_label_gen_id(&label_id, nspm->uuid, 0);
862+
863+
/* calculate a spa offset from the dpa allocation offset */
864+
for_each_dpa_resource(ndd, res)
865+
if (strcmp(res->name, label_id.id) == 0) {
866+
offset = (res->start - nd_mapping->start)
867+
* nd_region->ndr_mappings;
868+
goto out;
869+
}
870+
871+
WARN_ON_ONCE(1);
872+
size = 0;
873+
}
874+
875+
out:
876+
res->start = nd_region->ndr_start + offset;
877+
res->end = res->start + size - 1;
843878
}
844879

845880
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)
930965
if (is_namespace_pmem(dev)) {
931966
struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev);
932967

933-
nd_namespace_pmem_set_size(nd_region, nspm,
968+
nd_namespace_pmem_set_resource(nd_region, nspm,
934969
val * nd_region->ndr_mappings);
935970
} else if (is_namespace_blk(dev)) {
936971
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)
15461581

15471582
for (i = 0; i < nd_region->ndr_mappings; i++) {
15481583
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
1584+
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
15491585
struct nd_namespace_label *nd_label = NULL;
15501586
u64 hw_start, hw_end, pmem_start, pmem_end;
15511587
struct nd_label_ent *label_ent;
@@ -1573,10 +1609,14 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id)
15731609
hw_end = hw_start + nd_mapping->size;
15741610
pmem_start = __le64_to_cpu(nd_label->dpa);
15751611
pmem_end = pmem_start + __le64_to_cpu(nd_label->rawsize);
1576-
if (pmem_start == hw_start && pmem_end <= hw_end)
1612+
if (pmem_start >= hw_start && pmem_start < hw_end
1613+
&& pmem_end <= hw_end && pmem_end > hw_start)
15771614
/* pass */;
1578-
else
1615+
else {
1616+
dev_dbg(&nd_region->dev, "%s invalid label for %pUb\n",
1617+
dev_name(ndd->dev), nd_label->uuid);
15791618
return -EINVAL;
1619+
}
15801620

15811621
/* move recently validated label to the front of the list */
15821622
list_move(&label_ent->list, &nd_mapping->labels);
@@ -1618,6 +1658,7 @@ struct device *create_namespace_pmem(struct nd_region *nd_region,
16181658
if (!nspm)
16191659
return ERR_PTR(-ENOMEM);
16201660

1661+
nspm->id = -1;
16211662
dev = &nspm->nsio.common.dev;
16221663
dev->type = &namespace_pmem_device_type;
16231664
dev->parent = &nd_region->dev;
@@ -1629,11 +1670,15 @@ struct device *create_namespace_pmem(struct nd_region *nd_region,
16291670
if (!has_uuid_at_pos(nd_region, nd_label->uuid, cookie, i))
16301671
break;
16311672
if (i < nd_region->ndr_mappings) {
1673+
struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]);
1674+
16321675
/*
16331676
* Give up if we don't find an instance of a uuid at each
16341677
* position (from 0 to nd_region->ndr_mappings - 1), or if we
16351678
* find a dimm with two instances of the same uuid.
16361679
*/
1680+
dev_err(&nd_region->dev, "%s missing label for %pUb\n",
1681+
dev_name(ndd->dev), nd_label->uuid);
16371682
rc = -EINVAL;
16381683
goto err;
16391684
}
@@ -1679,7 +1724,7 @@ struct device *create_namespace_pmem(struct nd_region *nd_region,
16791724
goto err;
16801725
}
16811726

1682-
nd_namespace_pmem_set_size(nd_region, nspm, size);
1727+
nd_namespace_pmem_set_resource(nd_region, nspm, size);
16831728

16841729
return dev;
16851730
err:
@@ -1961,23 +2006,31 @@ static struct device **scan_labels(struct nd_region *nd_region)
19612006
goto err;
19622007
dev = &nspm->nsio.common.dev;
19632008
dev->type = &namespace_pmem_device_type;
1964-
nd_namespace_pmem_set_size(nd_region, nspm, 0);
2009+
nd_namespace_pmem_set_resource(nd_region, nspm, 0);
19652010
}
19662011
dev->parent = &nd_region->dev;
19672012
devs[count++] = dev;
19682013
} else if (is_nd_pmem(&nd_region->dev)) {
19692014
/* clean unselected labels */
19702015
for (i = 0; i < nd_region->ndr_mappings; i++) {
2016+
struct list_head *l, *e;
2017+
LIST_HEAD(list);
2018+
int j;
2019+
19712020
nd_mapping = &nd_region->mapping[i];
19722021
if (list_empty(&nd_mapping->labels)) {
19732022
WARN_ON(1);
19742023
continue;
19752024
}
1976-
label_ent = list_first_entry(&nd_mapping->labels,
1977-
typeof(*label_ent), list);
1978-
list_del(&label_ent->list);
2025+
2026+
j = count;
2027+
list_for_each_safe(l, e, &nd_mapping->labels) {
2028+
if (!j--)
2029+
break;
2030+
list_move_tail(l, &list);
2031+
}
19792032
nd_mapping_free_labels(nd_mapping);
1980-
list_add(&label_ent->list, &nd_mapping->labels);
2033+
list_splice_init(&list, &nd_mapping->labels);
19812034
}
19822035
}
19832036

@@ -2117,6 +2170,13 @@ int nd_region_register_namespaces(struct nd_region *nd_region, int *err)
21172170
id = ida_simple_get(&nd_region->ns_ida, 0, 0,
21182171
GFP_KERNEL);
21192172
nsblk->id = id;
2173+
} else if (type == ND_DEVICE_NAMESPACE_PMEM) {
2174+
struct nd_namespace_pmem *nspm;
2175+
2176+
nspm = to_nd_namespace_pmem(dev);
2177+
id = ida_simple_get(&nd_region->ns_ida, 0, 0,
2178+
GFP_KERNEL);
2179+
nspm->id = id;
21202180
} else
21212181
id = i;
21222182

include/linux/nd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,13 @@ struct nd_namespace_io {
7777
* @nsio: device and system physical address range to drive
7878
* @alt_name: namespace name supplied in the dimm label
7979
* @uuid: namespace name supplied in the dimm label
80+
* @id: ida allocated id
8081
*/
8182
struct nd_namespace_pmem {
8283
struct nd_namespace_io nsio;
8384
char *alt_name;
8485
u8 *uuid;
86+
int id;
8587
};
8688

8789
/**

0 commit comments

Comments
 (0)