1 /* raid.c - module to read RAID arrays. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2006,2007,2008,2009 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
, const char *buf2
, int size
)
178 const grub_size_t
*p2
;
180 p1
= (grub_size_t
*) buf1
;
181 p2
= (const grub_size_t
*) buf2
;
182 size
/= GRUB_CPU_SIZEOF_VOID_P
;
192 grub_raid_read (grub_disk_t disk
, grub_disk_addr_t sector
,
193 grub_size_t size
, char *buf
)
195 struct grub_raid_array
*array
= disk
->data
;
198 switch (array
->level
)
204 grub_disk_addr_t read_sector
, far_ofs
;
205 grub_uint32_t disknr
, b
, near
, far
, ofs
;
207 read_sector
= grub_divmod64 (sector
, array
->chunk_size
, &b
);
208 far
= ofs
= near
= 1;
211 if (array
->level
== 1)
212 near
= array
->total_devs
;
213 else if (array
->level
== 10)
215 near
= array
->layout
& 0xFF;
216 far
= (array
->layout
>> 8) & 0xFF;
217 if (array
->layout
>> 16)
223 far_ofs
= grub_divmod64 (array
->disk_size
,
224 far
* array
->chunk_size
, 0);
226 far_ofs
*= array
->chunk_size
;
229 read_sector
= grub_divmod64 (read_sector
* near
, array
->total_devs
,
232 ofs
*= array
->chunk_size
;
237 grub_size_t read_size
;
240 read_size
= array
->chunk_size
- b
;
241 if (read_size
> size
)
244 for (i
= 0; i
< near
; i
++)
249 for (j
= 0; j
< far
; j
++)
251 if (array
->device
[k
])
253 if (grub_errno
== GRUB_ERR_READ_ERROR
)
254 grub_errno
= GRUB_ERR_NONE
;
256 err
= grub_disk_read (array
->device
[k
],
257 read_sector
+ j
* far_ofs
+ b
,
259 read_size
<< GRUB_DISK_SECTOR_BITS
,
263 else if (err
!= GRUB_ERR_READ_ERROR
)
267 err
= grub_error (GRUB_ERR_READ_ERROR
,
271 if (k
== array
->total_devs
)
279 if (disknr
== array
->total_devs
)
289 buf
+= read_size
<< GRUB_DISK_SECTOR_BITS
;
295 disknr
+= (near
- i
);
296 while (disknr
>= array
->total_devs
)
298 disknr
-= array
->total_devs
;
309 grub_disk_addr_t read_sector
;
310 grub_uint32_t b
, p
, n
, disknr
, e
;
312 /* n = 1 for level 4 and 5, 2 for level 6. */
313 n
= array
->level
/ 3;
315 /* Find the first sector to read. */
316 read_sector
= grub_divmod64 (sector
, array
->chunk_size
, &b
);
317 read_sector
= grub_divmod64 (read_sector
, array
->total_devs
- n
,
319 if (array
->level
>= 5)
321 grub_divmod64 (read_sector
, array
->total_devs
, &p
);
323 if (! (array
->layout
& GRUB_RAID_LAYOUT_RIGHT_MASK
))
324 p
= array
->total_devs
- 1 - p
;
326 if (array
->layout
& GRUB_RAID_LAYOUT_SYMMETRIC_MASK
)
335 if (q
>= array
->total_devs
)
336 q
-= array
->total_devs
;
340 else if (disknr
>= q
)
344 if (disknr
>= array
->total_devs
)
345 disknr
-= array
->total_devs
;
348 p
= array
->total_devs
- n
;
350 read_sector
*= array
->chunk_size
;
354 grub_size_t read_size
;
357 read_size
= array
->chunk_size
- b
;
358 if (read_size
> size
)
362 if (array
->device
[disknr
])
364 /* Reset read error. */
365 if (grub_errno
== GRUB_ERR_READ_ERROR
)
366 grub_errno
= GRUB_ERR_NONE
;
368 err
= grub_disk_read (array
->device
[disknr
],
370 read_size
<< GRUB_DISK_SECTOR_BITS
,
373 if ((err
) && (err
!= GRUB_ERR_READ_ERROR
))
378 err
= GRUB_ERR_READ_ERROR
;
382 if (array
->nr_devs
< array
->total_devs
- n
+ e
)
385 grub_errno
= GRUB_ERR_NONE
;
386 if (array
->level
== 6)
388 err
= ((grub_raid6_recover_func
) ?
389 (*grub_raid6_recover_func
) (array
, disknr
, p
,
390 buf
, read_sector
+ b
,
392 grub_error (GRUB_ERR_BAD_DEVICE
,
393 "raid6rec is not loaded"));
397 err
= ((grub_raid5_recover_func
) ?
398 (*grub_raid5_recover_func
) (array
, disknr
,
399 buf
, read_sector
+ b
,
401 grub_error (GRUB_ERR_BAD_DEVICE
,
402 "raid5rec is not loaded"));
409 buf
+= read_size
<< GRUB_DISK_SECTOR_BITS
;
417 if (array
->layout
& GRUB_RAID_LAYOUT_SYMMETRIC_MASK
)
419 if (disknr
== array
->total_devs
)
422 next_level
= (disknr
== p
);
429 next_level
= (disknr
>= array
->total_devs
);
434 read_sector
+= array
->chunk_size
;
436 if (array
->level
>= 5)
438 if (array
->layout
& GRUB_RAID_LAYOUT_RIGHT_MASK
)
439 p
= (p
== array
->total_devs
- 1) ? 0 : p
+ 1;
441 p
= (p
== 0) ? array
->total_devs
- 1 : p
- 1;
443 if (array
->layout
& GRUB_RAID_LAYOUT_SYMMETRIC_MASK
)
446 if (disknr
>= array
->total_devs
)
447 disknr
-= array
->total_devs
;
451 disknr
-= array
->total_devs
;
468 grub_raid_write (grub_disk_t disk
__attribute ((unused
)),
469 grub_disk_addr_t sector
__attribute ((unused
)),
470 grub_size_t size
__attribute ((unused
)),
471 const char *buf
__attribute ((unused
)))
473 return GRUB_ERR_NOT_IMPLEMENTED_YET
;
477 insert_array (grub_disk_t disk
, struct grub_raid_array
*new_array
,
478 const char *scanner_name
)
480 struct grub_raid_array
*array
= 0, *p
;
482 /* See whether the device is part of an array we have already seen a
484 for (p
= array_list
; p
!= NULL
; p
= p
->next
)
485 if ((p
->uuid_len
== new_array
->uuid_len
) &&
486 (! grub_memcmp (p
->uuid
, new_array
->uuid
, p
->uuid_len
)))
488 grub_free (new_array
->uuid
);
491 /* Do some checks before adding the device to the array. */
493 /* FIXME: Check whether the update time of the superblocks are
496 if (array
->total_devs
== array
->nr_devs
)
497 /* We found more members of the array than the array
498 actually has according to its superblock. This shouldn't
500 grub_dprintf ("raid", "array->nr_devs > array->total_devs (%d)?!?",
503 if (array
->device
[new_array
->index
] != NULL
)
504 /* We found multiple devices with the same number. Again,
505 this shouldn't happen.*/
506 grub_dprintf ("raid", "Found two disks with the number %d?!?",
509 if (new_array
->disk_size
< array
->disk_size
)
510 array
->disk_size
= new_array
->disk_size
;
514 /* Add an array to the list if we didn't find any. */
517 array
= grub_malloc (sizeof (*array
));
520 grub_free (new_array
->uuid
);
526 grub_memset (&array
->device
, 0, sizeof (array
->device
));
528 /* Check whether we don't have multiple arrays with the same number. */
529 for (p
= array_list
; p
!= NULL
; p
= p
->next
)
531 if (p
->number
== array
->number
)
537 /* The number is already in use, so we need to find an new number. */
542 for (p
= array_list
; p
!= NULL
; p
= p
->next
)
550 /* We found an unused number. */
559 array
->name
= grub_xasprintf ("md%d", array
->number
);
562 grub_free (array
->uuid
);
568 grub_dprintf ("raid", "Found array %s (%s)\n", array
->name
,
571 /* Add our new array to the list. */
572 array
->next
= array_list
;
575 /* RAID 1 doesn't use a chunksize but code assumes one so set
577 if (array
->level
== 1)
578 array
->chunk_size
= 64;
581 /* Add the device to the array. */
582 array
->device
[new_array
->index
] = disk
;
588 static grub_raid_t grub_raid_list
;
593 struct grub_raid_array
*array
;
598 struct grub_raid_array
*p
;
604 for (i
= 0; i
< GRUB_RAID_MAX_DEVICES
; i
++)
606 grub_disk_close (p
->device
[i
]);
617 grub_raid_register (grub_raid_t raid
)
619 auto int hook (const char *name
);
620 int hook (const char *name
)
623 struct grub_raid_array array
;
625 grub_dprintf ("raid", "Scanning for RAID devices on disk %s\n", name
);
627 disk
= grub_disk_open (name
);
631 if ((disk
->total_sectors
!= GRUB_ULONG_MAX
) &&
632 (! grub_raid_list
->detect (disk
, &array
)) &&
633 (! insert_array (disk
, &array
, grub_raid_list
->name
)))
636 /* This error usually means it's not raid, no need to display
638 if (grub_errno
!= GRUB_ERR_OUT_OF_RANGE
)
641 grub_errno
= GRUB_ERR_NONE
;
643 grub_disk_close (disk
);
648 raid
->next
= grub_raid_list
;
649 grub_raid_list
= raid
;
650 grub_device_iterate (&hook
);
654 grub_raid_unregister (grub_raid_t raid
)
658 for (p
= &grub_raid_list
, q
= *p
; q
; p
= &(q
->next
), q
= q
->next
)
666 static struct grub_disk_dev grub_raid_dev
=
669 .id
= GRUB_DISK_DEVICE_RAID_ID
,
670 .iterate
= grub_raid_iterate
,
671 .open
= grub_raid_open
,
672 .close
= grub_raid_close
,
673 .read
= grub_raid_read
,
674 .write
= grub_raid_write
,
676 .memberlist
= grub_raid_memberlist
,
684 grub_disk_dev_register (&grub_raid_dev
);
689 grub_disk_dev_unregister (&grub_raid_dev
);