summaryrefslogtreecommitdiffstats
path: root/libblkid/src/superblocks/stratis.c
diff options
context:
space:
mode:
Diffstat (limited to 'libblkid/src/superblocks/stratis.c')
-rw-r--r--libblkid/src/superblocks/stratis.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/libblkid/src/superblocks/stratis.c b/libblkid/src/superblocks/stratis.c
new file mode 100644
index 0000000..fe4a452
--- /dev/null
+++ b/libblkid/src/superblocks/stratis.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 Tony Asleson <tasleson@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/*
+ * Specification for on disk format
+ * https://stratis-storage.github.io/StratisSoftwareDesign.pdf
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include "superblocks.h"
+#include "crc32c.h"
+
+/* Macro to avoid error in struct declaration. */
+#define STRATIS_UUID_LEN 32
+/* Contains 4 hyphens and trailing null byte. */
+const int STRATIS_UUID_STR_LEN = 37;
+
+struct stratis_sb {
+ uint32_t crc32;
+ uint8_t magic[16];
+ uint64_t sectors;
+ uint8_t reserved[4];
+ uint8_t pool_uuid[STRATIS_UUID_LEN];
+ uint8_t dev_uuid[STRATIS_UUID_LEN];
+ uint64_t mda_size;
+ uint64_t reserved_size;
+ uint64_t flags;
+ uint64_t initialization_time;
+} __attribute__ ((__packed__));
+
+#define BS 512
+#define FIRST_COPY_OFFSET BS
+#define SECOND_COPY_OFFSET (BS * 9)
+#define SB_AREA_SIZE (BS * 16)
+
+const char STRATIS_MAGIC[] = "!Stra0tis\x86\xff\x02^\x41rh";
+#define MAGIC_LEN (sizeof(STRATIS_MAGIC) - 1)
+
+#define _MAGIC_OFFSET (offsetof(const struct stratis_sb, magic))
+#define MAGIC_OFFSET_COPY_1 (FIRST_COPY_OFFSET + _MAGIC_OFFSET)
+#define MAGIC_OFFSET_COPY_2 (SECOND_COPY_OFFSET + _MAGIC_OFFSET)
+
+static int stratis_valid_sb(uint8_t *p)
+{
+ const struct stratis_sb *stratis = (const struct stratis_sb *)p;
+ uint32_t crc = 0;
+
+ /* generate CRC from byte position 4 for length 508 == 512 byte sector */
+ crc = crc32c(~0L, p + sizeof(stratis->crc32),
+ BS - sizeof(stratis->crc32));
+ crc ^= ~0L;
+
+ return crc == le32_to_cpu(stratis->crc32);
+}
+
+/*
+ * Format UUID string representation to include hyphens given that Stratis stores
+ * UUIDs without hyphens in the superblock to keep the UUID length a power of 2.
+ */
+static void stratis_format_uuid(const unsigned char *src_uuid,
+ unsigned char *dst_uuid)
+{
+ int i;
+
+ for (i = 0; i < STRATIS_UUID_LEN; i++) {
+ *dst_uuid++ = *src_uuid++;
+ if (i == 7 || i == 11 || i == 15 || i == 19)
+ *dst_uuid ++ = '-';
+ }
+ *dst_uuid = '\0';
+}
+
+static int probe_stratis(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ const struct stratis_sb *stratis = NULL;
+ uint8_t *buf = blkid_probe_get_buffer(pr, 0, SB_AREA_SIZE);
+ unsigned char uuid[STRATIS_UUID_STR_LEN];
+
+ if (!buf)
+ return errno ? -errno : 1;
+
+ if (stratis_valid_sb(buf + FIRST_COPY_OFFSET)) {
+ stratis = (const struct stratis_sb *)(buf + FIRST_COPY_OFFSET);
+ } else {
+ if (!stratis_valid_sb(buf + SECOND_COPY_OFFSET))
+ return 1;
+
+ stratis = (const struct stratis_sb *)
+ (buf + SECOND_COPY_OFFSET);
+ }
+
+ stratis_format_uuid(stratis->dev_uuid, uuid);
+ blkid_probe_strncpy_uuid(pr, uuid, sizeof(uuid));
+
+ stratis_format_uuid(stratis->pool_uuid, uuid);
+ blkid_probe_set_value(pr, "POOL_UUID", uuid, sizeof(uuid));
+
+ blkid_probe_sprintf_value(pr, "BLOCKDEV_SECTORS", "%" PRIu64,
+ le64_to_cpu(stratis->sectors));
+ blkid_probe_sprintf_value(pr, "BLOCKDEV_INITTIME", "%" PRIu64,
+ le64_to_cpu(stratis->initialization_time));
+ return 0;
+}
+
+const struct blkid_idinfo stratis_idinfo = {
+ .name = "stratis",
+ .usage = BLKID_USAGE_RAID,
+ .probefunc = probe_stratis,
+ .minsz = SB_AREA_SIZE,
+ .magics = {
+ { .magic = STRATIS_MAGIC, .len = MAGIC_LEN,
+ .sboff = MAGIC_OFFSET_COPY_1},
+ { .magic = STRATIS_MAGIC, .len = MAGIC_LEN,
+ .sboff = MAGIC_OFFSET_COPY_2},
+ { NULL }
+ }
+};