1 /*
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 
18 struct 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  */
40 struct 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 
probe_raid0(blkid_probe pr,blkid_loff_t off)102 static 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 errno ? -errno : 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 
probe_raid1(blkid_probe pr,off_t off)185 static 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 errno ? -errno : 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 
probe_raid(blkid_probe pr,const struct blkid_idmag * mag)215 int probe_raid(blkid_probe pr,
216 		const struct blkid_idmag *mag __attribute__((__unused__)))
217 {
218 	const char *ver = NULL;
219 	int ret = BLKID_PROBE_NONE;
220 
221 	if (pr->size > MD_RESERVED_BYTES) {
222 		/* version 0 at the end of the device */
223 		uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1))
224 			- MD_RESERVED_BYTES;
225 		ret = probe_raid0(pr, sboff);
226 		if (ret < 1)
227 			return ret;	/* error */
228 
229 		/* version 1.0 at the end of the device */
230 		sboff = (pr->size & ~(0x1000 - 1)) - 0x2000;
231 		ret = probe_raid1(pr, sboff);
232 		if (ret < 0)
233 			return ret;	/* error */
234 		if (ret == 0)
235 			ver = "1.0";
236 	}
237 
238 	if (!ver) {
239 		/* version 1.1 at the start of the device */
240 		ret = probe_raid1(pr, 0);
241 		if (ret == 0)
242 			ver = "1.1";
243 
244 		/* version 1.2 at 4k offset from the start */
245 		else if (ret == BLKID_PROBE_NONE) {
246 			ret = probe_raid1(pr, 0x1000);
247 			if (ret == 0)
248 				ver = "1.2";
249 		}
250 	}
251 
252 	if (ver) {
253 		blkid_probe_set_version(pr, ver);
254 		return BLKID_PROBE_OK;
255 	}
256 	return ret;
257 }
258 
259 
260 const struct blkid_idinfo linuxraid_idinfo = {
261 	.name		= "linux_raid_member",
262 	.usage		= BLKID_USAGE_RAID,
263 	.probefunc	= probe_raid,
264 	.magics		= BLKID_NONE_MAGIC
265 };
266 
267 
268