Commit ae8219f1 authored by Dan Williams's avatar Dan Williams

libnvdimm, label: convert label tracking to a linked list

In preparation for enabling multiple namespaces per pmem region, convert
the label tracking to use a linked list.  In particular this will allow
select_pmem_id() to move labels from the unvalidated state to the
validated state.  Currently we only track one validated set per-region.
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 44c462eb
...@@ -499,6 +499,7 @@ static int __pmem_label_update(struct nd_region *nd_region, ...@@ -499,6 +499,7 @@ static int __pmem_label_update(struct nd_region *nd_region,
struct nd_namespace_label *victim_label; struct nd_namespace_label *victim_label;
struct nd_namespace_label *nd_label; struct nd_namespace_label *nd_label;
struct nd_namespace_index *nsindex; struct nd_namespace_index *nsindex;
struct nd_label_ent *label_ent;
unsigned long *free; unsigned long *free;
u32 nslot, slot; u32 nslot, slot;
size_t offset; size_t offset;
...@@ -536,8 +537,13 @@ static int __pmem_label_update(struct nd_region *nd_region, ...@@ -536,8 +537,13 @@ static int __pmem_label_update(struct nd_region *nd_region,
return rc; return rc;
/* Garbage collect the previous label */ /* Garbage collect the previous label */
victim_label = nd_mapping->labels[0]; mutex_lock(&nd_mapping->lock);
label_ent = list_first_entry_or_null(&nd_mapping->labels,
typeof(*label_ent), list);
WARN_ON(!label_ent);
victim_label = label_ent ? label_ent->label : NULL;
if (victim_label) { if (victim_label) {
label_ent->label = NULL;
slot = to_slot(ndd, victim_label); slot = to_slot(ndd, victim_label);
nd_label_free_slot(ndd, slot); nd_label_free_slot(ndd, slot);
dev_dbg(ndd->dev, "%s: free: %d\n", __func__, slot); dev_dbg(ndd->dev, "%s: free: %d\n", __func__, slot);
...@@ -546,28 +552,11 @@ static int __pmem_label_update(struct nd_region *nd_region, ...@@ -546,28 +552,11 @@ static int __pmem_label_update(struct nd_region *nd_region,
/* update index */ /* update index */
rc = nd_label_write_index(ndd, ndd->ns_next, rc = nd_label_write_index(ndd, ndd->ns_next,
nd_inc_seq(__le32_to_cpu(nsindex->seq)), 0); nd_inc_seq(__le32_to_cpu(nsindex->seq)), 0);
if (rc < 0) if (rc == 0 && label_ent)
return rc; label_ent->label = nd_label;
mutex_unlock(&nd_mapping->lock);
nd_mapping->labels[0] = nd_label;
return 0;
}
static void del_label(struct nd_mapping *nd_mapping, int l)
{
struct nd_namespace_label *next_label, *nd_label;
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
unsigned int slot;
int j;
nd_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_mapping->labels[j + 1]); j++) return rc;
nd_mapping->labels[j] = next_label;
nd_mapping->labels[j] = NULL;
} }
static bool is_old_resource(struct resource *res, struct resource **list, int n) static bool is_old_resource(struct resource *res, struct resource **list, int n)
...@@ -607,14 +596,16 @@ static int __blk_label_update(struct nd_region *nd_region, ...@@ -607,14 +596,16 @@ static int __blk_label_update(struct nd_region *nd_region,
struct nd_mapping *nd_mapping, struct nd_namespace_blk *nsblk, struct nd_mapping *nd_mapping, struct nd_namespace_blk *nsblk,
int num_labels) int num_labels)
{ {
int i, l, alloc, victims, nfree, old_num_resources, nlabel, rc = -ENXIO; int i, alloc, victims, nfree, old_num_resources, nlabel, rc = -ENXIO;
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
struct nd_namespace_label *nd_label; struct nd_namespace_label *nd_label;
struct nd_label_ent *label_ent, *e;
struct nd_namespace_index *nsindex; struct nd_namespace_index *nsindex;
unsigned long *free, *victim_map = NULL; unsigned long *free, *victim_map = NULL;
struct resource *res, **old_res_list; struct resource *res, **old_res_list;
struct nd_label_id label_id; struct nd_label_id label_id;
u8 uuid[NSLABEL_UUID_LEN]; u8 uuid[NSLABEL_UUID_LEN];
LIST_HEAD(list);
u32 nslot, slot; u32 nslot, slot;
if (!preamble_next(ndd, &nsindex, &free, &nslot)) if (!preamble_next(ndd, &nsindex, &free, &nslot))
...@@ -736,15 +727,22 @@ static int __blk_label_update(struct nd_region *nd_region, ...@@ -736,15 +727,22 @@ static int __blk_label_update(struct nd_region *nd_region,
* entries in nd_mapping->labels * entries in nd_mapping->labels
*/ */
nlabel = 0; nlabel = 0;
for_each_label(l, nd_label, nd_mapping->labels) { mutex_lock(&nd_mapping->lock);
list_for_each_entry_safe(label_ent, e, &nd_mapping->labels, list) {
nd_label = label_ent->label;
if (!nd_label)
continue;
nlabel++; nlabel++;
memcpy(uuid, nd_label->uuid, NSLABEL_UUID_LEN); memcpy(uuid, nd_label->uuid, NSLABEL_UUID_LEN);
if (memcmp(uuid, nsblk->uuid, NSLABEL_UUID_LEN) != 0) if (memcmp(uuid, nsblk->uuid, NSLABEL_UUID_LEN) != 0)
continue; continue;
nlabel--; nlabel--;
del_label(nd_mapping, l); list_move(&label_ent->list, &list);
l--; /* retry with the new label at this index */ label_ent->label = NULL;
} }
list_splice_tail_init(&list, &nd_mapping->labels);
mutex_unlock(&nd_mapping->lock);
if (nlabel + nsblk->num_resources > num_labels) { if (nlabel + nsblk->num_resources > num_labels) {
/* /*
* Bug, we can't end up with more resources than * Bug, we can't end up with more resources than
...@@ -755,6 +753,15 @@ static int __blk_label_update(struct nd_region *nd_region, ...@@ -755,6 +753,15 @@ static int __blk_label_update(struct nd_region *nd_region,
goto out; goto out;
} }
mutex_lock(&nd_mapping->lock);
label_ent = list_first_entry_or_null(&nd_mapping->labels,
typeof(*label_ent), list);
if (!label_ent) {
WARN_ON(1);
mutex_unlock(&nd_mapping->lock);
rc = -ENXIO;
goto out;
}
for_each_clear_bit_le(slot, free, nslot) { for_each_clear_bit_le(slot, free, nslot) {
nd_label = nd_label_base(ndd) + slot; nd_label = nd_label_base(ndd) + slot;
memcpy(uuid, nd_label->uuid, NSLABEL_UUID_LEN); memcpy(uuid, nd_label->uuid, NSLABEL_UUID_LEN);
...@@ -762,11 +769,19 @@ static int __blk_label_update(struct nd_region *nd_region, ...@@ -762,11 +769,19 @@ static int __blk_label_update(struct nd_region *nd_region,
continue; continue;
res = to_resource(ndd, nd_label); res = to_resource(ndd, nd_label);
res->flags &= ~DPA_RESOURCE_ADJUSTED; res->flags &= ~DPA_RESOURCE_ADJUSTED;
dev_vdbg(&nsblk->common.dev, "assign label[%d] slot: %d\n", dev_vdbg(&nsblk->common.dev, "assign label slot: %d\n", slot);
l, slot); list_for_each_entry_from(label_ent, &nd_mapping->labels, list) {
nd_mapping->labels[l++] = nd_label; if (label_ent->label)
continue;
label_ent->label = nd_label;
nd_label = NULL;
break;
} }
nd_mapping->labels[l] = NULL; if (nd_label)
dev_WARN(&nsblk->common.dev,
"failed to track label slot%d\n", slot);
}
mutex_unlock(&nd_mapping->lock);
out: out:
kfree(old_res_list); kfree(old_res_list);
...@@ -788,32 +803,28 @@ static int __blk_label_update(struct nd_region *nd_region, ...@@ -788,32 +803,28 @@ static int __blk_label_update(struct nd_region *nd_region,
static int init_labels(struct nd_mapping *nd_mapping, int num_labels) static int init_labels(struct nd_mapping *nd_mapping, int num_labels)
{ {
int i, l, old_num_labels = 0; int i, old_num_labels = 0;
struct nd_label_ent *label_ent;
struct nd_namespace_index *nsindex; struct nd_namespace_index *nsindex;
struct nd_namespace_label *nd_label;
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
size_t size = (num_labels + 1) * sizeof(struct nd_namespace_label *);
for_each_label(l, nd_label, nd_mapping->labels) mutex_lock(&nd_mapping->lock);
list_for_each_entry(label_ent, &nd_mapping->labels, list)
old_num_labels++; old_num_labels++;
mutex_unlock(&nd_mapping->lock);
/* /*
* We need to preserve all the old labels for the mapping so * We need to preserve all the old labels for the mapping so
* they can be garbage collected after writing the new labels. * they can be garbage collected after writing the new labels.
*/ */
if (num_labels > old_num_labels) { for (i = old_num_labels; i < num_labels; i++) {
struct nd_namespace_label **labels; label_ent = kzalloc(sizeof(*label_ent), GFP_KERNEL);
if (!label_ent)
labels = krealloc(nd_mapping->labels, size, GFP_KERNEL);
if (!labels)
return -ENOMEM; return -ENOMEM;
nd_mapping->labels = labels; mutex_lock(&nd_mapping->lock);
list_add_tail(&label_ent->list, &nd_mapping->labels);
mutex_unlock(&nd_mapping->lock);
} }
if (!nd_mapping->labels)
return -ENOMEM;
for (i = old_num_labels; i <= num_labels; i++)
nd_mapping->labels[i] = NULL;
if (ndd->ns_current == -1 || ndd->ns_next == -1) if (ndd->ns_current == -1 || ndd->ns_next == -1)
/* pass */; /* pass */;
...@@ -837,42 +848,45 @@ static int init_labels(struct nd_mapping *nd_mapping, int num_labels) ...@@ -837,42 +848,45 @@ static int init_labels(struct nd_mapping *nd_mapping, int num_labels)
static int del_labels(struct nd_mapping *nd_mapping, u8 *uuid) static int del_labels(struct nd_mapping *nd_mapping, u8 *uuid)
{ {
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
struct nd_namespace_label *nd_label; struct nd_label_ent *label_ent, *e;
struct nd_namespace_index *nsindex; struct nd_namespace_index *nsindex;
u8 label_uuid[NSLABEL_UUID_LEN]; u8 label_uuid[NSLABEL_UUID_LEN];
int l, num_freed = 0;
unsigned long *free; unsigned long *free;
LIST_HEAD(list);
u32 nslot, slot; u32 nslot, slot;
int active = 0;
if (!uuid) if (!uuid)
return 0; return 0;
/* no index || no labels == nothing to delete */ /* no index || no labels == nothing to delete */
if (!preamble_next(ndd, &nsindex, &free, &nslot) if (!preamble_next(ndd, &nsindex, &free, &nslot))
|| !nd_mapping->labels)
return 0; return 0;
for_each_label(l, nd_label, nd_mapping->labels) { mutex_lock(&nd_mapping->lock);
list_for_each_entry_safe(label_ent, e, &nd_mapping->labels, list) {
struct nd_namespace_label *nd_label = label_ent->label;
if (!nd_label)
continue;
active++;
memcpy(label_uuid, nd_label->uuid, NSLABEL_UUID_LEN); memcpy(label_uuid, nd_label->uuid, NSLABEL_UUID_LEN);
if (memcmp(label_uuid, uuid, NSLABEL_UUID_LEN) != 0) if (memcmp(label_uuid, uuid, NSLABEL_UUID_LEN) != 0)
continue; continue;
active--;
slot = to_slot(ndd, nd_label); slot = to_slot(ndd, nd_label);
nd_label_free_slot(ndd, slot); nd_label_free_slot(ndd, slot);
dev_dbg(ndd->dev, "%s: free: %d\n", __func__, slot); dev_dbg(ndd->dev, "%s: free: %d\n", __func__, slot);
del_label(nd_mapping, l); list_move_tail(&label_ent->list, &list);
num_freed++; label_ent->label = NULL;
l--; /* retry with new label at this index */
} }
list_splice_tail_init(&list, &nd_mapping->labels);
if (num_freed > l) { if (active == 0) {
/* nd_mapping_free_labels(nd_mapping);
* num_freed will only ever be > l when we delete the last dev_dbg(ndd->dev, "%s: no more active labels\n", __func__);
* label
*/
kfree(nd_mapping->labels);
nd_mapping->labels = NULL;
dev_dbg(ndd->dev, "%s: no more labels\n", __func__);
} }
mutex_unlock(&nd_mapping->lock);
return nd_label_write_index(ndd, ndd->ns_next, return nd_label_write_index(ndd, ndd->ns_next,
nd_inc_seq(__le32_to_cpu(nsindex->seq)), 0); nd_inc_seq(__le32_to_cpu(nsindex->seq)), 0);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pmem.h> #include <linux/pmem.h>
#include <linux/list.h>
#include <linux/nd.h> #include <linux/nd.h>
#include "nd-core.h" #include "nd-core.h"
#include "nd.h" #include "nd.h"
...@@ -1089,7 +1090,7 @@ static int namespace_update_uuid(struct nd_region *nd_region, ...@@ -1089,7 +1090,7 @@ static int namespace_update_uuid(struct nd_region *nd_region,
* *
* FIXME: can we delete uuid with zero dpa allocated? * FIXME: can we delete uuid with zero dpa allocated?
*/ */
if (nd_mapping->labels) if (list_empty(&nd_mapping->labels))
return -EBUSY; return -EBUSY;
} }
...@@ -1491,14 +1492,19 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid, ...@@ -1491,14 +1492,19 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid,
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 nd_namespace_label *nd_label; struct nd_label_ent *label_ent;
bool found_uuid = false; bool found_uuid = false;
int l;
for_each_label(l, nd_label, nd_mapping->labels) { list_for_each_entry(label_ent, &nd_mapping->labels, list) {
u64 isetcookie = __le64_to_cpu(nd_label->isetcookie); struct nd_namespace_label *nd_label = label_ent->label;
u16 position = __le16_to_cpu(nd_label->position); u16 position, nlabel;
u16 nlabel = __le16_to_cpu(nd_label->nlabel); u64 isetcookie;
if (!nd_label)
continue;
isetcookie = __le64_to_cpu(nd_label->isetcookie);
position = __le16_to_cpu(nd_label->position);
nlabel = __le16_to_cpu(nd_label->nlabel);
if (isetcookie != cookie) if (isetcookie != cookie)
continue; continue;
...@@ -1528,7 +1534,6 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid, ...@@ -1528,7 +1534,6 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid,
static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id)
{ {
struct nd_namespace_label *select = NULL;
int i; int i;
if (!pmem_id) if (!pmem_id)
...@@ -1536,35 +1541,47 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) ...@@ -1536,35 +1541,47 @@ 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 nd_namespace_label *nd_label; 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;
int l; struct nd_label_ent *label_ent;
for_each_label(l, nd_label, nd_mapping->labels) mutex_lock(&nd_mapping->lock);
list_for_each_entry(label_ent, &nd_mapping->labels, list) {
nd_label = label_ent->label;
if (!nd_label)
continue;
if (memcmp(nd_label->uuid, pmem_id, NSLABEL_UUID_LEN) == 0) if (memcmp(nd_label->uuid, pmem_id, NSLABEL_UUID_LEN) == 0)
break; break;
nd_label = NULL;
}
mutex_unlock(&nd_mapping->lock);
if (!nd_label) { if (!nd_label) {
WARN_ON(1); WARN_ON(1);
return -EINVAL; return -EINVAL;
} }
select = nd_label;
/* /*
* Check that this label is compliant with the dpa * Check that this label is compliant with the dpa
* range published in NFIT * range published in NFIT
*/ */
hw_start = nd_mapping->start; hw_start = nd_mapping->start;
hw_end = hw_start + nd_mapping->size; hw_end = hw_start + nd_mapping->size;
pmem_start = __le64_to_cpu(select->dpa); pmem_start = __le64_to_cpu(nd_label->dpa);
pmem_end = pmem_start + __le64_to_cpu(select->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_end <= hw_end)
/* pass */; /* pass */;
else else
return -EINVAL; return -EINVAL;
nd_mapping->labels[0] = select; mutex_lock(&nd_mapping->lock);
nd_mapping->labels[1] = NULL; label_ent = list_first_entry(&nd_mapping->labels,
typeof(*label_ent), list);
label_ent->label = nd_label;
list_del(&label_ent->list);
nd_mapping_free_labels(nd_mapping);
list_add(&label_ent->list, &nd_mapping->labels);
mutex_unlock(&nd_mapping->lock);
} }
return 0; return 0;
} }
...@@ -1577,11 +1594,12 @@ static int find_pmem_label_set(struct nd_region *nd_region, ...@@ -1577,11 +1594,12 @@ static int find_pmem_label_set(struct nd_region *nd_region,
struct nd_namespace_pmem *nspm) struct nd_namespace_pmem *nspm)
{ {
u64 cookie = nd_region_interleave_set_cookie(nd_region); u64 cookie = nd_region_interleave_set_cookie(nd_region);
struct nd_namespace_label *nd_label;
u8 select_id[NSLABEL_UUID_LEN]; u8 select_id[NSLABEL_UUID_LEN];
struct nd_label_ent *label_ent;
struct nd_mapping *nd_mapping;
resource_size_t size = 0; resource_size_t size = 0;
u8 *pmem_id = NULL; u8 *pmem_id = NULL;
int rc = -ENODEV, l; int rc = 0;
u16 i; u16 i;
if (cookie == 0) { if (cookie == 0) {
...@@ -1593,13 +1611,19 @@ static int find_pmem_label_set(struct nd_region *nd_region, ...@@ -1593,13 +1611,19 @@ static int find_pmem_label_set(struct nd_region *nd_region,
* Find a complete set of labels by uuid. By definition we can start * Find a complete set of labels by uuid. By definition we can start
* with any mapping as the reference label * with any mapping as the reference label
*/ */
for_each_label(l, nd_label, nd_region->mapping[0].labels) { for (i = 0; i < nd_region->ndr_mappings; i++) {
u64 isetcookie = __le64_to_cpu(nd_label->isetcookie); nd_mapping = &nd_region->mapping[i];
mutex_lock_nested(&nd_mapping->lock, i);
}
list_for_each_entry(label_ent, &nd_region->mapping[0].labels, list) {
struct nd_namespace_label *nd_label = label_ent->label;
if (isetcookie != cookie) if (!nd_label)
continue;
if (__le64_to_cpu(nd_label->isetcookie) != cookie)
continue; continue;
for (i = 0; nd_region->ndr_mappings; i++) for (i = 0; i < nd_region->ndr_mappings; i++)
if (!has_uuid_at_pos(nd_region, nd_label->uuid, if (!has_uuid_at_pos(nd_region, nd_label->uuid,
cookie, i)) cookie, i))
break; break;
...@@ -1611,18 +1635,27 @@ static int find_pmem_label_set(struct nd_region *nd_region, ...@@ -1611,18 +1635,27 @@ static int find_pmem_label_set(struct nd_region *nd_region,
* dimm with two instances of the same uuid. * dimm with two instances of the same uuid.
*/ */
rc = -EINVAL; rc = -EINVAL;
goto err; break;
} else if (pmem_id) { } else if (pmem_id) {
/* /*
* If there is more than one valid uuid set, we * If there is more than one valid uuid set, we
* need userspace to clean this up. * need userspace to clean this up.
*/ */
rc = -EBUSY; rc = -EBUSY;
goto err; break;
} }
memcpy(select_id, nd_label->uuid, NSLABEL_UUID_LEN); memcpy(select_id, nd_label->uuid, NSLABEL_UUID_LEN);
pmem_id = select_id; pmem_id = select_id;
} }
for (i = 0; i < nd_region->ndr_mappings; i++) {
int reverse = nd_region->ndr_mappings - 1 - i;
nd_mapping = &nd_region->mapping[reverse];
mutex_unlock(&nd_mapping->lock);
}
if (rc)
goto err;
/* /*
* Fix up each mapping's 'labels' to have the validated pmem label for * Fix up each mapping's 'labels' to have the validated pmem label for
...@@ -1638,8 +1671,19 @@ static int find_pmem_label_set(struct nd_region *nd_region, ...@@ -1638,8 +1671,19 @@ static int find_pmem_label_set(struct nd_region *nd_region,
/* Calculate total size and populate namespace properties from label0 */ /* Calculate total size and populate namespace properties from label0 */
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_namespace_label *label0;
struct nd_namespace_label *label0 = nd_mapping->labels[0];
nd_mapping = &nd_region->mapping[i];
mutex_lock(&nd_mapping->lock);
label_ent = list_first_entry_or_null(&nd_mapping->labels,
typeof(*label_ent), list);
label0 = label_ent ? label_ent->label : 0;
mutex_unlock(&nd_mapping->lock);
if (!label0) {
WARN_ON(1);
continue;
}
size += __le64_to_cpu(label0->rawsize); size += __le64_to_cpu(label0->rawsize);
if (__le16_to_cpu(label0->position) != 0) if (__le16_to_cpu(label0->position) != 0)
...@@ -1700,8 +1744,9 @@ static struct device **create_namespace_pmem(struct nd_region *nd_region) ...@@ -1700,8 +1744,9 @@ static struct device **create_namespace_pmem(struct nd_region *nd_region)
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];
kfree(nd_mapping->labels); mutex_lock(&nd_mapping->lock);
nd_mapping->labels = NULL; nd_mapping_free_labels(nd_mapping);
mutex_unlock(&nd_mapping->lock);
} }
/* Publish a zero-sized namespace for userspace to configure. */ /* Publish a zero-sized namespace for userspace to configure. */
...@@ -1822,25 +1867,25 @@ void nd_region_create_btt_seed(struct nd_region *nd_region) ...@@ -1822,25 +1867,25 @@ void nd_region_create_btt_seed(struct nd_region *nd_region)
dev_err(&nd_region->dev, "failed to create btt namespace\n"); dev_err(&nd_region->dev, "failed to create btt namespace\n");
} }
static struct device **create_namespace_blk(struct nd_region *nd_region) static struct device **scan_labels(struct nd_region *nd_region,
struct nd_mapping *nd_mapping)
{ {
struct nd_mapping *nd_mapping = &nd_region->mapping[0]; struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
struct nd_namespace_label *nd_label;
struct device *dev, **devs = NULL; struct device *dev, **devs = NULL;
struct nd_namespace_blk *nsblk; struct nd_namespace_blk *nsblk;
struct nvdimm_drvdata *ndd; struct nd_label_ent *label_ent;
int i, l, count = 0; int i, count = 0;
struct resource *res;
if (nd_region->ndr_mappings == 0) list_for_each_entry(label_ent, &nd_mapping->labels, list) {
return NULL; struct nd_namespace_label *nd_label = label_ent->label;
ndd = to_ndd(nd_mapping);
for_each_label(l, nd_label, nd_mapping->labels) {
u32 flags = __le32_to_cpu(nd_label->flags);
char *name[NSLABEL_NAME_LEN]; char *name[NSLABEL_NAME_LEN];
struct device **__devs; struct device **__devs;
struct resource *res;
u32 flags;
if (!nd_label)
continue;
flags = __le32_to_cpu(nd_label->flags);
if (flags & NSLABEL_FLAG_LOCAL) if (flags & NSLABEL_FLAG_LOCAL)
/* pass */; /* pass */;
else else
...@@ -1899,12 +1944,7 @@ static struct device **create_namespace_blk(struct nd_region *nd_region) ...@@ -1899,12 +1944,7 @@ static struct device **create_namespace_blk(struct nd_region *nd_region)
if (count == 0) { if (count == 0) {
/* Publish a zero-sized namespace for userspace to configure. */ /* Publish a zero-sized namespace for userspace to configure. */
for (i = 0; i < nd_region->ndr_mappings; i++) { nd_mapping_free_labels(nd_mapping);
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
kfree(nd_mapping->labels);
nd_mapping->labels = NULL;
}
devs = kcalloc(2, sizeof(dev), GFP_KERNEL); devs = kcalloc(2, sizeof(dev), GFP_KERNEL);
if (!devs) if (!devs)
...@@ -1920,8 +1960,8 @@ static struct device **create_namespace_blk(struct nd_region *nd_region) ...@@ -1920,8 +1960,8 @@ static struct device **create_namespace_blk(struct nd_region *nd_region)
return devs; return devs;
err: err:
for (i = 0; i < count; i++) { for (i = 0; devs[i]; i++) {
nsblk = to_nd_namespace_blk(devs[i]); nsblk = to_nd_namespace_blk(devs[i]);
namespace_blk_release(&nsblk->common.dev); namespace_blk_release(&nsblk->common.dev);
} }
...@@ -1929,6 +1969,21 @@ static struct device **create_namespace_blk(struct nd_region *nd_region) ...@@ -1929,6 +1969,21 @@ static struct device **create_namespace_blk(struct nd_region *nd_region)
return NULL; return NULL;
} }
static struct device **create_namespace_blk(struct nd_region *nd_region)
{
struct nd_mapping *nd_mapping = &nd_region->mapping[0];
struct device **devs;
if (nd_region->ndr_mappings == 0)
return NULL;
mutex_lock(&nd_mapping->lock);
devs = scan_labels(nd_region, nd_mapping);
mutex_unlock(&nd_mapping->lock);
return devs;
}
static int init_active_labels(struct nd_region *nd_region) static int init_active_labels(struct nd_region *nd_region)
{ {
int i; int i;
...@@ -1937,6 +1992,7 @@ static int init_active_labels(struct nd_region *nd_region) ...@@ -1937,6 +1992,7 @@ static int init_active_labels(struct nd_region *nd_region)
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 nvdimm_drvdata *ndd = to_ndd(nd_mapping);
struct nvdimm *nvdimm = nd_mapping->nvdimm; struct nvdimm *nvdimm = nd_mapping->nvdimm;
struct nd_label_ent *label_ent;
int count, j; int count, j;
/* /*
...@@ -1958,16 +2014,27 @@ static int init_active_labels(struct nd_region *nd_region) ...@@ -1958,16 +2014,27 @@ static int init_active_labels(struct nd_region *nd_region)
dev_dbg(ndd->dev, "%s: %d\n", __func__, count); dev_dbg(ndd->dev, "%s: %d\n", __func__, count);
if (!count) if (!count)
continue; continue;
nd_mapping->labels = kcalloc(count + 1, sizeof(void *),
GFP_KERNEL);
if (!nd_mapping->labels)
return -ENOMEM;
for (j = 0; j < count; j++) { for (j = 0; j < count; j++) {
struct nd_namespace_label *label; struct nd_namespace_label *label;
label_ent = kzalloc(sizeof(*label_ent), GFP_KERNEL);
if (!label_ent)
break;
label = nd_label_active(ndd, j); label = nd_label_active(ndd, j);
nd_mapping->labels[j] = label; label_ent->label = label;
mutex_lock(&nd_mapping->lock);
list_add_tail(&label_ent->list, &nd_mapping->labels);
mutex_unlock(&nd_mapping->lock);
} }
if (j >= count)
continue;
mutex_lock(&nd_mapping->lock);
nd_mapping_free_labels(nd_mapping);
mutex_unlock(&nd_mapping->lock);
return -ENOMEM;
} }
return 0; return 0;
......
...@@ -73,6 +73,7 @@ bool nd_is_uuid_unique(struct device *dev, u8 *uuid); ...@@ -73,6 +73,7 @@ bool nd_is_uuid_unique(struct device *dev, u8 *uuid);
struct nd_region; struct nd_region;
struct nvdimm_drvdata; struct nvdimm_drvdata;
struct nd_mapping; struct nd_mapping;
void nd_mapping_free_labels(struct nd_mapping *nd_mapping);
resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region, resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region,
struct nd_mapping *nd_mapping, resource_size_t *overlap); struct nd_mapping *nd_mapping, resource_size_t *overlap);
resource_size_t nd_blk_available_dpa(struct nd_mapping *nd_mapping); resource_size_t nd_blk_available_dpa(struct nd_mapping *nd_mapping);
......
...@@ -83,9 +83,6 @@ static inline struct nd_namespace_index *to_next_namespace_index( ...@@ -83,9 +83,6 @@ static inline struct nd_namespace_index *to_next_namespace_index(
(unsigned long long) (res ? resource_size(res) : 0), \ (unsigned long long) (res ? resource_size(res) : 0), \
(unsigned long long) (res ? res->start : 0), ##arg) (unsigned long long) (res ? res->start : 0), ##arg)
#define for_each_label(l, label, labels) \
for (l = 0; (label = labels ? labels[l] : NULL); l++)
#define for_each_dpa_resource(ndd, res) \ #define for_each_dpa_resource(ndd, res) \
for (res = (ndd)->dpa.child; res; res = res->sibling) for (res = (ndd)->dpa.child; res; res = res->sibling)
...@@ -98,11 +95,22 @@ struct nd_percpu_lane { ...@@ -98,11 +95,22 @@ struct nd_percpu_lane {
spinlock_t lock; spinlock_t lock;
}; };
struct nd_label_ent {
struct list_head list;
struct nd_namespace_label *label;
};
enum nd_mapping_lock_class {
ND_MAPPING_CLASS0,
ND_MAPPING_UUID_SCAN,
};
struct nd_mapping { struct nd_mapping {
struct nvdimm *nvdimm; struct nvdimm *nvdimm;
struct nd_namespace_label **labels;
u64 start; u64 start;
u64 size; u64 size;
struct list_head labels;
struct mutex lock;
/* /*
* @ndd is for private use at region enable / disable time for * @ndd is for private use at region enable / disable time for
* get_ndd() + put_ndd(), all other nd_mapping to ndd * get_ndd() + put_ndd(), all other nd_mapping to ndd
......
...@@ -487,6 +487,17 @@ u64 nd_region_interleave_set_cookie(struct nd_region *nd_region) ...@@ -487,6 +487,17 @@ u64 nd_region_interleave_set_cookie(struct nd_region *nd_region)
return 0; return 0;
} }
void nd_mapping_free_labels(struct nd_mapping *nd_mapping)
{
struct nd_label_ent *label_ent, *e;
WARN_ON(!mutex_is_locked(&nd_mapping->lock));
list_for_each_entry_safe(label_ent, e, &nd_mapping->labels, list) {
list_del(&label_ent->list);
kfree(label_ent);
}
}
/* /*
* Upon successful probe/remove, take/release a reference on the * Upon successful probe/remove, take/release a reference on the
* associated interleave set (if present), and plant new btt + namespace * associated interleave set (if present), and plant new btt + namespace
...@@ -507,8 +518,10 @@ static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus, ...@@ -507,8 +518,10 @@ static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus,
struct nvdimm_drvdata *ndd = nd_mapping->ndd; struct nvdimm_drvdata *ndd = nd_mapping->ndd;
struct nvdimm *nvdimm = nd_mapping->nvdimm; struct nvdimm *nvdimm = nd_mapping->nvdimm;
kfree(nd_mapping->labels); mutex_lock(&nd_mapping->lock);
nd_mapping->labels = NULL; nd_mapping_free_labels(nd_mapping);
mutex_unlock(&nd_mapping->lock);
put_ndd(ndd); put_ndd(ndd);
nd_mapping->ndd = NULL; nd_mapping->ndd = NULL;
if (ndd) if (ndd)
...@@ -816,6 +829,8 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, ...@@ -816,6 +829,8 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
nd_region->mapping[i].nvdimm = nvdimm; nd_region->mapping[i].nvdimm = nvdimm;
nd_region->mapping[i].start = mapping->start; nd_region->mapping[i].start = mapping->start;
nd_region->mapping[i].size = mapping->size; nd_region->mapping[i].size = mapping->size;
INIT_LIST_HEAD(&nd_region->mapping[i].labels);
mutex_init(&nd_region->mapping[i].lock);
get_device(&nvdimm->dev); get_device(&nvdimm->dev);
} }
......
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