1
/* raid.c - module to read RAID arrays. */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2006,2007,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/raid.h>
27
/* Linked list of RAID arrays. */
28
static struct grub_raid_array *array_list;
29
grub_raid5_recover_func_t grub_raid5_recover_func;
30
grub_raid6_recover_func_t grub_raid6_recover_func;
34
grub_is_array_readable (struct grub_raid_array *array)
39
if (array->nr_devs == array->total_devs)
44
if (array->nr_devs >= 1)
55
if (array->level == 10)
57
n = array->layout & 0xFF;
59
n = (array->layout >> 8) & 0xFF;
66
if (array->nr_devs >= array->total_devs - n)
77
grub_raid_iterate (int (*hook) (const char *name))
79
struct grub_raid_array *array;
81
for (array = array_list; array != NULL; array = array->next)
83
if (grub_is_array_readable (array))
84
if (hook (array->name))
92
static grub_disk_memberlist_t
93
grub_raid_memberlist (grub_disk_t disk)
95
struct grub_raid_array *array = disk->data;
96
grub_disk_memberlist_t list = NULL, tmp;
99
for (i = 0; i < array->total_devs; i++)
100
if (array->members[i].device)
102
tmp = grub_malloc (sizeof (*tmp));
103
tmp->disk = array->members[i].device;
112
grub_raid_getname (struct grub_disk *disk)
114
struct grub_raid_array *array = disk->data;
116
return array->driver->name;
121
grub_raid_open (const char *name, grub_disk_t disk)
123
struct grub_raid_array *array;
126
for (array = array_list; array != NULL; array = array->next)
128
if (!grub_strcmp (array->name, name))
129
if (grub_is_array_readable (array))
134
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
137
disk->id = array->number;
140
grub_dprintf ("raid", "%s: total_devs=%d, disk_size=%lld\n", name,
141
array->total_devs, (unsigned long long) array->disk_size);
143
switch (array->level)
146
disk->total_sectors = array->disk_size;
150
n = array->layout & 0xFF;
152
n = (array->layout >> 8) & 0xFF;
154
disk->total_sectors = grub_divmod64 (array->total_devs *
163
n = array->level / 3;
165
disk->total_sectors = (array->total_devs - n) * array->disk_size;
169
grub_dprintf ("raid", "%s: level=%d, total_sectors=%lld\n", name,
170
array->level, (unsigned long long) disk->total_sectors);
176
grub_raid_close (grub_disk_t disk __attribute ((unused)))
182
grub_raid_block_xor (char *buf1, const char *buf2, int size)
185
const grub_size_t *p2;
187
p1 = (grub_size_t *) buf1;
188
p2 = (const grub_size_t *) buf2;
189
size /= GRUB_CPU_SIZEOF_VOID_P;
199
grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector,
200
grub_size_t size, char *buf)
202
struct grub_raid_array *array = disk->data;
205
switch (array->level)
211
grub_disk_addr_t read_sector, far_ofs;
212
grub_uint32_t disknr, b, near, far, ofs;
214
read_sector = grub_divmod64 (sector, array->chunk_size, &b);
215
far = ofs = near = 1;
218
if (array->level == 1)
219
near = array->total_devs;
220
else if (array->level == 10)
222
near = array->layout & 0xFF;
223
far = (array->layout >> 8) & 0xFF;
224
if (array->layout >> 16)
230
far_ofs = grub_divmod64 (array->disk_size,
231
far * array->chunk_size, 0);
233
far_ofs *= array->chunk_size;
236
read_sector = grub_divmod64 (read_sector * near, array->total_devs,
239
ofs *= array->chunk_size;
244
grub_size_t read_size;
247
read_size = array->chunk_size - b;
248
if (read_size > size)
251
for (i = 0; i < near; i++)
256
for (j = 0; j < far; j++)
258
if (array->members[k].device)
260
if (grub_errno == GRUB_ERR_READ_ERROR)
261
grub_errno = GRUB_ERR_NONE;
263
err = grub_disk_read (array->members[k].device,
264
array->members[k].start_sector +
265
read_sector + j * far_ofs + b,
267
read_size << GRUB_DISK_SECTOR_BITS,
271
else if (err != GRUB_ERR_READ_ERROR)
275
err = grub_error (GRUB_ERR_READ_ERROR,
279
if (k == array->total_devs)
287
if (disknr == array->total_devs)
297
buf += read_size << GRUB_DISK_SECTOR_BITS;
303
disknr += (near - i);
304
while (disknr >= array->total_devs)
306
disknr -= array->total_devs;
317
grub_disk_addr_t read_sector;
318
grub_uint32_t b, p, n, disknr, e;
320
/* n = 1 for level 4 and 5, 2 for level 6. */
321
n = array->level / 3;
323
/* Find the first sector to read. */
324
read_sector = grub_divmod64 (sector, array->chunk_size, &b);
325
read_sector = grub_divmod64 (read_sector, array->total_devs - n,
327
if (array->level >= 5)
329
grub_divmod64 (read_sector, array->total_devs, &p);
331
if (! (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK))
332
p = array->total_devs - 1 - p;
334
if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
343
if (q >= array->total_devs)
344
q -= array->total_devs;
348
else if (disknr >= q)
352
if (disknr >= array->total_devs)
353
disknr -= array->total_devs;
356
p = array->total_devs - n;
358
read_sector *= array->chunk_size;
362
grub_size_t read_size;
365
read_size = array->chunk_size - b;
366
if (read_size > size)
370
if (array->members[disknr].device)
372
/* Reset read error. */
373
if (grub_errno == GRUB_ERR_READ_ERROR)
374
grub_errno = GRUB_ERR_NONE;
376
err = grub_disk_read (array->members[disknr].device,
377
array->members[disknr].start_sector +
379
read_size << GRUB_DISK_SECTOR_BITS,
382
if ((err) && (err != GRUB_ERR_READ_ERROR))
387
err = GRUB_ERR_READ_ERROR;
391
if (array->nr_devs < array->total_devs - n + e)
394
grub_errno = GRUB_ERR_NONE;
395
if (array->level == 6)
397
err = ((grub_raid6_recover_func) ?
398
(*grub_raid6_recover_func) (array, disknr, p,
399
buf, read_sector + b,
401
grub_error (GRUB_ERR_BAD_DEVICE,
402
"raid6rec is not loaded"));
406
err = ((grub_raid5_recover_func) ?
407
(*grub_raid5_recover_func) (array, disknr,
408
buf, read_sector + b,
410
grub_error (GRUB_ERR_BAD_DEVICE,
411
"raid5rec is not loaded"));
418
buf += read_size << GRUB_DISK_SECTOR_BITS;
426
if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
428
if (disknr == array->total_devs)
431
next_level = (disknr == p);
438
next_level = (disknr >= array->total_devs);
443
read_sector += array->chunk_size;
445
if (array->level >= 5)
447
if (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK)
448
p = (p == array->total_devs - 1) ? 0 : p + 1;
450
p = (p == 0) ? array->total_devs - 1 : p - 1;
452
if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
455
if (disknr >= array->total_devs)
456
disknr -= array->total_devs;
460
disknr -= array->total_devs;
477
grub_raid_write (grub_disk_t disk __attribute ((unused)),
478
grub_disk_addr_t sector __attribute ((unused)),
479
grub_size_t size __attribute ((unused)),
480
const char *buf __attribute ((unused)))
482
return GRUB_ERR_NOT_IMPLEMENTED_YET;
486
insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
487
grub_disk_addr_t start_sector, const char *scanner_name,
488
grub_raid_t raid __attribute__ ((unused)))
490
struct grub_raid_array *array = 0, *p;
492
/* See whether the device is part of an array we have already seen a
494
for (p = array_list; p != NULL; p = p->next)
495
if ((p->uuid_len == new_array->uuid_len) &&
496
(! grub_memcmp (p->uuid, new_array->uuid, p->uuid_len)))
498
grub_free (new_array->uuid);
501
/* Do some checks before adding the device to the array. */
503
if (new_array->index >= array->allocated_devs)
506
unsigned int newnum = 2 * (new_array->index + 1);
507
tmp = grub_realloc (array->members, newnum
508
* sizeof (array->members[0]));
511
array->members = tmp;
512
grub_memset (array->members + array->allocated_devs,
513
0, (newnum - array->allocated_devs)
514
* sizeof (array->members[0]));
515
array->allocated_devs = newnum;
518
/* FIXME: Check whether the update time of the superblocks are
521
if (array->total_devs == array->nr_devs)
522
/* We found more members of the array than the array
523
actually has according to its superblock. This shouldn't
525
grub_dprintf ("raid", "array->nr_devs > array->total_devs (%d)?!?",
528
if (array->members[new_array->index].device != NULL)
529
/* We found multiple devices with the same number. Again,
530
this shouldn't happen. */
531
grub_dprintf ("raid", "Found two disks with the number %d?!?",
534
if (new_array->disk_size < array->disk_size)
535
array->disk_size = new_array->disk_size;
539
/* Add an array to the list if we didn't find any. */
542
array = grub_malloc (sizeof (*array));
545
grub_free (new_array->uuid);
552
array->driver = raid;
554
array->allocated_devs = 32;
555
if (new_array->index >= array->allocated_devs)
556
array->allocated_devs = 2 * (new_array->index + 1);
558
array->members = grub_zalloc (array->allocated_devs
559
* sizeof (array->members[0]));
563
grub_free (new_array->uuid);
569
for (p = array_list; p != NULL; p = p->next)
571
if (! p->name && p->number == array->number)
576
if (array->name || p)
578
/* The number is already in use, so we need to find a new one.
579
(Or, in the case of named arrays, the array doesn't have its
580
own number, but we need one that doesn't clash for use as a key
581
in the disk cache. */
582
int i = array->name ? 0x40000000 : 0;
586
for (p = array_list; p != NULL; p = p->next)
594
/* We found an unused number. */
603
/* mdraid 1.x superblocks have only a name stored not a number.
604
Use it directly as GRUB device. */
607
array->name = grub_xasprintf ("md%d", array->number);
610
grub_free (array->members);
611
grub_free (array->uuid);
619
/* Strip off the homehost if present. */
620
char *colon = grub_strchr (array->name, ':');
621
char *new_name = grub_xasprintf ("md/%s",
622
colon ? colon + 1 : array->name);
626
grub_free (array->members);
627
grub_free (array->uuid);
633
grub_free (array->name);
634
array->name = new_name;
637
grub_dprintf ("raid", "Found array %s (%s)\n", array->name,
640
/* Add our new array to the list. */
641
array->next = array_list;
644
/* RAID 1 doesn't use a chunksize but code assumes one so set
646
if (array->level == 1)
647
array->chunk_size = 64;
650
/* Add the device to the array. */
651
array->members[new_array->index].device = disk;
652
array->members[new_array->index].start_sector = start_sector;
658
static grub_raid_t grub_raid_list;
663
struct grub_raid_array *array;
668
struct grub_raid_array *p;
674
for (i = 0; i < p->allocated_devs; i++)
675
if (p->members[i].device)
676
grub_disk_close (p->members[i].device);
677
grub_free (p->members);
688
grub_raid_register (grub_raid_t raid)
690
auto int hook (const char *name);
691
int hook (const char *name)
694
struct grub_raid_array array;
695
grub_disk_addr_t start_sector;
697
grub_dprintf ("raid", "Scanning for RAID devices on disk %s\n", name);
699
disk = grub_disk_open (name);
703
if ((disk->total_sectors != GRUB_ULONG_MAX) &&
704
(! grub_raid_list->detect (disk, &array, &start_sector)) &&
705
(! insert_array (disk, &array, start_sector, grub_raid_list->name,
709
/* This error usually means it's not raid, no need to display
711
if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
714
grub_errno = GRUB_ERR_NONE;
716
grub_disk_close (disk);
721
raid->next = grub_raid_list;
722
grub_raid_list = raid;
723
grub_device_iterate (&hook);
727
grub_raid_unregister (grub_raid_t raid)
731
for (p = &grub_raid_list, q = *p; q; p = &(q->next), q = q->next)
739
static struct grub_disk_dev grub_raid_dev =
742
.id = GRUB_DISK_DEVICE_RAID_ID,
743
.iterate = grub_raid_iterate,
744
.open = grub_raid_open,
745
.close = grub_raid_close,
746
.read = grub_raid_read,
747
.write = grub_raid_write,
749
.memberlist = grub_raid_memberlist,
750
.raidname = grub_raid_getname,
758
grub_disk_dev_register (&grub_raid_dev);
763
grub_disk_dev_unregister (&grub_raid_dev);