1 /* raid.c - module to read RAID arrays. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2006,2007,2008 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
->device
[i
])
102 tmp
= grub_malloc (sizeof (*tmp
));
103 tmp
->disk
= array
->device
[i
];
113 grub_raid_open (const char *name
, grub_disk_t disk
)
115 struct grub_raid_array
*array
;
118 for (array
= array_list
; array
!= NULL
; array
= array
->next
)
120 if (!grub_strcmp (array
->name
, name
))
121 if (grub_is_array_readable (array
))
126 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "Unknown RAID device %s",
129 disk
->has_partitions
= 1;
130 disk
->id
= array
->number
;
133 grub_dprintf ("raid", "%s: total_devs=%d, disk_size=%lld\n", name
,
134 array
->total_devs
, (unsigned long long) array
->disk_size
);
136 switch (array
->level
)
139 disk
->total_sectors
= array
->disk_size
;
143 n
= array
->layout
& 0xFF;
145 n
= (array
->layout
>> 8) & 0xFF;
147 disk
->total_sectors
= grub_divmod64 (array
->total_devs
*
156 n
= array
->level
/ 3;
158 disk
->total_sectors
= (array
->total_devs
- n
) * array
->disk_size
;
162 grub_dprintf ("raid", "%s: level=%d, total_sectors=%lld\n", name
,
163 array
->level
, (unsigned long long) disk
->total_sectors
);
169 grub_raid_close (grub_disk_t disk
__attribute ((unused
)))
175 grub_raid_block_xor (char *buf1
, char *buf2
, int size
)
177 grub_size_t
*p1
, *p2
;
179 p1
= (grub_size_t
*) buf1
;
180 p2
= (grub_size_t
*) buf2
;
181 size
/= GRUB_CPU_SIZEOF_VOID_P
;
191 grub_raid_read (grub_disk_t disk
, grub_disk_addr_t sector
,
192 grub_size_t size
, char *buf
)
194 struct grub_raid_array
*array
= disk
->data
;
197 switch (array
->level
)
203 grub_disk_addr_t read_sector
, far_ofs
;
204 grub_uint32_t disknr
, b
, near
, far
, ofs
;
206 read_sector
= grub_divmod64 (sector
, array
->chunk_size
, &b
);
207 far
= ofs
= near
= 1;
210 if (array
->level
== 1)
211 near
= array
->total_devs
;
212 else if (array
->level
== 10)
214 near
= array
->layout
& 0xFF;
215 far
= (array
->layout
>> 8) & 0xFF;
216 if (array
->layout
>> 16)
222 far_ofs
= grub_divmod64 (array
->disk_size
,
223 far
* array
->chunk_size
, 0);
225 far_ofs
*= array
->chunk_size
;
228 read_sector
= grub_divmod64 (read_sector
* near
, array
->total_devs
,
231 ofs
*= array
->chunk_size
;
236 grub_size_t read_size
;
239 read_size
= array
->chunk_size
- b
;
240 if (read_size
> size
)
243 for (i
= 0; i
< near
; i
++)
248 for (j
= 0; j
< far
; j
++)
250 if (array
->device
[k
])
252 if (grub_errno
== GRUB_ERR_READ_ERROR
)
253 grub_errno
= GRUB_ERR_NONE
;
255 err
= grub_disk_read (array
->device
[k
],
256 read_sector
+ j
* far_ofs
+ b
,
258 read_size
<< GRUB_DISK_SECTOR_BITS
,
262 else if (err
!= GRUB_ERR_READ_ERROR
)
266 err
= grub_error (GRUB_ERR_READ_ERROR
,
270 if (k
== array
->total_devs
)
278 if (disknr
== array
->total_devs
)
288 buf
+= read_size
<< GRUB_DISK_SECTOR_BITS
;
294 disknr
+= (near
- i
);
295 while (disknr
>= array
->total_devs
)
297 disknr
-= array
->total_devs
;
308 grub_disk_addr_t read_sector
;
309 grub_uint32_t b
, p
, n
, disknr
, e
;
311 /* n = 1 for level 4 and 5, 2 for level 6. */
312 n
= array
->level
/ 3;
314 /* Find the first sector to read. */
315 read_sector
= grub_divmod64 (sector
, array
->chunk_size
, &b
);
316 read_sector
= grub_divmod64 (read_sector
, array
->total_devs
- n
,
318 if (array
->level
>= 5)
320 grub_divmod64 (read_sector
, array
->total_devs
, &p
);
322 if (! (array
->layout
& GRUB_RAID_LAYOUT_RIGHT_MASK
))
323 p
= array
->total_devs
- 1 - p
;
325 if (array
->layout
& GRUB_RAID_LAYOUT_SYMMETRIC_MASK
)
334 if (q
>= array
->total_devs
)
335 q
-= array
->total_devs
;
339 else if (disknr
>= q
)
343 if (disknr
>= array
->total_devs
)
344 disknr
-= array
->total_devs
;
347 p
= array
->total_devs
- n
;
349 read_sector
*= array
->chunk_size
;
353 grub_size_t read_size
;
356 read_size
= array
->chunk_size
- b
;
357 if (read_size
> size
)
361 if (array
->device
[disknr
])
363 /* Reset read error. */
364 if (grub_errno
== GRUB_ERR_READ_ERROR
)
365 grub_errno
= GRUB_ERR_NONE
;
367 err
= grub_disk_read (array
->device
[disknr
],
369 read_size
<< GRUB_DISK_SECTOR_BITS
,
372 if ((err
) && (err
!= GRUB_ERR_READ_ERROR
))
377 err
= GRUB_ERR_READ_ERROR
;
381 if (array
->nr_devs
< array
->total_devs
- n
+ e
)
384 grub_errno
= GRUB_ERR_NONE
;
385 if (array
->level
== 6)
387 err
= ((grub_raid6_recover_func
) ?
388 (*grub_raid6_recover_func
) (array
, disknr
, p
,
389 buf
, read_sector
+ b
,
391 grub_error (GRUB_ERR_BAD_DEVICE
,
392 "raid6rec is not loaded"));
396 err
= ((grub_raid5_recover_func
) ?
397 (*grub_raid5_recover_func
) (array
, disknr
,
398 buf
, read_sector
+ b
,
400 grub_error (GRUB_ERR_BAD_DEVICE
,
401 "raid5rec is not loaded"));
408 buf
+= read_size
<< GRUB_DISK_SECTOR_BITS
;
416 if (array
->layout
& GRUB_RAID_LAYOUT_SYMMETRIC_MASK
)
418 if (disknr
== array
->total_devs
)
421 next_level
= (disknr
== p
);
428 next_level
= (disknr
>= array
->total_devs
);
433 read_sector
+= array
->chunk_size
;
435 if (array
->level
>= 5)
437 if (array
->layout
& GRUB_RAID_LAYOUT_RIGHT_MASK
)
438 p
= (p
== array
->total_devs
- 1) ? 0 : p
+ 1;
440 p
= (p
== 0) ? array
->total_devs
- 1 : p
- 1;
442 if (array
->layout
& GRUB_RAID_LAYOUT_SYMMETRIC_MASK
)
445 if (disknr
>= array
->total_devs
)
446 disknr
-= array
->total_devs
;
450 disknr
-= array
->total_devs
;
467 grub_raid_write (grub_disk_t disk
__attribute ((unused
)),
468 grub_disk_addr_t sector
__attribute ((unused
)),
469 grub_size_t size
__attribute ((unused
)),
470 const char *buf
__attribute ((unused
)))
472 return GRUB_ERR_NOT_IMPLEMENTED_YET
;
476 insert_array (grub_disk_t disk
, struct grub_raid_array
*new_array
,
477 const char *scanner_name
)
479 struct grub_raid_array
*array
= 0, *p
;
481 /* See whether the device is part of an array we have already seen a
483 for (p
= array_list
; p
!= NULL
; p
= p
->next
)
484 if ((p
->uuid_len
== new_array
->uuid_len
) &&
485 (! grub_memcmp (p
->uuid
, new_array
->uuid
, p
->uuid_len
)))
487 grub_free (new_array
->uuid
);
490 /* Do some checks before adding the device to the array. */
492 /* FIXME: Check whether the update time of the superblocks are
495 if (array
->total_devs
== array
->nr_devs
)
496 /* We found more members of the array than the array
497 actually has according to its superblock. This shouldn't
498 happen normally, but what is the sanest things to do in such
500 return grub_error (GRUB_ERR_BAD_NUMBER
,
501 "array->nr_devs > array->total_devs (%d)?!?",
504 if (array
->device
[new_array
->index
] != NULL
)
505 /* We found multiple devices with the same number. Again,
506 this shouldn't happen.*/
507 return grub_error (GRUB_ERR_BAD_NUMBER
,
508 "Found two disks with the number %d?!?",
511 if (new_array
->disk_size
< array
->disk_size
)
512 array
->disk_size
= new_array
->disk_size
;
516 /* Add an array to the list if we didn't find any. */
519 array
= grub_malloc (sizeof (*array
));
522 grub_free (new_array
->uuid
);
528 grub_memset (&array
->device
, 0, sizeof (array
->device
));
530 /* Check whether we don't have multiple arrays with the same number. */
531 for (p
= array_list
; p
!= NULL
; p
= p
->next
)
533 if (p
->number
== array
->number
)
539 /* The number is already in use, so we need to find an new number. */
544 for (p
= array_list
; p
!= NULL
; p
= p
->next
)
552 /* We found an unused number. */
561 array
->name
= grub_malloc (13);
564 grub_free (array
->uuid
);
570 grub_sprintf (array
->name
, "md%d", array
->number
);
572 grub_dprintf ("raid", "Found array %s (%s)\n", array
->name
,
575 /* Add our new array to the list. */
576 array
->next
= array_list
;
579 /* RAID 1 doestn't use a chunksize but code assumes one so set
581 if (array
->level
== 1)
582 array
->chunk_size
= 64;
585 /* Add the device to the array. */
586 array
->device
[new_array
->index
] = disk
;
592 static grub_raid_t grub_raid_list
;
595 grub_raid_scan_device (int head_only
)
597 auto int hook (const char *name
);
598 int hook (const char *name
)
601 struct grub_raid_array array
;
604 grub_dprintf ("raid", "Scanning for RAID devices\n");
606 disk
= grub_disk_open (name
);
610 if (disk
->total_sectors
== ULONG_MAX
)
612 grub_disk_close (disk
);
616 for (p
= grub_raid_list
; p
; p
= p
->next
)
618 if (! p
->detect (disk
, &array
))
620 if (! insert_array (disk
, &array
, p
->name
))
626 /* This error usually means it's not raid, no need to display
628 if (grub_errno
!= GRUB_ERR_OUT_OF_RANGE
)
631 grub_errno
= GRUB_ERR_NONE
;
636 grub_disk_close (disk
);
641 grub_device_iterate (&hook
);
647 struct grub_raid_array
*array
;
652 struct grub_raid_array
*p
;
658 for (i
= 0; i
< GRUB_RAID_MAX_DEVICES
; i
++)
660 grub_disk_close (p
->device
[i
]);
671 grub_raid_register (grub_raid_t raid
)
673 raid
->next
= grub_raid_list
;
674 grub_raid_list
= raid
;
675 grub_raid_scan_device (1);
679 grub_raid_unregister (grub_raid_t raid
)
683 for (p
= &grub_raid_list
, q
= *p
; q
; p
= &(q
->next
), q
= q
->next
)
692 grub_raid_rescan (void)
695 grub_raid_scan_device (0);
698 static struct grub_disk_dev grub_raid_dev
=
701 .id
= GRUB_DISK_DEVICE_RAID_ID
,
702 .iterate
= grub_raid_iterate
,
703 .open
= grub_raid_open
,
704 .close
= grub_raid_close
,
705 .read
= grub_raid_read
,
706 .write
= grub_raid_write
,
708 .memberlist
= grub_raid_memberlist
,
716 grub_disk_dev_register (&grub_raid_dev
);
721 grub_disk_dev_unregister (&grub_raid_dev
);