/src/util-linux/libblkid/src/superblocks/stratis.c
Line  | Count  | Source (jump to first uncovered line)  | 
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  | 0  | #define STRATIS_UUID_LEN 32  | 
24  |  | /* Contains 4 hyphens and trailing null byte. */  | 
25  |  | #define 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  | 2.63k  | #define BS 512  | 
41  | 526  | #define FIRST_COPY_OFFSET BS  | 
42  | 526  | #define SECOND_COPY_OFFSET (BS * 9)  | 
43  | 526  | #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(const uint8_t *p)  | 
53  | 1.05k  | { | 
54  | 1.05k  |   const struct stratis_sb *stratis = (const struct stratis_sb *)p;  | 
55  | 1.05k  |   uint32_t crc = 0;  | 
56  |  |  | 
57  |  |   /* generate CRC from byte position 4 for length 508 == 512 byte sector */  | 
58  | 1.05k  |   crc = crc32c(~0L, p + sizeof(stratis->crc32),  | 
59  | 1.05k  |       BS - sizeof(stratis->crc32));  | 
60  | 1.05k  |   crc ^= ~0L;  | 
61  |  |  | 
62  | 1.05k  |   return crc == le32_to_cpu(stratis->crc32);  | 
63  | 1.05k  | }  | 
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  | 0  | { | 
72  | 0  |   int i;  | 
73  |  | 
  | 
74  | 0  |   for (i = 0; i < STRATIS_UUID_LEN; i++) { | 
75  | 0  |     *dst_uuid++ = *src_uuid++;  | 
76  | 0  |     if (i == 7 || i == 11 || i == 15 || i == 19)  | 
77  | 0  |       *dst_uuid ++ = '-';  | 
78  | 0  |   }  | 
79  | 0  |   *dst_uuid = '\0';  | 
80  | 0  | }  | 
81  |  |  | 
82  |  | static int probe_stratis(blkid_probe pr,  | 
83  |  |     const struct blkid_idmag *mag __attribute__((__unused__)))  | 
84  | 526  | { | 
85  | 526  |   const struct stratis_sb *stratis = NULL;  | 
86  | 526  |   const uint8_t *buf = blkid_probe_get_buffer(pr, 0, SB_AREA_SIZE);  | 
87  | 526  |   unsigned char uuid[STRATIS_UUID_STR_LEN];  | 
88  |  |  | 
89  | 526  |   if (!buf)  | 
90  | 0  |     return errno ? -errno : 1;  | 
91  |  |  | 
92  | 526  |   if (stratis_valid_sb(buf + FIRST_COPY_OFFSET)) { | 
93  | 0  |     stratis = (const struct stratis_sb *)(buf + FIRST_COPY_OFFSET);  | 
94  | 526  |   } else { | 
95  | 526  |     if (!stratis_valid_sb(buf + SECOND_COPY_OFFSET))  | 
96  | 526  |       return 1;  | 
97  |  |  | 
98  | 0  |     stratis = (const struct stratis_sb *)  | 
99  | 0  |         (buf + SECOND_COPY_OFFSET);  | 
100  | 0  |   }  | 
101  |  |  | 
102  | 0  |   stratis_format_uuid(stratis->dev_uuid, uuid);  | 
103  | 0  |   blkid_probe_strncpy_uuid(pr, uuid, sizeof(uuid));  | 
104  |  | 
  | 
105  | 0  |   stratis_format_uuid(stratis->pool_uuid, uuid);  | 
106  | 0  |   blkid_probe_set_value(pr, "POOL_UUID", uuid, sizeof(uuid));  | 
107  |  | 
  | 
108  | 0  |   blkid_probe_sprintf_value(pr, "BLOCKDEV_SECTORS", "%" PRIu64,  | 
109  | 0  |         le64_to_cpu(stratis->sectors));  | 
110  | 0  |   blkid_probe_sprintf_value(pr, "BLOCKDEV_INITTIME", "%" PRIu64,  | 
111  | 0  |         le64_to_cpu(stratis->initialization_time));  | 
112  | 0  |   return 0;  | 
113  | 526  | }  | 
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  |  | };  |