@@ -62,6 +62,12 @@ static struct parameters {
.autorecover = true,
};
+struct ns_info {
+ void *ns_sb_buf;
+ enum ndctl_namespace_mode mode;
+ size_t offset;
+};
+
const char *cmd_name = "namespace";
void builtin_xaction_namespace_reset(void)
@@ -256,7 +262,7 @@ static int set_defaults(enum device_action action)
break;
}
} else if (action == ACTION_WRITE_INFOBLOCK) {
- param.mode = "fsdax";
+ param.mode = "unknown";
} else if (!param.reconfig && param.type) {
if (strcmp(param.type, "pmem") == 0)
param.mode = "fsdax";
@@ -1750,70 +1756,110 @@ err:
#define INFOBLOCK_SZ SZ_8K
-static int parse_namespace_infoblock(char *_buf, struct ndctl_namespace *ndns,
+static int ns_info_init(struct ns_info *ns_info)
+{
+ char *buf = NULL;
+
+ if (!ns_info)
+ return -EINVAL;
+ /*
+ * Initializing it to null so that it can be checked properly in
+ * ns_info_destroy function
+ */
+ ns_info->ns_sb_buf = NULL;
+ buf = calloc(1, INFOBLOCK_SZ);
+ if (!buf)
+ return -ENOMEM;
+ ns_info->ns_sb_buf = buf;
+ ns_info->mode = NDCTL_NS_MODE_UNKNOWN;
+ return 0;
+}
+
+static void ns_info_destroy(struct ns_info *ns_info)
+{
+ if (ns_info && ns_info->ns_sb_buf)
+ free(ns_info->ns_sb_buf);
+}
+
+static int parse_namespace_infoblock(struct ns_info *ns_info, struct ndctl_namespace *ndns,
const char *path, struct read_infoblock_ctx *ri_ctx)
{
int rc;
- void *buf = _buf;
+ void *buf = ns_info->ns_sb_buf;
unsigned long flags = param.human ? UTIL_JSON_HUMAN : 0;
struct btt_sb *btt1_sb = buf + SZ_4K, *btt2_sb = buf;
- struct json_object *jblock = NULL, *jblocks = ri_ctx->jblocks;
+ struct json_object *jblock = NULL, *jblocks = NULL;
struct pfn_sb *pfn_sb = buf + SZ_4K, *dax_sb = buf + SZ_4K;
- if (!param.json && !param.human) {
- rc = fwrite(buf, 1, INFOBLOCK_SZ, ri_ctx->f_out);
- if (rc != INFOBLOCK_SZ)
- return -EIO;
- fflush(ri_ctx->f_out);
- return 0;
- }
+ if (ri_ctx) {
+ jblocks = ri_ctx->jblocks;
+
+ if (!param.json && !param.human) {
+ rc = fwrite(buf, 1, INFOBLOCK_SZ, ri_ctx->f_out);
+ if (rc != INFOBLOCK_SZ)
+ return -EIO;
+ fflush(ri_ctx->f_out);
+ return 0;
+ }
- if (!jblocks) {
- jblocks = json_object_new_array();
- if (!jblocks)
- return -ENOMEM;
- ri_ctx->jblocks = jblocks;
+ if (!jblocks) {
+ jblocks = json_object_new_array();
+ if (!jblocks)
+ return -ENOMEM;
+ ri_ctx->jblocks = jblocks;
+ }
}
if (memcmp(btt1_sb->signature, BTT_SIG, BTT_SIG_LEN) == 0) {
- jblock = btt_parse(btt1_sb, ndns, path, flags);
- if (jblock)
- json_object_array_add(jblocks, jblock);
+ ns_info->offset = BTT1_START_OFFSET;
+ ns_info->mode = NDCTL_NS_MODE_SECTOR;
+ if (ri_ctx) {
+ jblock = btt_parse(btt1_sb, ndns, path, flags);
+ if (jblock)
+ json_object_array_add(jblocks, jblock);
+ }
}
if (memcmp(btt2_sb->signature, BTT_SIG, BTT_SIG_LEN) == 0) {
- jblock = btt_parse(btt2_sb, ndns, path, flags);
- if (jblock)
- json_object_array_add(jblocks, jblock);
+ ns_info->offset = BTT2_START_OFFSET;
+ ns_info->mode = NDCTL_NS_MODE_SECTOR;
+ if (ri_ctx) {
+ jblock = btt_parse(btt2_sb, ndns, path, flags);
+ if (jblock)
+ json_object_array_add(jblocks, jblock);
+ }
}
if (memcmp(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN) == 0) {
- jblock = pfn_parse(pfn_sb, ndns, path, flags);
- if (jblock)
- json_object_array_add(jblocks, jblock);
+ ns_info->offset = SZ_4K;
+ ns_info->mode = NDCTL_NS_MODE_FSDAX;
+ if (ri_ctx) {
+ jblock = pfn_parse(pfn_sb, ndns, path, flags);
+ if (jblock)
+ json_object_array_add(jblocks, jblock);
+ }
}
if (memcmp(dax_sb->signature, DAX_SIG, PFN_SIG_LEN) == 0) {
- jblock = pfn_parse(dax_sb, ndns, path, flags);
- if (jblock)
- json_object_array_add(jblocks, jblock);
+ ns_info->offset = SZ_4K;
+ ns_info->mode = NDCTL_NS_MODE_DEVDAX;
+ if (ri_ctx) {
+ jblock = pfn_parse(dax_sb, ndns, path, flags);
+ if (jblock)
+ json_object_array_add(jblocks, jblock);
+ }
}
return 0;
}
static int file_read_infoblock(const char *path, struct ndctl_namespace *ndns,
- struct read_infoblock_ctx *ri_ctx)
+ struct read_infoblock_ctx *ri_ctx, struct ns_info *ns_info)
{
const char *devname = ndns ? ndctl_namespace_get_devname(ndns) : "";
const char *cmd = "read-infoblock";
- void *buf = NULL;
int fd = -1, rc;
- buf = calloc(1, INFOBLOCK_SZ);
- if (!buf)
- return -ENOMEM;
-
if (!path) {
fd = STDIN_FILENO;
path = "<stdin>";
@@ -1827,7 +1873,7 @@ static int file_read_infoblock(const char *path, struct ndctl_namespace *ndns,
goto out;
}
- rc = read(fd, buf, INFOBLOCK_SZ);
+ rc = read(fd, ns_info->ns_sb_buf, INFOBLOCK_SZ);
if (rc < INFOBLOCK_SZ) {
pr_verbose("%s: %s failed to read %s: %s\n",
cmd, devname, path, strerror(errno));
@@ -1837,10 +1883,8 @@ static int file_read_infoblock(const char *path, struct ndctl_namespace *ndns,
rc = -EIO;
goto out;
}
-
- rc = parse_namespace_infoblock(buf, ndns, path, ri_ctx);
+ rc = parse_namespace_infoblock(ns_info, ndns, path, ri_ctx);
out:
- free(buf);
if (fd >= 0 && fd != STDIN_FILENO)
close(fd);
return rc;
@@ -1857,10 +1901,10 @@ static unsigned long PHYS_PFN(unsigned long long phys)
/* Derived from nd_pfn_init() in kernel version v5.5 */
static int write_pfn_sb(int fd, unsigned long long size, const char *sig,
- void *buf)
+ struct ns_info *ns_info)
{
unsigned long npfns, align, pfn_align;
- struct pfn_sb *pfn_sb = buf + SZ_4K;
+ struct pfn_sb *pfn_sb = ns_info->ns_sb_buf + SZ_4K;
unsigned long long start, offset;
uuid_t uuid, parent_uuid;
u32 end_trunc, start_pad;
@@ -1874,24 +1918,62 @@ static int write_pfn_sb(int fd, unsigned long long size, const char *sig,
align = max(pfn_align, SUBSECTION_SIZE);
if (param.uuid)
uuid_parse(param.uuid, uuid);
- else
- uuid_generate(uuid);
-
+ else {
+ switch (ns_info->mode) {
+ case NDCTL_NS_MODE_FSDAX:
+ case NDCTL_NS_MODE_DEVDAX:
+ memcpy(uuid,
+ ((struct pfn_sb *)(ns_info->ns_sb_buf + ns_info->offset))->uuid,
+ sizeof(uuid_t));
+ break;
+ case NDCTL_NS_MODE_SECTOR:
+ memcpy(uuid,
+ ((struct btt_sb *)(ns_info->ns_sb_buf + ns_info->offset))->uuid,
+ sizeof(uuid_t));
+ break;
+ default:
+ uuid_generate(uuid);
+ break;
+ }
+ }
if (param.parent_uuid)
uuid_parse(param.parent_uuid, parent_uuid);
- else
- memset(parent_uuid, 0, sizeof(uuid_t));
+ else {
+ switch (ns_info->mode) {
+ case NDCTL_NS_MODE_FSDAX:
+ case NDCTL_NS_MODE_DEVDAX:
+ memcpy(parent_uuid,
+ ((struct pfn_sb *)(ns_info->ns_sb_buf + ns_info->offset))
+ ->parent_uuid, sizeof(uuid_t));
+ break;
+ case NDCTL_NS_MODE_SECTOR:
+ memcpy(parent_uuid,
+ ((struct btt_sb *)(ns_info->ns_sb_buf + ns_info->offset))
+ ->parent_uuid, sizeof(uuid_t));
+ break;
+ default:
+ memset(parent_uuid, 0, sizeof(uuid_t));
+ break;
+ }
+ }
if (strcmp(param.map, "dev") == 0)
mode = PFN_MODE_PMEM;
else
mode = PFN_MODE_RAM;
+ /*
+ * If originally the namespace was of sector type with backup
+ * infoblock offset 0, resetting those bits.
+ */
+ memset(ns_info->ns_sb_buf, 0, SZ_4K);
+
/*
* Unlike the kernel implementation always set start_pad and
* end_trunc relative to the specified --offset= option to allow
* testing legacy / "buggy" configurations.
*/
+
start_pad = ALIGN(start, align) - start;
end_trunc = start + size - ALIGN_DOWN(start + size, align);
if (mode == PFN_MODE_PMEM) {
@@ -1933,17 +2015,16 @@ static int write_pfn_sb(int fd, unsigned long long size, const char *sig,
checksum = fletcher64(pfn_sb, sizeof(*pfn_sb), 0);
pfn_sb->checksum = cpu_to_le64(checksum);
- rc = write(fd, buf, INFOBLOCK_SZ);
+ rc = write(fd, ns_info->ns_sb_buf, INFOBLOCK_SZ);
if (rc < INFOBLOCK_SZ)
return -EIO;
return 0;
}
-static int file_write_infoblock(const char *path)
+static int file_write_infoblock(const char *path, struct ns_info *ns_info)
{
unsigned long long size = parse_size64(param.size);
int fd = -1, rc;
- void *buf;
if (param.std_out)
fd = STDOUT_FILENO;
@@ -1980,25 +2061,30 @@ static int file_write_infoblock(const char *path)
}
}
- buf = calloc(INFOBLOCK_SZ, 1);
- if (!buf) {
- rc = -ENOMEM;
- goto out;
- }
-
switch (util_nsmode(param.mode)) {
case NDCTL_NS_MODE_FSDAX:
- rc = write_pfn_sb(fd, size, PFN_SIG, buf);
+ rc = write_pfn_sb(fd, size, PFN_SIG, ns_info);
break;
case NDCTL_NS_MODE_DEVDAX:
- rc = write_pfn_sb(fd, size, DAX_SIG, buf);
+ rc = write_pfn_sb(fd, size, DAX_SIG, ns_info);
+ break;
+ case NDCTL_NS_MODE_UNKNOWN:
+ switch (ns_info->mode) {
+ case NDCTL_NS_MODE_FSDAX:
+ rc = write_pfn_sb(fd, size, PFN_SIG, ns_info);
+ break;
+ case NDCTL_NS_MODE_DEVDAX:
+ rc = write_pfn_sb(fd, size, DAX_SIG, ns_info);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
break;
default:
rc = -EINVAL;
break;
}
-
- free(buf);
out:
if (fd >= 0 && fd != STDOUT_FILENO)
close(fd);
@@ -2026,12 +2112,10 @@ static int namespace_rw_infoblock(struct ndctl_namespace *ndns,
struct read_infoblock_ctx *ri_ctx, int write)
{
int rc;
- uuid_t uuid;
- char str[40];
char path[50];
- const char *save;
const char *cmd = write ? "write-infoblock" : "read-infoblock";
const char *devname = ndctl_namespace_get_devname(ndns);
+ struct ns_info ns_info;
if (ndctl_namespace_is_active(ndns)) {
pr_verbose("%s: %s enabled, must be disabled\n", cmd, devname);
@@ -2045,21 +2129,22 @@ static int namespace_rw_infoblock(struct ndctl_namespace *ndns,
goto out;
}
- save = param.parent_uuid;
- if (!param.parent_uuid) {
- ndctl_namespace_get_uuid(ndns, uuid);
- uuid_unparse(uuid, str);
- param.parent_uuid = str;
- }
-
sprintf(path, "/dev/%s", ndctl_namespace_get_block_device(ndns));
- if (write) {
+ if (ns_info_init(&ns_info) != 0)
+ goto out;
+
+ rc = file_read_infoblock(path, ndns, ri_ctx, &ns_info);
+ if (!rc && write) {
unsigned long long align;
bool align_provided = true;
if (!param.align) {
align = ndctl_get_default_alignment(ndns);
-
+ if (ns_info.mode == NDCTL_NS_MODE_FSDAX ||
+ ns_info.mode == NDCTL_NS_MODE_DEVDAX) {
+ align = ((struct pfn_sb *)(ns_info.ns_sb_buf + ns_info.offset))->
+ align;
+ }
if (asprintf((char **)¶m.align, "%llu", align) < 0) {
rc = -EINVAL;
goto out;
@@ -2078,18 +2163,16 @@ static int namespace_rw_infoblock(struct ndctl_namespace *ndns,
rc = -EINVAL;
}
}
-
if (!rc)
- rc = file_write_infoblock(path);
+ rc = file_write_infoblock(path, &ns_info);
if (!align_provided) {
free((char *)param.align);
param.align = NULL;
}
- } else
- rc = file_read_infoblock(path, ndns, ri_ctx);
- param.parent_uuid = save;
+ }
out:
+ ns_info_destroy(&ns_info);
ndctl_namespace_set_raw_mode(ndns, 0);
ndctl_namespace_disable_invalidate(ndns);
return rc;
@@ -2121,22 +2204,33 @@ static int do_xaction_namespace(const char *namespace,
}
if (param.infile || !namespace) {
- rc = file_read_infoblock(param.infile, NULL, &ri_ctx);
- if (ri_ctx.jblocks)
- util_display_json_array(ri_ctx.f_out, ri_ctx.jblocks, 0);
- if (rc >= 0)
- (*processed)++;
+ struct ns_info ns_info;
+
+ rc = ns_info_init(&ns_info);
+ if (!rc) {
+ rc = file_read_infoblock(param.infile, NULL, &ri_ctx, &ns_info);
+ if (ri_ctx.jblocks)
+ util_display_json_array(ri_ctx.f_out, ri_ctx.jblocks, 0);
+ if (rc >= 0)
+ (*processed)++;
+ }
+ ns_info_destroy(&ns_info);
return rc;
}
}
if (action == ACTION_WRITE_INFOBLOCK && !namespace) {
+ struct ns_info ns_info;
if (!param.align)
param.align = "2M";
- rc = file_write_infoblock(param.outfile);
- if (rc >= 0)
- (*processed)++;
+ rc = ns_info_init(&ns_info);
+ if (!rc) {
+ rc = file_write_infoblock(param.outfile, &ns_info);
+ if (rc >= 0)
+ (*processed)++;
+ }
+ ns_info_destroy(&ns_info);
return rc;
}