Commit 6ec68954 authored by Vishal Verma's avatar Vishal Verma Committed by Dan Williams

libnvdimm, btt: write and validate parent_uuid

When a BTT is instantiated on a namespace it must validate the namespace
uuid matches the 'parent_uuid' stored in the btt superblock. This
property enforces that changing the namespace UUID invalidates all
former BTT instances on that storage. For "IO namespaces" that don't
have a label or UUID, the parent_uuid is set to zero, and this
validation is skipped. For such cases, old BTTs have to be invalidated
by forcing the namespace to raw mode, and overwriting the BTT info
blocks.

Based on a patch by Dan Williams <dan.j.williams@intel.com>
Signed-off-by: default avatarVishal Verma <vishal.l.verma@intel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent ab45e763
...@@ -733,6 +733,7 @@ static int btt_arena_write_layout(struct arena_info *arena) ...@@ -733,6 +733,7 @@ static int btt_arena_write_layout(struct arena_info *arena)
int ret; int ret;
struct btt_sb *super; struct btt_sb *super;
struct nd_btt *nd_btt = arena->nd_btt; struct nd_btt *nd_btt = arena->nd_btt;
const u8 *parent_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev);
ret = btt_map_init(arena); ret = btt_map_init(arena);
if (ret) if (ret)
...@@ -748,6 +749,7 @@ static int btt_arena_write_layout(struct arena_info *arena) ...@@ -748,6 +749,7 @@ static int btt_arena_write_layout(struct arena_info *arena)
strncpy(super->signature, BTT_SIG, BTT_SIG_LEN); strncpy(super->signature, BTT_SIG, BTT_SIG_LEN);
memcpy(super->uuid, nd_btt->uuid, 16); memcpy(super->uuid, nd_btt->uuid, 16);
memcpy(super->parent_uuid, parent_uuid, 16);
super->flags = cpu_to_le32(arena->flags); super->flags = cpu_to_le32(arena->flags);
super->version_major = cpu_to_le16(arena->version_major); super->version_major = cpu_to_le16(arena->version_major);
super->version_minor = cpu_to_le16(arena->version_minor); super->version_minor = cpu_to_le16(arena->version_minor);
......
...@@ -342,24 +342,37 @@ struct device *nd_btt_create(struct nd_region *nd_region) ...@@ -342,24 +342,37 @@ struct device *nd_btt_create(struct nd_region *nd_region)
return dev; return dev;
} }
static bool uuid_is_null(u8 *uuid)
{
static const u8 null_uuid[16];
return (memcmp(uuid, null_uuid, 16) == 0);
}
/** /**
* nd_btt_arena_is_valid - check if the metadata layout is valid * nd_btt_arena_is_valid - check if the metadata layout is valid
* @nd_btt: device with BTT geometry and backing device info * @nd_btt: device with BTT geometry and backing device info
* @super: pointer to the arena's info block being tested * @super: pointer to the arena's info block being tested
* *
* Check consistency of the btt info block with itself by validating * Check consistency of the btt info block with itself by validating
* the checksum. * the checksum, and with the parent namespace by verifying the
* parent_uuid contained in the info block with the one supplied in.
* *
* Returns: * Returns:
* false for an invalid info block, true for a valid one * false for an invalid info block, true for a valid one
*/ */
bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super) bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super)
{ {
const u8 *parent_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev);
u64 checksum; u64 checksum;
if (memcmp(super->signature, BTT_SIG, BTT_SIG_LEN) != 0) if (memcmp(super->signature, BTT_SIG, BTT_SIG_LEN) != 0)
return false; return false;
if (!uuid_is_null(super->parent_uuid))
if (memcmp(super->parent_uuid, parent_uuid, 16) != 0)
return false;
checksum = le64_to_cpu(super->checksum); checksum = le64_to_cpu(super->checksum);
super->checksum = 0; super->checksum = 0;
if (checksum != nd_btt_sb_checksum(super)) if (checksum != nd_btt_sb_checksum(super))
......
...@@ -100,6 +100,26 @@ const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns, ...@@ -100,6 +100,26 @@ const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns,
} }
EXPORT_SYMBOL(nvdimm_namespace_disk_name); EXPORT_SYMBOL(nvdimm_namespace_disk_name);
const u8 *nd_dev_to_uuid(struct device *dev)
{
static const u8 null_uuid[16];
if (!dev)
return null_uuid;
if (is_namespace_pmem(dev)) {
struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev);
return nspm->uuid;
} else if (is_namespace_blk(dev)) {
struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev);
return nsblk->uuid;
} else
return null_uuid;
}
EXPORT_SYMBOL(nd_dev_to_uuid);
static ssize_t nstype_show(struct device *dev, static ssize_t nstype_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
......
...@@ -217,4 +217,5 @@ static inline bool nd_iostat_start(struct bio *bio, unsigned long *start) ...@@ -217,4 +217,5 @@ static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
} }
void nd_iostat_end(struct bio *bio, unsigned long start); void nd_iostat_end(struct bio *bio, unsigned long start);
resource_size_t nd_namespace_blk_validate(struct nd_namespace_blk *nsblk); resource_size_t nd_namespace_blk_validate(struct nd_namespace_blk *nsblk);
const u8 *nd_dev_to_uuid(struct device *dev);
#endif /* __ND_H__ */ #endif /* __ND_H__ */
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