Skip to content

Commit

Permalink
libnvdimm, label: add v1.2 nvdimm label definitions
Browse files Browse the repository at this point in the history
In support of improved interoperability between operating systems and pre-boot
environments the Intel proposed NVDIMM Namespace Specification [1], has been
adopted and modified to the the UEFI 2.7 NVDIMM Label Protocol [2].

Update the definitions of the namespace label data structures so that the new
format can be supported alongside the existing label format.

The new specification changes the default label size to 256 bytes, so
everywhere that relied on sizeof(struct nd_namespace_label) must now use the
sizeof_namespace_label() helper.

There should be no functional differences from these changes as the
default is still the v1.1 128-byte format. Future patches will move the
default to the v1.2 definition.

[1]: http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf
[2]: http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf

Signed-off-by: Dan Williams <[email protected]>
  • Loading branch information
djbw committed Jun 15, 2017
1 parent 87085ff commit 564e871
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 21 deletions.
95 changes: 77 additions & 18 deletions drivers/nvdimm/label.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ static u32 best_seq(u32 a, u32 b)
return a;
}

unsigned sizeof_namespace_label(struct nvdimm_drvdata *ndd)
{
return ndd->nslabel_size;
}

size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd)
{
u32 index_span;
Expand All @@ -49,7 +54,7 @@ size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd)
* starts to waste space at larger config_sizes, but it's
* unlikely we'll ever see anything but 128K.
*/
index_span = ndd->nsarea.config_size / 129;
index_span = ndd->nsarea.config_size / (sizeof_namespace_label(ndd) + 1);
index_span /= NSINDEX_ALIGN * 2;
ndd->nsindex_size = index_span * NSINDEX_ALIGN;

Expand All @@ -58,10 +63,10 @@ size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd)

int nvdimm_num_label_slots(struct nvdimm_drvdata *ndd)
{
return ndd->nsarea.config_size / 129;
return ndd->nsarea.config_size / (sizeof_namespace_label(ndd) + 1);
}

int nd_label_validate(struct nvdimm_drvdata *ndd)
static int __nd_label_validate(struct nvdimm_drvdata *ndd)
{
/*
* On media label format consists of two index blocks followed
Expand Down Expand Up @@ -104,13 +109,29 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
u32 nslot;
u8 sig[NSINDEX_SIG_LEN];
u64 sum_save, sum, size;
unsigned int version, labelsize;

memcpy(sig, nsindex[i]->sig, NSINDEX_SIG_LEN);
if (memcmp(sig, NSINDEX_SIGNATURE, NSINDEX_SIG_LEN) != 0) {
dev_dbg(dev, "%s: nsindex%d signature invalid\n",
__func__, i);
continue;
}

/* label sizes larger than 128 arrived with v1.2 */
version = __le16_to_cpu(nsindex[i]->major) * 100
+ __le16_to_cpu(nsindex[i]->minor);
if (version >= 102)
labelsize = 1 << (7 + nsindex[i]->labelsize);
else
labelsize = 128;

if (labelsize != sizeof_namespace_label(ndd)) {
dev_dbg(dev, "%s: nsindex%d labelsize %d invalid\n",
__func__, i, nsindex[i]->labelsize);
continue;
}

sum_save = __le64_to_cpu(nsindex[i]->checksum);
nsindex[i]->checksum = __cpu_to_le64(0);
sum = nd_fletcher64(nsindex[i], sizeof_namespace_index(ndd), 1);
Expand Down Expand Up @@ -153,7 +174,7 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
}

