Skip to content

Commit

Permalink
libnvdimm, label: convert label tracking to a linked list
Browse files Browse the repository at this point in the history
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: Dan Williams <dan.j.williams@intel.com>
  • Loading branch information
Dan Williams committed Oct 1, 2016
1 parent 44c462e commit ae8219f
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 120 deletions.
136 changes: 75 additions & 61 deletions drivers/nvdimm/label.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ static int __pmem_label_update(struct nd_region *nd_region,
struct nd_namespace_label *victim_label;
struct nd_namespace_label *nd_label;
struct nd_namespace_index *nsindex;
struct nd_label_ent *label_ent;
unsigned long *free;
u32 nslot, slot;
size_t offset;
Expand Down Expand Up @@ -536,8 +537,13 @@ static int __pmem_label_update(struct nd_region *nd_region,
return rc;

/* 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) {
label_ent->label = NULL;
slot = to_slot(ndd, victim_label);
nd_label_free_slot(ndd, slot);
dev_dbg(ndd->dev, "%s: free: %d\n", __func__, slot);
Expand All @@ -546,28 +552,11 @@ static int __pmem_label_update(struct nd_region *nd_region,
/* update index */
rc = nd_label_write_index(ndd, ndd->ns_next,
nd_inc_seq(__le32_to_cpu(nsindex->seq)), 0);
if (rc < 0)
return rc;

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;
if (rc == 0 && label_ent)
label_ent->label = nd_label;
mutex_unlock(&nd_mapping->lock);

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++)
nd_mapping->labels[j] = next_label;
nd_mapping->labels[j] = NULL;
return rc;
}

static bool is_old_resource(struct resource *res, struct resource **list, int n)
Expand Down Expand Up @@ -607,14 +596,16 @@ static int __blk_label_update(struct nd_region *nd_region,
struct nd_mapping *nd_mapping, struct nd_namespace_blk *nsblk,
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 nd_namespace_label *nd_label;
struct nd_label_ent *label_ent, *e;
struct nd_namespace_index *nsindex;
unsigned long *free, *victim_map = NULL;
struct resource *res, **old_res_list;
struct nd_label_id label_id;
u8 uuid[NSLABEL_UUID_LEN];
LIST_HEAD(list);
u32 nslot, slot;

if (!preamble_next(ndd, &nsindex, &free, &nslot))
Expand Down Expand Up @@ -736,15 +727,22 @@ static int __blk_label_update(struct nd_region *nd_region,
* entries in nd_mapping->labels
*/
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++;
memcpy(uuid, nd_label->uuid, NSLABEL_UUID_LEN);
if (memcmp(uuid, nsblk->uuid, NSLABEL_UUID_LEN) != 0)
continue;
nlabel--;
del_label(nd_mapping, l);
l--; /* retry with the new label at this index */
list_move(&label_ent->list, &list);
label_ent->label = NULL;
}
list_splice_tail_init(&list, &nd_mapping->labels);
mutex_unlock(&nd_mapping->lock);

if (nlabel + nsblk->num_resources > num_labels) {
/*
* Bug, we can't end up with more resources than
Expand All @@ -755,18 +753,35 @@ static int __blk_label_update(struct nd_region *nd_region,
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) {
nd_label = nd_label_base(ndd) + slot;
memcpy(uuid, nd_label->uuid, NSLABEL_UUID_LEN);
if (memcmp(uuid, nsblk->uuid, NSLABEL_UUID_LEN) != 0)
continue;
res = to_resource(ndd, nd_label);
res->flags &= ~DPA_RESOURCE_ADJUSTED;
dev_vdbg(&nsblk->common.dev, "assign label[%d] slot: %d\n",
l, slot);
nd_mapping->labels[l++] = nd_label;
dev_vdbg(&nsblk->common.dev, "assign label slot: %d\n", slot);
list_for_each_entry_from(label_ent, &nd_mapping->labels, list) {
if (label_ent->label)
continue;
label_ent->label = nd_label;
nd_label = NULL;
break;
}
if (nd_label)
dev_WARN(&nsblk->common.dev,
"failed to track label slot%d\n", slot);
}
nd_mapping->labels[l] = NULL;
mutex_unlock(&nd_mapping->lock);

out:
kfree(old_res_list);
Expand All @@ -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)
{
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_label *nd_label;
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++;
mutex_unlock(&nd_mapping->lock);

/*
* We need to preserve all the old labels for the mapping so
* they can be garbage collected after writing the new labels.
*/
if (num_labels > old_num_labels) {
struct nd_namespace_label **labels;

labels = krealloc(nd_mapping->labels, size, GFP_KERNEL);
if (!labels)
for (i = old_num_labels; i < num_labels; i++) {
label_ent = kzalloc(sizeof(*label_ent), GFP_KERNEL);
if (!label_ent)
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)
/* pass */;
Expand All @@ -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)
{
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;
u8 label_uuid[NSLABEL_UUID_LEN];
int l, num_freed = 0;
unsigned long *free;
LIST_HEAD(list);
u32 nslot, slot;
int active = 0;

if (!uuid)
return 0;

/* no index || no labels == nothing to delete */
if (!preamble_next(ndd, &nsindex, &free, &nslot)
|| !nd_mapping->labels)
if (!preamble_next(ndd, &nsindex, &free, &nslot))
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);
if (memcmp(label_uuid, uuid, NSLABEL_UUID_LEN) != 0)
continue;
active--;
slot = to_slot(ndd, nd_label);
nd_label_free_slot(ndd, slot);
dev_dbg(ndd->dev, "%s: free: %d\n", __func__, slot);
del_label(nd_mapping, l);
num_freed++;
l--; /* retry with new label at this index */
list_move_tail(&label_ent->list, &list);
label_ent->label = NULL;
}
list_splice_tail_init(&list, &nd_mapping->labels);

if (num_freed > l) {
/*
* num_freed will only ever be > l when we delete the last
* label
*/
kfree(nd_mapping->labels);
nd_mapping->labels = NULL;
dev_dbg(ndd->dev, "%s: no more labels\n", __func__);
if (active == 0) {
nd_mapping_free_labels(nd_mapping);
dev_dbg(ndd->dev, "%s: no more active labels\n", __func__);
}
mutex_unlock(&nd_mapping->lock);

return nd_label_write_index(ndd, ndd->ns_next,
nd_inc_seq(__le32_to_cpu(nsindex->seq)), 0);
Expand Down
Loading

0 comments on commit ae8219f

Please sign in to comment.