1 /* mdraid_linux.c - module to handle Linux Software RAID. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
21 #include <grub/disk.h>
24 #include <grub/misc.h>
25 #include <grub/diskfilter.h>
27 GRUB_MOD_LICENSE ("GPLv3+");
29 /* Linux RAID on disk structures and constants,
30 copied from include/linux/raid/md_p.h. */
32 #define SB_MAGIC 0xa92b4efc
35 * The version-1 superblock :
36 * All numeric fields are little-endian.
38 * Total size: 256 bytes plus 2 per device.
39 * 1K allows 384 devices.
42 struct grub_raid_super_1x
44 /* Constant array information - 128 bytes. */
45 grub_uint32_t magic
; /* MD_SB_MAGIC: 0xa92b4efc - little endian. */
46 grub_uint32_t major_version
; /* 1. */
47 grub_uint32_t feature_map
; /* Bit 0 set if 'bitmap_offset' is meaningful. */
48 grub_uint32_t pad0
; /* Always set to 0 when writing. */
50 grub_uint8_t set_uuid
[16]; /* User-space generated. */
51 char set_name
[32]; /* Set and interpreted by user-space. */
53 grub_uint64_t ctime
; /* Lo 40 bits are seconds, top 24 are microseconds or 0. */
54 grub_uint32_t level
; /* -4 (multipath), -1 (linear), 0,1,4,5. */
55 grub_uint32_t layout
; /* only for raid5 and raid10 currently. */
56 grub_uint64_t size
; /* Used size of component devices, in 512byte sectors. */
58 grub_uint32_t chunksize
; /* In 512byte sectors. */
59 grub_uint32_t raid_disks
;
60 grub_uint32_t bitmap_offset
; /* Sectors after start of superblock that bitmap starts
61 * NOTE: signed, so bitmap can be before superblock
62 * only meaningful of feature_map[0] is set.
65 /* These are only valid with feature bit '4'. */
66 grub_uint32_t new_level
; /* New level we are reshaping to. */
67 grub_uint64_t reshape_position
; /* Next address in array-space for reshape. */
68 grub_uint32_t delta_disks
; /* Change in number of raid_disks. */
69 grub_uint32_t new_layout
; /* New layout. */
70 grub_uint32_t new_chunk
; /* New chunk size (512byte sectors). */
71 grub_uint8_t pad1
[128 - 124]; /* Set to 0 when written. */
73 /* Constant this-device information - 64 bytes. */
74 grub_uint64_t data_offset
; /* Sector start of data, often 0. */
75 grub_uint64_t data_size
; /* Sectors in this device that can be used for data. */
76 grub_uint64_t super_offset
; /* Sector start of this superblock. */
77 grub_uint64_t recovery_offset
; /* Sectors before this offset (from data_offset) have been recovered. */
78 grub_uint32_t dev_number
; /* Permanent identifier of this device - not role in raid. */
79 grub_uint32_t cnt_corrected_read
; /* Number of read errors that were corrected by re-writing. */
80 grub_uint8_t device_uuid
[16]; /* User-space setable, ignored by kernel. */
81 grub_uint8_t devflags
; /* Per-device flags. Only one defined... */
82 grub_uint8_t pad2
[64 - 57]; /* Set to 0 when writing. */
84 /* Array state information - 64 bytes. */
85 grub_uint64_t utime
; /* 40 bits second, 24 btes microseconds. */
86 grub_uint64_t events
; /* Incremented when superblock updated. */
87 grub_uint64_t resync_offset
; /* Data before this offset (from data_offset) known to be in sync. */
88 grub_uint32_t sb_csum
; /* Checksum upto devs[max_dev]. */
89 grub_uint32_t max_dev
; /* Size of devs[] array to consider. */
90 grub_uint8_t pad3
[64 - 32]; /* Set to 0 when writing. */
92 /* Device state information. Indexed by dev_number.
94 * Note there are no per-device state flags. State information is rolled
95 * into the 'roles' value. If a device is spare or faulty, then it doesn't
96 * have a meaningful role.
98 grub_uint16_t dev_roles
[0]; /* Role in array, or 0xffff for a spare, or 0xfffe for faulty. */
100 /* Could be GRUB_PACKED, but since all members in this struct
101 are already appropriately aligned, we can omit this and avoid suboptimal
102 assembly in some cases. */
104 #define WriteMostly1 1 /* Mask for writemostly flag in above devflags. */
106 static struct grub_diskfilter_vg
*
107 grub_mdraid_detect (grub_disk_t disk
,
108 struct grub_diskfilter_pv_id
*id
,
109 grub_disk_addr_t
*start_sector
)
112 grub_uint8_t minor_version
;
114 size
= grub_disk_get_size (disk
);
116 /* Check for an 1.x superblock.
117 * It's always aligned to a 4K boundary
118 * and depending on the minor version it can be:
119 * 0: At least 8K, but less than 12K, from end of device
120 * 1: At start of device
121 * 2: 4K from start of device.
124 for (minor_version
= 0; minor_version
< 3; ++minor_version
)
126 grub_disk_addr_t sector
= 0;
127 struct grub_raid_super_1x sb
;
130 struct grub_diskfilter_vg
*array
;
133 if (size
== GRUB_DISK_SIZE_UNKNOWN
&& minor_version
== 0)
136 switch (minor_version
)
139 sector
= (size
- 8 * 2) & ~(4 * 2 - 1);
149 if (grub_disk_read (disk
, sector
, 0, sizeof (struct grub_raid_super_1x
),
153 if (sb
.magic
!= grub_cpu_to_le32_compile_time (SB_MAGIC
)
154 || grub_le_to_cpu64 (sb
.super_offset
) != sector
)
157 if (sb
.major_version
!= grub_cpu_to_le32_compile_time (1))
158 /* Unsupported version. */
161 level
= grub_le_to_cpu32 (sb
.level
);
164 if ((int) level
== -4)
167 if (level
!= 0 && level
!= 1 && level
!= 4 &&
168 level
!= 5 && level
!= 6 && level
!= 10)
170 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
171 "Unsupported RAID level: %d", sb
.level
);
175 if (grub_le_to_cpu32 (sb
.dev_number
) >=
176 grub_le_to_cpu32 (sb
.max_dev
))
177 /* Spares aren't implemented. */
180 if (grub_disk_read (disk
, sector
,
181 (char *) &sb
.dev_roles
[grub_le_to_cpu32 (sb
.dev_number
)]
183 sizeof (role
), &role
))
186 if (grub_le_to_cpu16 (role
)
187 >= grub_le_to_cpu32 (sb
.raid_disks
))
188 /* Spares aren't implemented. */
192 id
->id
= grub_le_to_cpu16 (role
);
194 uuid
= grub_malloc (16);
198 grub_memcpy (uuid
, sb
.set_uuid
, 16);
200 *start_sector
= grub_le_to_cpu64 (sb
.data_offset
);
202 array
= grub_diskfilter_make_raid (16, uuid
,
203 grub_le_to_cpu32 (sb
.raid_disks
),
206 ? grub_le_to_cpu64 (sb
.size
)
207 : grub_le_to_cpu64 (sb
.data_size
),
208 grub_le_to_cpu32 (sb
.chunksize
),
209 grub_le_to_cpu32 (sb
.layout
),
210 grub_le_to_cpu32 (sb
.level
));
219 static struct grub_diskfilter grub_mdraid_dev
= {
221 .detect
= grub_mdraid_detect
,
225 GRUB_MOD_INIT (mdraid1x
)
227 grub_diskfilter_register_front (&grub_mdraid_dev
);
230 GRUB_MOD_FINI (mdraid1x
)
232 grub_diskfilter_unregister (&grub_mdraid_dev
);