nslot = __le32_to_cpu(nsindex[i]->nslot);
if (nslot * sizeof(struct nd_namespace_label)
if (nslot * sizeof_namespace_label(ndd)
+ 2 * sizeof_namespace_index(ndd)
> ndd->nsarea.config_size) {
dev_dbg(dev, "%s: nsindex%d nslot: %u invalid, config_size: %#x\n",
Expand Down Expand Up @@ -189,6 +210,28 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
return -1;
}

int nd_label_validate(struct nvdimm_drvdata *ndd)
{
/*
* In order to probe for and validate namespace index blocks we
* need to know the size of the labels, and we can't trust the
* size of the labels until we validate the index blocks.
* Resolve this dependency loop by probing for known label
* sizes.
*/
int label_size[] = { 256, 128 };
int i, rc;

for (i = 0; i < ARRAY_SIZE(label_size); i++) {
ndd->nslabel_size = label_size[i];
rc = __nd_label_validate(ndd);
if (rc >= 0)
return rc;
}

return -1;
}

void nd_label_copy(struct nvdimm_drvdata *ndd, struct nd_namespace_index *dst,
struct nd_namespace_index *src)
{
Expand All @@ -210,7 +253,22 @@ static struct nd_namespace_label *nd_label_base(struct nvdimm_drvdata *ndd)
static int to_slot(struct nvdimm_drvdata *ndd,
struct nd_namespace_label *nd_label)
{
return nd_label - nd_label_base(ndd);
unsigned long label, base;

label = (unsigned long) nd_label;
base = (unsigned long) nd_label_base(ndd);

return (label - base) / sizeof_namespace_label(ndd);
}

static struct nd_namespace_label *to_label(struct nvdimm_drvdata *ndd, int slot)
{
unsigned long label, base;

base = (unsigned long) nd_label_base(ndd);
label = base + sizeof_namespace_label(ndd) * slot;

return (struct nd_namespace_label *) label;
}

#define for_each_clear_bit_le(bit, addr, size) \
Expand Down Expand Up @@ -299,7 +357,7 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd)
struct resource *res;
u32 flags;

nd_label = nd_label_base(ndd) + slot;
nd_label = to_label(ndd, slot);

if (!slot_valid(nd_label, slot))
continue;
Expand Down Expand Up @@ -331,7 +389,7 @@ int nd_label_active_count(struct nvdimm_drvdata *ndd)
for_each_clear_bit_le(slot, free, nslot) {
struct nd_namespace_label *nd_label;

nd_label = nd_label_base(ndd) + slot;
nd_label = to_label(ndd, slot);

if (!slot_valid(nd_label, slot)) {
u32 label_slot = __le32_to_cpu(nd_label->slot);
Expand Down Expand Up @@ -360,12 +418,12 @@ struct nd_namespace_label *nd_label_active(struct nvdimm_drvdata *ndd, int n)
for_each_clear_bit_le(slot, free, nslot) {
struct nd_namespace_label *nd_label;

nd_label = nd_label_base(ndd) + slot;
nd_label = to_label(ndd, slot);
if (!slot_valid(nd_label, slot))
continue;

if (n-- == 0)
return nd_label_base(ndd) + slot;
return to_label(ndd, slot);
}

return NULL;
Expand Down Expand Up @@ -437,7 +495,8 @@ static int nd_label_write_index(struct nvdimm_drvdata *ndd, int index, u32 seq,
nslot = __le32_to_cpu(nsindex->nslot);

memcpy(nsindex->sig, NSINDEX_SIGNATURE, NSINDEX_SIG_LEN);
nsindex->flags = __cpu_to_le32(0);
memset(&nsindex->flags, 0, 3);
nsindex->labelsize = sizeof_namespace_label(ndd) >> 8;
nsindex->seq = __cpu_to_le32(seq);
offset = (unsigned long) nsindex
- (unsigned long) to_namespace_index(ndd, 0);
Expand Down Expand Up @@ -525,8 +584,8 @@ static int __pmem_label_update(struct nd_region *nd_region,
return -ENXIO;
dev_dbg(ndd->dev, "%s: allocated: %d\n", __func__, slot);

nd_label = nd_label_base(ndd) + slot;
memset(nd_label, 0, sizeof(struct nd_namespace_label));
nd_label = to_label(ndd, slot);
memset(nd_label, 0, sizeof_namespace_label(ndd));
memcpy(nd_label->uuid, nspm->uuid, NSLABEL_UUID_LEN);
if (nspm->alt_name)
memcpy(nd_label->name, nspm->alt_name, NSLABEL_NAME_LEN);
Expand All @@ -542,7 +601,7 @@ static int __pmem_label_update(struct nd_region *nd_region,
/* update label */
offset = nd_label_offset(ndd, nd_label);
rc = nvdimm_set_config_data(ndd, offset, nd_label,
sizeof(struct nd_namespace_label));
sizeof_namespace_label(ndd));
if (rc < 0)
return rc;

Expand Down Expand Up @@ -668,7 +727,7 @@ static int __blk_label_update(struct nd_region *nd_region,

/* mark unused labels for garbage collection */
for_each_clear_bit_le(slot, free, nslot) {
nd_label = nd_label_base(ndd) + slot;
nd_label = to_label(ndd, slot);
memcpy(uuid, nd_label->uuid, NSLABEL_UUID_LEN);
if (memcmp(uuid, nsblk->uuid, NSLABEL_UUID_LEN) != 0)
continue;
Expand Down Expand Up @@ -714,8 +773,8 @@ static int __blk_label_update(struct nd_region *nd_region,
goto abort;
dev_dbg(ndd->dev, "%s: allocated: %d\n", __func__, slot);

nd_label = nd_label_base(ndd) + slot;
memset(nd_label, 0, sizeof(struct nd_namespace_label));
nd_label = to_label(ndd, slot);
memset(nd_label, 0, sizeof_namespace_label(ndd));
memcpy(nd_label->uuid, nsblk->uuid, NSLABEL_UUID_LEN);
if (nsblk->alt_name)
memcpy(nd_label->name, nsblk->alt_name,
Expand All @@ -732,7 +791,7 @@ static int __blk_label_update(struct nd_region *nd_region,
/* update label */
offset = nd_label_offset(ndd, nd_label);
rc = nvdimm_set_config_data(ndd, offset, nd_label,
sizeof(struct nd_namespace_label));
sizeof_namespace_label(ndd));
if (rc < 0)
goto abort;
}
Expand Down Expand Up @@ -790,7 +849,7 @@ static int __blk_label_update(struct nd_region *nd_region,
goto out;
}
for_each_clear_bit_le(slot, free, nslot) {
nd_label = nd_label_base(ndd) + slot;
nd_label = to_label(ndd, slot);
memcpy(uuid, nd_label->uuid, NSLABEL_UUID_LEN);
if (memcmp(uuid, nsblk->uuid, NSLABEL_UUID_LEN) != 0)
continue;
Expand Down
15 changes: 13 additions & 2 deletions drivers/nvdimm/label.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include <linux/ndctl.h>
#include <linux/sizes.h>
#include <linux/uuid.h>
#include <linux/io.h>

enum {
Expand Down Expand Up @@ -60,7 +61,8 @@ static const char NSINDEX_SIGNATURE[] = "NAMESPACE_INDEX\0";
*/
struct nd_namespace_index {
u8 sig[NSINDEX_SIG_LEN];
__le32 flags;
u8 flags[3];
u8 labelsize;
__le32 seq;
__le64 myoff;
__le64 mysize;
Expand Down Expand Up @@ -98,7 +100,16 @@ struct nd_namespace_label {
__le64 dpa;
__le64 rawsize;
__le32 slot;
__le32 unused;
/*
* Accessing fields past this point should be gated by a
* namespace_label_has() check.
*/
u8 align;
u8 reserved[3];
guid_t type_guid;
guid_t abstraction_guid;
u8 reserved2[88];
__le64 checksum;
};

/**
Expand Down
8 changes: 7 additions & 1 deletion drivers/nvdimm/nd.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct nd_poison {

struct nvdimm_drvdata {
struct device *dev;
int nsindex_size;
int nsindex_size, nslabel_size;
struct nd_cmd_get_config_size nsarea;
void *data;
int ns_current, ns_next;
Expand Down Expand Up @@ -96,6 +96,12 @@ static inline struct nd_namespace_index *to_next_namespace_index(
return to_namespace_index(ndd, ndd->ns_next);
}

unsigned sizeof_namespace_label(struct nvdimm_drvdata *ndd);

#define namespace_label_has(ndd, field) \
(offsetof(struct nd_namespace_label, field) \
< sizeof_namespace_label(ndd))

#define nd_dbg_dpa(r, d, res, fmt, arg...) \
dev_dbg((r) ? &(r)->dev : (d)->dev, "%s: %.13s: %#llx @ %#llx " fmt, \
(r) ? dev_name((d)->dev) : "", res ? res->name : "null", \
Expand Down

0 comments on commit 564e871

Please sign in to comment.