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 #include <grub/util/misc.h>
30 GRUB_MOD_LICENSE ("GPLv3+");
32 /* Linked list of RAID arrays. */
33 static struct grub_raid_array
*array_list
;
34 grub_raid5_recover_func_t grub_raid5_recover_func
;
35 grub_raid6_recover_func_t grub_raid6_recover_func
;
39 grub_is_array_readable (struct grub_raid_array
*array
)
44 if (array
->nr_devs
== array
->total_devs
)
49 if (array
->nr_devs
>= 1)
60 if (array
->level
== 10)
62 n
= array
->layout
& 0xFF;
64 n
= (array
->layout
>> 8) & 0xFF;
71 if (array
->nr_devs
>= array
->total_devs
- n
)
82 grub_raid_iterate (int (*hook
) (const char *name
))
84 struct grub_raid_array
*array
;
86 for (array
= array_list
; array
!= NULL
; array
= array
->next
)
88 if (grub_is_array_readable (array
))
89 if (hook (array
->name
))
97 static grub_disk_memberlist_t
98 grub_raid_memberlist (grub_disk_t disk
)
100 struct grub_raid_array
*array
= disk
->data
;
101 grub_disk_memberlist_t list
= NULL
, tmp
;
104 for (i
= 0; i
< array
->total_devs
; i
++)
105 if (array
->members
[i
].device
)
107 tmp
= grub_malloc (sizeof (*tmp
));
108 tmp
->disk
= array
->members
[i
].device
;
117 grub_raid_getname (struct grub_disk
*disk
)
119 struct grub_raid_array
*array
= disk
->data
;
121 return array
->driver
->name
;
128 if (c
>= '0' && c
<= '9')
130 if (c
>= 'a' && c
<= 'f')
132 if (c
>= 'A' && c
<= 'F')
138 grub_raid_open (const char *name
, grub_disk_t disk
)
140 struct grub_raid_array
*array
;
143 if (grub_memcmp (name
, "mduuid/", sizeof ("mduuid/") - 1) == 0)
145 const char *uuidstr
= name
+ sizeof ("mduuid/") - 1;
146 grub_size_t uuid_len
= grub_strlen (uuidstr
) / 2;
147 grub_uint8_t uuidbin
[uuid_len
];
149 for (i
= 0; i
< uuid_len
; i
++)
150 uuidbin
[i
] = ascii2hex (uuidstr
[2 * i
+ 1])
151 | (ascii2hex (uuidstr
[2 * i
]) << 4);
153 for (array
= array_list
; array
!= NULL
; array
= array
->next
)
155 if (uuid_len
== (unsigned) array
->uuid_len
156 && grub_memcmp (uuidbin
, array
->uuid
, uuid_len
) == 0)
157 if (grub_is_array_readable (array
))
162 for (array
= array_list
; array
!= NULL
; array
= array
->next
)
164 if (!grub_strcmp (array
->name
, name
))
165 if (grub_is_array_readable (array
))
170 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "unknown RAID device %s",
173 disk
->id
= array
->number
;
176 grub_dprintf ("raid", "%s: total_devs=%d, disk_size=%lld\n", name
,
177 array
->total_devs
, (unsigned long long) array
->disk_size
);
179 switch (array
->level
)
182 disk
->total_sectors
= array
->disk_size
;
186 n
= array
->layout
& 0xFF;
188 n
= (array
->layout
>> 8) & 0xFF;
190 disk
->total_sectors
= grub_divmod64 (array
->total_devs
*
199 n
= array
->level
/ 3;
201 disk
->total_sectors
= (array
->total_devs
- n
) * array
->disk_size
;
205 grub_dprintf ("raid", "%s: level=%d, total_sectors=%lld\n", name
,
206 array
->level
, (unsigned long long) disk
->total_sectors
);
212 grub_raid_close (grub_disk_t disk
__attribute ((unused
)))
218 grub_raid_block_xor (char *buf1
, const char *buf2
, int size
)
221 const grub_size_t
*p2
;
223 p1
= (grub_size_t
*) buf1
;
224 p2
= (const grub_size_t
*) buf2
;
225 size
/= GRUB_CPU_SIZEOF_VOID_P
;
235 grub_raid_read (grub_disk_t disk
, grub_disk_addr_t sector
,
236 grub_size_t size
, char *buf
)
238 struct grub_raid_array
*array
= disk
->data
;
241 switch (array
->level
)
247 grub_disk_addr_t read_sector
, far_ofs
;
248 grub_uint64_t disknr
, b
, near
, far
, ofs
;
250 read_sector
= grub_divmod64 (sector
, array
->chunk_size
, &b
);
251 far
= ofs
= near
= 1;
254 if (array
->level
== 1)
255 near
= array
->total_devs
;
256 else if (array
->level
== 10)
258 near
= array
->layout
& 0xFF;
259 far
= (array
->layout
>> 8) & 0xFF;
260 if (array
->layout
>> 16)
266 far_ofs
= grub_divmod64 (array
->disk_size
,
267 far
* array
->chunk_size
, 0);
269 far_ofs
*= array
->chunk_size
;
272 read_sector
= grub_divmod64 (read_sector
* near
, array
->total_devs
,
275 ofs
*= array
->chunk_size
;
280 grub_size_t read_size
;
283 read_size
= array
->chunk_size
- b
;
284 if (read_size
> size
)
287 for (i
= 0; i
< near
; i
++)
292 for (j
= 0; j
< far
; j
++)
294 if (array
->members
[k
].device
)
296 if (grub_errno
== GRUB_ERR_READ_ERROR
)
297 grub_errno
= GRUB_ERR_NONE
;
299 err
= grub_disk_read (array
->members
[k
].device
,
300 array
->members
[k
].start_sector
+
301 read_sector
+ j
* far_ofs
+ b
,
303 read_size
<< GRUB_DISK_SECTOR_BITS
,
307 else if (err
!= GRUB_ERR_READ_ERROR
)
311 err
= grub_error (GRUB_ERR_READ_ERROR
,
315 if (k
== array
->total_devs
)
323 if (disknr
== array
->total_devs
)
333 buf
+= read_size
<< GRUB_DISK_SECTOR_BITS
;
339 disknr
+= (near
- i
);
340 while (disknr
>= array
->total_devs
)
342 disknr
-= array
->total_devs
;
353 grub_disk_addr_t read_sector
;
354 grub_uint64_t b
, p
, n
, disknr
, e
;
356 /* n = 1 for level 4 and 5, 2 for level 6. */
357 n
= array
->level
/ 3;
359 /* Find the first sector to read. */
360 read_sector
= grub_divmod64 (sector
, array
->chunk_size
, &b
);
361 read_sector
= grub_divmod64 (read_sector
, array
->total_devs
- n
,
363 if (array
->level
>= 5)
365 grub_divmod64 (read_sector
, array
->total_devs
, &p
);
367 if (! (array
->layout
& GRUB_RAID_LAYOUT_RIGHT_MASK
))
368 p
= array
->total_devs
- 1 - p
;
370 if (array
->layout
& GRUB_RAID_LAYOUT_SYMMETRIC_MASK
)
379 if (q
>= array
->total_devs
)
380 q
-= array
->total_devs
;
384 else if (disknr
>= q
)
388 if (disknr
>= array
->total_devs
)
389 disknr
-= array
->total_devs
;
392 p
= array
->total_devs
- n
;
394 read_sector
*= array
->chunk_size
;
398 grub_size_t read_size
;
401 read_size
= array
->chunk_size
- b
;
402 if (read_size
> size
)
406 if (array
->members
[disknr
].device
)
408 /* Reset read error. */
409 if (grub_errno
== GRUB_ERR_READ_ERROR
)
410 grub_errno
= GRUB_ERR_NONE
;
412 err
= grub_disk_read (array
->members
[disknr
].device
,
413 array
->members
[disknr
].start_sector
+
415 read_size
<< GRUB_DISK_SECTOR_BITS
,
418 if ((err
) && (err
!= GRUB_ERR_READ_ERROR
))
423 err
= GRUB_ERR_READ_ERROR
;
427 if (array
->nr_devs
< array
->total_devs
- n
+ e
)
430 grub_errno
= GRUB_ERR_NONE
;
431 if (array
->level
== 6)
433 err
= ((grub_raid6_recover_func
) ?
434 (*grub_raid6_recover_func
) (array
, disknr
, p
,
435 buf
, read_sector
+ b
,
437 grub_error (GRUB_ERR_BAD_DEVICE
,
438 "raid6rec is not loaded"));
442 err
= ((grub_raid5_recover_func
) ?
443 (*grub_raid5_recover_func
) (array
, disknr
,
444 buf
, read_sector
+ b
,
446 grub_error (GRUB_ERR_BAD_DEVICE
,
447 "raid5rec is not loaded"));
454 buf
+= read_size
<< GRUB_DISK_SECTOR_BITS
;
462 if (array
->layout
& GRUB_RAID_LAYOUT_SYMMETRIC_MASK
)
464 if (disknr
== array
->total_devs
)
467 next_level
= (disknr
== p
);
474 next_level
= (disknr
>= array
->total_devs
);
479 read_sector
+= array
->chunk_size
;
481 if (array
->level
>= 5)
483 if (array
->layout
& GRUB_RAID_LAYOUT_RIGHT_MASK
)
484 p
= (p
== array
->total_devs
- 1) ? 0 : p
+ 1;
486 p
= (p
== 0) ? array
->total_devs
- 1 : p
- 1;
488 if (array
->layout
& GRUB_RAID_LAYOUT_SYMMETRIC_MASK
)
491 if (disknr
>= array
->total_devs
)
492 disknr
-= array
->total_devs
;
496 disknr
-= array
->total_devs
;
513 grub_raid_write (grub_disk_t disk
__attribute ((unused
)),
514 grub_disk_addr_t sector
__attribute ((unused
)),
515 grub_size_t size
__attribute ((unused
)),
516 const char *buf
__attribute ((unused
)))
518 return GRUB_ERR_NOT_IMPLEMENTED_YET
;
522 insert_array (grub_disk_t disk
, struct grub_raid_array
*new_array
,
523 grub_disk_addr_t start_sector
, const char *scanner_name
,
524 grub_raid_t raid
__attribute__ ((unused
)))
526 struct grub_raid_array
*array
= 0, *p
;
528 /* See whether the device is part of an array we have already seen a
530 for (p
= array_list
; p
!= NULL
; p
= p
->next
)
531 if ((p
->uuid_len
== new_array
->uuid_len
) &&
532 (! grub_memcmp (p
->uuid
, new_array
->uuid
, p
->uuid_len
)))
534 grub_free (new_array
->uuid
);
537 /* Do some checks before adding the device to the array. */
539 if (new_array
->index
>= array
->allocated_devs
)
542 unsigned int newnum
= 2 * (new_array
->index
+ 1);
543 tmp
= grub_realloc (array
->members
, newnum
544 * sizeof (array
->members
[0]));
547 array
->members
= tmp
;
548 grub_memset (array
->members
+ array
->allocated_devs
,
549 0, (newnum
- array
->allocated_devs
)
550 * sizeof (array
->members
[0]));
551 array
->allocated_devs
= newnum
;
554 /* FIXME: Check whether the update time of the superblocks are
557 if (array
->total_devs
== array
->nr_devs
)
558 /* We found more members of the array than the array
559 actually has according to its superblock. This shouldn't
561 return grub_error (GRUB_ERR_BAD_DEVICE
,
562 "superfluous RAID member (%d found)",
565 if (array
->members
[new_array
->index
].device
!= NULL
)
566 /* We found multiple devices with the same number. Again,
567 this shouldn't happen. */
568 return grub_error (GRUB_ERR_BAD_DEVICE
,
569 "found two disks with the index %d for RAID %s",
570 new_array
->index
, array
->name
);
572 if (new_array
->disk_size
< array
->disk_size
)
573 array
->disk_size
= new_array
->disk_size
;
577 /* Add an array to the list if we didn't find any. */
580 array
= grub_malloc (sizeof (*array
));
583 grub_free (new_array
->uuid
);
590 array
->driver
= raid
;
592 array
->allocated_devs
= 32;
593 if (new_array
->index
>= array
->allocated_devs
)
594 array
->allocated_devs
= 2 * (new_array
->index
+ 1);
596 array
->members
= grub_zalloc (array
->allocated_devs
597 * sizeof (array
->members
[0]));
601 grub_free (new_array
->uuid
);
607 for (p
= array_list
; p
!= NULL
; p
= p
->next
)
609 if (p
->number
== array
->number
)
614 if (array
->name
|| p
)
616 /* The number is already in use, so we need to find a new one.
617 (Or, in the case of named arrays, the array doesn't have its
618 own number, but we need one that doesn't clash for use as a key
619 in the disk cache. */
620 int i
= array
->name
? 0x40000000 : 0;
624 for (p
= array_list
; p
!= NULL
; p
= p
->next
)
632 /* We found an unused number. */
641 /* mdraid 1.x superblocks have only a name stored not a number.
642 Use it directly as GRUB device. */
645 array
->name
= grub_xasprintf ("md%d", array
->number
);
648 grub_free (array
->members
);
649 grub_free (array
->uuid
);
657 /* Strip off the homehost if present. */
658 char *colon
= grub_strchr (array
->name
, ':');
659 char *new_name
= grub_xasprintf ("md/%s",
660 colon
? colon
+ 1 : array
->name
);
664 grub_free (array
->members
);
665 grub_free (array
->uuid
);
671 grub_free (array
->name
);
672 array
->name
= new_name
;
675 grub_dprintf ("raid", "Found array %s (%s)\n", array
->name
,
678 grub_util_info ("Found array %s (%s)", array
->name
,
682 /* Add our new array to the list. */
683 array
->next
= array_list
;
686 /* RAID 1 doesn't use a chunksize but code assumes one so set
688 if (array
->level
== 1)
689 array
->chunk_size
= 64;
692 /* Add the device to the array. */
693 array
->members
[new_array
->index
].device
= disk
;
694 array
->members
[new_array
->index
].start_sector
= start_sector
;
700 static grub_raid_t grub_raid_list
;
705 struct grub_raid_array
*array
;
710 struct grub_raid_array
*p
;
716 for (i
= 0; i
< p
->allocated_devs
; i
++)
717 if (p
->members
[i
].device
)
718 grub_disk_close (p
->members
[i
].device
);
719 grub_free (p
->members
);
730 grub_raid_register (grub_raid_t raid
)
732 auto int hook (const char *name
);
733 int hook (const char *name
)
736 struct grub_raid_array array
;
737 grub_disk_addr_t start_sector
;
739 grub_dprintf ("raid", "Scanning for %s RAID devices on disk %s\n",
740 grub_raid_list
->name
, name
);
742 grub_util_info ("Scanning for %s RAID devices on disk %s",
743 grub_raid_list
->name
, name
);
746 disk
= grub_disk_open (name
);
750 if ((disk
->total_sectors
!= GRUB_ULONG_MAX
) &&
751 (! grub_raid_list
->detect (disk
, &array
, &start_sector
)) &&
752 (! insert_array (disk
, &array
, start_sector
, grub_raid_list
->name
,
756 /* This error usually means it's not raid, no need to display
758 if (grub_errno
!= GRUB_ERR_OUT_OF_RANGE
)
761 grub_errno
= GRUB_ERR_NONE
;
763 grub_disk_close (disk
);
768 raid
->next
= grub_raid_list
;
769 grub_raid_list
= raid
;
770 grub_device_iterate (&hook
);
774 grub_raid_unregister (grub_raid_t raid
)
778 for (p
= &grub_raid_list
, q
= *p
; q
; p
= &(q
->next
), q
= q
->next
)
786 static struct grub_disk_dev grub_raid_dev
=
789 .id
= GRUB_DISK_DEVICE_RAID_ID
,
790 .iterate
= grub_raid_iterate
,
791 .open
= grub_raid_open
,
792 .close
= grub_raid_close
,
793 .read
= grub_raid_read
,
794 .write
= grub_raid_write
,
796 .memberlist
= grub_raid_memberlist
,
797 .raidname
= grub_raid_getname
,
805 grub_disk_dev_register (&grub_raid_dev
);
810 grub_disk_dev_unregister (&grub_raid_dev
);