@@ -77,16 +77,31 @@ struct namespace_label {
le64 checksum;
};
-size_t sizeof_namespace_label(struct ndctl_cmd *cmd_read)
+struct nvdimm_data {
+ struct ndctl_dimm *dimm;
+ struct ndctl_cmd *cmd_read;
+ unsigned long config_size;
+ size_t nslabel_size;
+ struct log_ctx ctx;
+ void *data;
+ int nsindex_size;
+ int ns_current, ns_next;
+};
+
+static size_t sizeof_namespace_label(struct nvdimm_data *ndd)
{
struct namespace_index nsindex;
int v1 = 0, v2 = 0;
ssize_t offset;
+ if (ndd->nslabel_size)
+ return ndd->nslabel_size;
+
for (offset = 0; offset < NSINDEX_ALIGN * 2; offset += NSINDEX_ALIGN) {
ssize_t len = (ssize_t) sizeof(nsindex);
- len = ndctl_cmd_cfg_read_get_data(cmd_read, &nsindex, len, offset);
+ len = ndctl_cmd_cfg_read_get_data(ndd->cmd_read, &nsindex,
+ len, offset);
if (len < 0)
break;
@@ -104,18 +119,21 @@ size_t sizeof_namespace_label(struct ndctl_cmd *cmd_read)
}
if (v2 > v1)
- return sizeof(struct namespace_label);
- return 128;
+ ndd->nslabel_size = 256;
+ else
+ ndd->nslabel_size = 128;
+ return ndd->nslabel_size;
}
-#define namespace_label_has(cmd_read, field) \
+#define namespace_label_has(ndd, field) \
(offsetof(struct namespace_label, field) \
- < sizeof_namespace_label(cmd_read))
+ < sizeof_namespace_label(ndd))
static const char NSINDEX_SIGNATURE[] = "NAMESPACE_INDEX\0";
struct action_context {
struct json_object *jdimms;
+ int labelversion;
FILE *f_out;
FILE *f_in;
};
@@ -143,7 +161,10 @@ static int action_zero(struct ndctl_dimm *dimm, struct action_context *actx)
static struct json_object *dump_label_json(struct ndctl_cmd *cmd_read, ssize_t size)
{
- size_t namespace_label_size = sizeof_namespace_label(cmd_read);
+ struct nvdimm_data __ndd = {
+ .nslabel_size = 0,
+ .cmd_read = cmd_read
+ }, *ndd = &__ndd;
struct json_object *jarray = json_object_new_array();
struct json_object *jlabel = NULL;
struct namespace_label nslabel;
@@ -153,8 +174,10 @@ static struct json_object *dump_label_json(struct ndctl_cmd *cmd_read, ssize_t s
if (!jarray)
return NULL;
- for (offset = NSINDEX_ALIGN * 2; offset < size; offset += sizeof(nslabel)) {
- ssize_t len = min_t(ssize_t, namespace_label_size, size - offset);
+ for (offset = NSINDEX_ALIGN * 2; offset < size;
+ offset += sizeof_namespace_label(ndd)) {
+ ssize_t len = min_t(ssize_t, sizeof_namespace_label(ndd),
+ size - offset);
struct json_object *jobj;
char uuid[40];
@@ -163,7 +186,7 @@ static struct json_object *dump_label_json(struct ndctl_cmd *cmd_read, ssize_t s
if (!jlabel)
break;
- if (len < (ssize_t) sizeof(nslabel))
+ if (len < (ssize_t) sizeof_namespace_label(ndd))
break;
len = ndctl_cmd_cfg_read_get_data(cmd_read, &nslabel, len, offset);
@@ -222,7 +245,7 @@ static struct json_object *dump_label_json(struct ndctl_cmd *cmd_read, ssize_t s
json_object_array_add(jarray, jlabel);
- if (namespace_label_size < 256)
+ if (sizeof_namespace_label(ndd) < 256)
continue;
uuid_unparse((void *) nslabel.type_guid, uuid);
@@ -486,16 +509,6 @@ static int action_read(struct ndctl_dimm *dimm, struct action_context *actx)
return rc;
}
-struct nvdimm_data {
- struct ndctl_dimm *dimm;
- struct ndctl_cmd *cmd_read;
- unsigned long config_size;
- struct log_ctx ctx;
- void *data;
- int nsindex_size;
- int ns_current, ns_next;
-};
-
/*
* Note, best_seq(), inc_seq(), sizeof_namespace_index()
* nvdimm_num_label_slots(), label_validate(), and label_write_index()
@@ -508,6 +521,7 @@ struct nvdimm_data {
* 5/ s,__cpu_to,cpu_to,gc
* 6/ remove flags argument to label_write_index
* 7/ dropped clear_bit_le() usage in label_write_index
+ * 8/ s,nvdimm_drvdata,nvdimm_data,gc
*/
static unsigned inc_seq(unsigned seq)
@@ -532,7 +546,7 @@ static u32 best_seq(u32 a, u32 b)
return a;
}
-static size_t sizeof_namespace_index(struct nvdimm_data *ndd)
+size_t sizeof_namespace_index(struct nvdimm_data *ndd)
{
u32 index_span;
@@ -547,16 +561,16 @@ static size_t sizeof_namespace_index(struct nvdimm_data *ndd)
* starts to waste space at larger config_sizes, but it's
* unlikely we'll ever see anything but 128K.
*/
- index_span = ndd->config_size / 129;
+ index_span = ndd->config_size / (sizeof_namespace_label(ndd) + 1);
index_span /= NSINDEX_ALIGN * 2;
ndd->nsindex_size = index_span * NSINDEX_ALIGN;
return ndd->nsindex_size;
}
-static int nvdimm_num_label_slots(struct nvdimm_data *ndd)
+int nvdimm_num_label_slots(struct nvdimm_data *ndd)
{
- return ndd->config_size / 129;
+ return ndd->config_size / (sizeof_namespace_label(ndd) + 1);
}
static struct namespace_index *to_namespace_index(struct nvdimm_data *ndd,
@@ -571,7 +585,7 @@ static struct namespace_index *to_namespace_index(struct nvdimm_data *ndd,
return (struct namespace_index *) index;
}
-static int label_validate(struct nvdimm_data *ndd)
+static int __label_validate(struct nvdimm_data *ndd)
{
/*
* On media label format consists of two index blocks followed
@@ -613,12 +627,28 @@ static int label_validate(struct nvdimm_data *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) {
dbg(ndd, "nsindex%d signature invalid\n", 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)) {
+ dbg(ndd, "nsindex%d labelsize %d invalid\n",
+ i, nsindex[i]->labelsize);
+ continue;
+ }
+
sum_save = le64_to_cpu(nsindex[i]->checksum);
nsindex[i]->checksum = cpu_to_le64(0);
sum = fletcher64(nsindex[i], sizeof_namespace_index(ndd), 1);
@@ -658,7 +688,7 @@ static int label_validate(struct nvdimm_data *ndd)
}
nslot = le32_to_cpu(nsindex[i]->nslot);
- if (nslot * sizeof(struct namespace_label)
+ if (nslot * sizeof_namespace_label(ndd)
+ 2 * sizeof_namespace_index(ndd)
> ndd->config_size) {
dbg(ndd, "nsindex%d nslot: %u invalid, config_size: %#zx\n",
@@ -693,6 +723,29 @@ static int label_validate(struct nvdimm_data *ndd)
return -1;
}
+int label_validate(struct nvdimm_data *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, but default to v1.2 256-byte namespace labels if
+ * discovery fails.
+ */
+ int label_size[] = { 128, 256 };
+ int i, rc;
+
+ for (i = 0; (size_t) i < ARRAY_SIZE(label_size); i++) {
+ ndd->nslabel_size = label_size[i];
+ rc = __label_validate(ndd);
+ if (rc >= 0)
+ return rc;
+ }
+
+ return -1;
+}
+
static int nvdimm_set_config_data(struct nvdimm_data *ndd, size_t offset,
void *buf, size_t len)
{
@@ -742,6 +795,7 @@ static int label_write_index(struct nvdimm_data *ndd, int index, u32 seq)
memcpy(nsindex->sig, NSINDEX_SIGNATURE, NSINDEX_SIG_LEN);
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);
@@ -756,7 +810,10 @@ static int label_write_index(struct nvdimm_data *ndd, int index, u32 seq)
nsindex->labeloff = cpu_to_le64(offset);
nsindex->nslot = cpu_to_le32(nslot);
nsindex->major = cpu_to_le16(1);
- nsindex->minor = cpu_to_le16(1);
+ if (sizeof_namespace_label(ndd) < 256)
+ nsindex->minor = cpu_to_le16(1);
+ else
+ nsindex->minor = cpu_to_le16(2);
nsindex->checksum = cpu_to_le64(0);
/* init label bitmap */
memset(nsindex->free, 0xff, ALIGN(nslot, BITS_PER_LONG) / 8);
@@ -770,14 +827,17 @@ static struct parameters {
const char *bus;
const char *outfile;
const char *infile;
+ const char *labelversion;
bool force;
bool json;
bool verbose;
-} param;
+} param = {
+ .labelversion = "1.1",
+};
-static int __action_init(struct ndctl_dimm *dimm, int chk_only)
+static int __action_init(struct ndctl_dimm *dimm, int version, int chk_only)
{
- struct nvdimm_data __ndd, *ndd = &__ndd;
+ struct nvdimm_data __ndd = { 0 }, *ndd = &__ndd;
struct ndctl_cmd *cmd_read;
int rc = 0, i;
ssize_t size;
@@ -830,6 +890,16 @@ static int __action_init(struct ndctl_dimm *dimm, int chk_only)
goto out;
}
+ /*
+ * We may have initialized ndd to whatever labelsize is
+ * currently on the dimm during label_validate(), so we reset it
+ * to the desired version here.
+ */
+ if (version > 1)
+ ndd->nslabel_size = 256;
+ else
+ ndd->nslabel_size = 128;
+
for (i = 0; i < 2; i++) {
rc = label_write_index(ndd, i, i*2);
if (rc)
@@ -856,12 +926,12 @@ static int __action_init(struct ndctl_dimm *dimm, int chk_only)
static int action_init(struct ndctl_dimm *dimm, struct action_context *actx)
{
- return __action_init(dimm, 0);
+ return __action_init(dimm, actx->labelversion, 0);
}
static int action_check(struct ndctl_dimm *dimm, struct action_context *actx)
{
- return __action_init(dimm, 1);
+ return __action_init(dimm, 0, 1);
}
@@ -881,7 +951,9 @@ OPT_STRING('i', "input", ¶m.infile, "input-file", \
#define INIT_OPTIONS() \
OPT_BOOLEAN('f', "force", ¶m.force, \
- "force initialization even if existing index-block present")
+ "force initialization even if existing index-block present"), \
+OPT_STRING('V', "--label-version", ¶m.labelversion, "version-number", \
+ "namespace label specification version (default: 1.1)")
static const struct option read_options[] = {
BASE_OPTIONS(),
@@ -975,6 +1047,21 @@ static int dimm_action(int argc, const char **argv, void *ctx,
if (param.verbose)
ndctl_set_log_priority(ctx, LOG_DEBUG);
+ if (strcmp(param.labelversion, "1.1") == 0)
+ actx.labelversion = 1;
+ else if (strcmp(param.labelversion, "v1.1") == 0)
+ actx.labelversion = 1;
+ else if (strcmp(param.labelversion, "1.2") == 0)
+ actx.labelversion = 2;
+ else if (strcmp(param.labelversion, "v1.2") == 0)
+ actx.labelversion = 2;
+ else {
+ fprintf(stderr, "'%s' is not a valid label version\n",
+ param.labelversion);
+ rc = -EINVAL;
+ goto out;
+ }
+
rc = 0;
err = 0;
count = 0;
With the kernel change in 4.13 to start using v1.2 labels by default, some environments may choose to keep deploying v1.1. The --label-version option explicitly initializes the index block to the desired version. It defaults to "1.1" since that has the widest compatibility. Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- ndctl/dimm.c | 155 +++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 121 insertions(+), 34 deletions(-)