blob: a3f9d67d59c2d2757a1f19e83475d945fb4f976f [file] [log] [blame]
bigbiff bigbiffe60683a2013-02-22 20:55:50 -05001/*
2 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
3 *
4 * Inspired by libvolume_id by
5 * Kay Sievers <kay.sievers@vrfy.org>
6 *
7 * This file may be redistributed under the terms of the
8 * GNU Lesser General Public License.
9 */
10#include <stdio.h>
11#include <stdlib.h>
12#include <unistd.h>
13#include <string.h>
14#include <stdint.h>
15
16#include "superblocks.h"
17
18struct mdp0_super_block {
19 uint32_t md_magic;
20 uint32_t major_version;
21 uint32_t minor_version;
22 uint32_t patch_version;
23 uint32_t gvalid_words;
24 uint32_t set_uuid0;
25 uint32_t ctime;
26 uint32_t level;
27 uint32_t size;
28 uint32_t nr_disks;
29 uint32_t raid_disks;
30 uint32_t md_minor;
31 uint32_t not_persistent;
32 uint32_t set_uuid1;
33 uint32_t set_uuid2;
34 uint32_t set_uuid3;
35};
36
37/*
38 * Version-1, little-endian.
39 */
40struct mdp1_super_block {
41 /* constant array information - 128 bytes */
42 uint32_t magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */
43 uint32_t major_version; /* 1 */
44 uint32_t feature_map; /* 0 for now */
45 uint32_t pad0; /* always set to 0 when writing */
46
47 uint8_t set_uuid[16]; /* user-space generated. */
48 unsigned char set_name[32]; /* set and interpreted by user-space */
49
50 uint64_t ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/
51 uint32_t level; /* -4 (multipath), -1 (linear), 0,1,4,5 */
52 uint32_t layout; /* only for raid5 currently */
53 uint64_t size; /* used size of component devices, in 512byte sectors */
54
55 uint32_t chunksize; /* in 512byte sectors */
56 uint32_t raid_disks;
57 uint32_t bitmap_offset; /* sectors after start of superblock that bitmap starts
58 * NOTE: signed, so bitmap can be before superblock
59 * only meaningful of feature_map[0] is set.
60 */
61
62 /* These are only valid with feature bit '4' */
63 uint32_t new_level; /* new level we are reshaping to */
64 uint64_t reshape_position; /* next address in array-space for reshape */
65 uint32_t delta_disks; /* change in number of raid_disks */
66 uint32_t new_layout; /* new layout */
67 uint32_t new_chunk; /* new chunk size (bytes) */
68 uint8_t pad1[128-124]; /* set to 0 when written */
69
70 /* constant this-device information - 64 bytes */
71 uint64_t data_offset; /* sector start of data, often 0 */
72 uint64_t data_size; /* sectors in this device that can be used for data */
73 uint64_t super_offset; /* sector start of this superblock */
74 uint64_t recovery_offset;/* sectors before this offset (from data_offset) have been recovered */
75 uint32_t dev_number; /* permanent identifier of this device - not role in raid */
76 uint32_t cnt_corrected_read; /* number of read errors that were corrected by re-writing */
77 uint8_t device_uuid[16]; /* user-space setable, ignored by kernel */
78 uint8_t devflags; /* per-device flags. Only one defined...*/
79 uint8_t pad2[64-57]; /* set to 0 when writing */
80
81 /* array state information - 64 bytes */
82 uint64_t utime; /* 40 bits second, 24 btes microseconds */
83 uint64_t events; /* incremented when superblock updated */
84 uint64_t resync_offset; /* data before this offset (from data_offset) known to be in sync */
85 uint32_t sb_csum; /* checksum up to dev_roles[max_dev] */
86 uint32_t max_dev; /* size of dev_roles[] array to consider */
87 uint8_t pad3[64-32]; /* set to 0 when writing */
88
89 /* device state information. Indexed by dev_number.
90 * 2 bytes per device
91 * Note there are no per-device state flags. State information is rolled
92 * into the 'roles' value. If a device is spare or faulty, then it doesn't
93 * have a meaningful role.
94 */
95 uint16_t dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */
96};
97
98
99#define MD_RESERVED_BYTES 0x10000
100#define MD_SB_MAGIC 0xa92b4efc
101
102static int probe_raid0(blkid_probe pr, blkid_loff_t off)
103{
104 struct mdp0_super_block *mdp0;
105 union {
106 uint32_t ints[4];
107 uint8_t bytes[16];
108 } uuid;
109 uint32_t ma, mi, pa;
110 uint64_t size;
111
112 if (pr->size < MD_RESERVED_BYTES)
113 return -1;
114 mdp0 = (struct mdp0_super_block *)
115 blkid_probe_get_buffer(pr,
116 off,
117 sizeof(struct mdp0_super_block));
118 if (!mdp0)
119 return -1;
120
121 memset(uuid.ints, 0, sizeof(uuid.ints));
122
123 if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
124 uuid.ints[0] = swab32(mdp0->set_uuid0);
125 if (le32_to_cpu(mdp0->minor_version) >= 90) {
126 uuid.ints[1] = swab32(mdp0->set_uuid1);
127 uuid.ints[2] = swab32(mdp0->set_uuid2);
128 uuid.ints[3] = swab32(mdp0->set_uuid3);
129 }
130 ma = le32_to_cpu(mdp0->major_version);
131 mi = le32_to_cpu(mdp0->minor_version);
132 pa = le32_to_cpu(mdp0->patch_version);
133 size = le32_to_cpu(mdp0->size);
134
135 } else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
136 uuid.ints[0] = mdp0->set_uuid0;
137 if (be32_to_cpu(mdp0->minor_version) >= 90) {
138 uuid.ints[1] = mdp0->set_uuid1;
139 uuid.ints[2] = mdp0->set_uuid2;
140 uuid.ints[3] = mdp0->set_uuid3;
141 }
142 ma = be32_to_cpu(mdp0->major_version);
143 mi = be32_to_cpu(mdp0->minor_version);
144 pa = be32_to_cpu(mdp0->patch_version);
145 size = be32_to_cpu(mdp0->size);
146 } else
147 return 1;
148
149 size <<= 10; /* convert KiB to bytes */
150
151 if (pr->size < 0 || (uint64_t) pr->size < size + MD_RESERVED_BYTES)
152 /* device is too small */
153 return 1;
154
155 if (off < 0 || (uint64_t) off < size)
156 /* no space before superblock */
157 return 1;
158
159 /*
160 * Check for collisions between RAID and partition table
161 *
162 * For example the superblock is at the end of the last partition, it's
163 * the same position as at the end of the disk...
164 */
165 if ((S_ISREG(pr->mode) || blkid_probe_is_wholedisk(pr)) &&
166 blkid_probe_is_covered_by_pt(pr,
167 off - size, /* min. start */
168 size + MD_RESERVED_BYTES)) { /* min. length */
169
170 /* ignore this superblock, it's within any partition and
171 * we are working with whole-disk now */
172 return 1;
173 }
174
175 if (blkid_probe_sprintf_version(pr, "%u.%u.%u", ma, mi, pa) != 0)
176 return -1;
177 if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0)
178 return -1;
179 if (blkid_probe_set_magic(pr, off, sizeof(mdp0->md_magic),
180 (unsigned char *) &mdp0->md_magic))
181 return -1;
182 return 0;
183}
184
185static int probe_raid1(blkid_probe pr, off_t off)
186{
187 struct mdp1_super_block *mdp1;
188
189 mdp1 = (struct mdp1_super_block *)
190 blkid_probe_get_buffer(pr,
191 off,
192 sizeof(struct mdp1_super_block));
193 if (!mdp1)
194 return -1;
195 if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC)
196 return -1;
197 if (le32_to_cpu(mdp1->major_version) != 1U)
198 return -1;
199 if (le64_to_cpu(mdp1->super_offset) != (uint64_t) off >> 9)
200 return -1;
201 if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0)
202 return -1;
203 if (blkid_probe_set_uuid_as(pr,
204 (unsigned char *) mdp1->device_uuid, "UUID_SUB") != 0)
205 return -1;
206 if (blkid_probe_set_label(pr, mdp1->set_name,
207 sizeof(mdp1->set_name)) != 0)
208 return -1;
209 if (blkid_probe_set_magic(pr, off, sizeof(mdp1->magic),
210 (unsigned char *) &mdp1->magic))
211 return -1;
212 return 0;
213}
214
215int probe_raid(blkid_probe pr,
216 const struct blkid_idmag *mag __attribute__((__unused__)))
217{
218 const char *ver = NULL;
219
220 if (pr->size > MD_RESERVED_BYTES) {
221 /* version 0 at the end of the device */
222 uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1))
223 - MD_RESERVED_BYTES;
224 if (probe_raid0(pr, sboff) == 0)
225 return 0;
226
227 /* version 1.0 at the end of the device */
228 sboff = (pr->size & ~(0x1000 - 1)) - 0x2000;
229 if (probe_raid1(pr, sboff) == 0)
230 ver = "1.0";
231 }
232
233 if (!ver) {
234 /* version 1.1 at the start of the device */
235 if (probe_raid1(pr, 0) == 0)
236 ver = "1.1";
237
238 /* version 1.2 at 4k offset from the start */
239 else if (probe_raid1(pr, 0x1000) == 0)
240 ver = "1.2";
241 }
242
243 if (ver) {
244 blkid_probe_set_version(pr, ver);
245 return 0;
246 }
247 return -1;
248}
249
250
251const struct blkid_idinfo linuxraid_idinfo = {
252 .name = "linux_raid_member",
253 .usage = BLKID_USAGE_RAID,
254 .probefunc = probe_raid,
255 .magics = BLKID_NONE_MAGIC
256};
257
258