(root)/
util-linux-2.39/
libblkid/
src/
superblocks/
stratis.c
       1  /*
       2   * Copyright (C) 2018 Tony Asleson <tasleson@redhat.com>
       3   *
       4   * This file may be redistributed under the terms of the
       5   * GNU Lesser General Public License.
       6   */
       7  
       8  /*
       9   * Specification for on disk format
      10   * https://stratis-storage.github.io/StratisSoftwareDesign.pdf
      11   */
      12  #include <stdio.h>
      13  #include <stdlib.h>
      14  #include <unistd.h>
      15  #include <string.h>
      16  #include <stdint.h>
      17  #include <inttypes.h>
      18  
      19  #include "superblocks.h"
      20  #include "crc32c.h"
      21  
      22  /* Macro to avoid error in struct declaration. */
      23  #define STRATIS_UUID_LEN 32
      24  /* Contains 4 hyphens and trailing null byte. */
      25  const int STRATIS_UUID_STR_LEN = 37;
      26  
      27  struct stratis_sb {
      28  	uint32_t crc32;
      29  	uint8_t magic[16];
      30  	uint64_t sectors;
      31  	uint8_t reserved[4];
      32  	uint8_t pool_uuid[STRATIS_UUID_LEN];
      33  	uint8_t dev_uuid[STRATIS_UUID_LEN];
      34  	uint64_t mda_size;
      35  	uint64_t reserved_size;
      36  	uint64_t flags;
      37  	uint64_t initialization_time;
      38  } __attribute__ ((__packed__));
      39  
      40  #define BS 512
      41  #define FIRST_COPY_OFFSET BS
      42  #define SECOND_COPY_OFFSET (BS * 9)
      43  #define SB_AREA_SIZE (BS * 16)
      44  
      45  const char STRATIS_MAGIC[] = "!Stra0tis\x86\xff\x02^\x41rh";
      46  #define MAGIC_LEN (sizeof(STRATIS_MAGIC) - 1)
      47  
      48  #define _MAGIC_OFFSET (offsetof(const struct stratis_sb, magic))
      49  #define MAGIC_OFFSET_COPY_1 (FIRST_COPY_OFFSET + _MAGIC_OFFSET)
      50  #define MAGIC_OFFSET_COPY_2 (SECOND_COPY_OFFSET + _MAGIC_OFFSET)
      51  
      52  static int stratis_valid_sb(uint8_t *p)
      53  {
      54  	const struct stratis_sb *stratis = (const struct stratis_sb *)p;
      55  	uint32_t crc = 0;
      56  
      57  	/* generate CRC from byte position 4 for length 508 == 512 byte sector */
      58  	crc = crc32c(~0L, p + sizeof(stratis->crc32),
      59  			BS - sizeof(stratis->crc32));
      60  	crc ^= ~0L;
      61  
      62  	return crc == le32_to_cpu(stratis->crc32);
      63  }
      64  
      65  /*
      66   * Format UUID string representation to include hyphens given that Stratis stores
      67   * UUIDs without hyphens in the superblock to keep the UUID length a power of 2.
      68   */
      69  static void stratis_format_uuid(const unsigned char *src_uuid,
      70  				unsigned char *dst_uuid)
      71  {
      72  	int i;
      73  
      74  	for (i = 0; i < STRATIS_UUID_LEN; i++) {
      75  		*dst_uuid++ = *src_uuid++;
      76  		if (i == 7 || i == 11 || i == 15 || i == 19)
      77  			*dst_uuid ++ = '-';
      78  	}
      79  	*dst_uuid = '\0';
      80  }
      81  
      82  static int probe_stratis(blkid_probe pr,
      83  		const struct blkid_idmag *mag __attribute__((__unused__)))
      84  {
      85  	const struct stratis_sb *stratis = NULL;
      86  	uint8_t *buf = blkid_probe_get_buffer(pr, 0, SB_AREA_SIZE);
      87  	unsigned char uuid[STRATIS_UUID_STR_LEN];
      88  
      89  	if (!buf)
      90  		return errno ? -errno : 1;
      91  
      92  	if (stratis_valid_sb(buf + FIRST_COPY_OFFSET)) {
      93  		stratis = (const struct stratis_sb *)(buf + FIRST_COPY_OFFSET);
      94  	} else {
      95  		if (!stratis_valid_sb(buf + SECOND_COPY_OFFSET))
      96  			return 1;
      97  
      98  		stratis = (const struct stratis_sb *)
      99  				(buf + SECOND_COPY_OFFSET);
     100  	}
     101  
     102  	stratis_format_uuid(stratis->dev_uuid, uuid);
     103  	blkid_probe_strncpy_uuid(pr, uuid, sizeof(uuid));
     104  
     105  	stratis_format_uuid(stratis->pool_uuid, uuid);
     106  	blkid_probe_set_value(pr, "POOL_UUID", uuid, sizeof(uuid));
     107  
     108  	blkid_probe_sprintf_value(pr, "BLOCKDEV_SECTORS", "%" PRIu64,
     109  				le64_to_cpu(stratis->sectors));
     110  	blkid_probe_sprintf_value(pr, "BLOCKDEV_INITTIME", "%" PRIu64,
     111  				le64_to_cpu(stratis->initialization_time));
     112  	return 0;
     113  }
     114  
     115  const struct blkid_idinfo stratis_idinfo = {
     116  	.name		= "stratis",
     117  	.usage		= BLKID_USAGE_RAID,
     118  	.probefunc	= probe_stratis,
     119  	.minsz		= SB_AREA_SIZE,
     120  	.magics		= {
     121  		{ .magic = STRATIS_MAGIC, .len = MAGIC_LEN,
     122  			.sboff = MAGIC_OFFSET_COPY_1},
     123  		{ .magic = STRATIS_MAGIC, .len = MAGIC_LEN,
     124  			.sboff = MAGIC_OFFSET_COPY_2},
     125  		{ NULL }
     126  	}
     127  };