mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-10-31 20:57:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			692 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			692 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* raid.c - module to read RAID arrays.  */
 | ||
| /*
 | ||
|  *  GRUB  --  GRand Unified Bootloader
 | ||
|  *  Copyright (C) 2006,2007,2008,2009  Free Software Foundation, Inc.
 | ||
|  *
 | ||
|  *  GRUB is free software: you can redistribute it and/or modify
 | ||
|  *  it under the terms of the GNU General Public License as published by
 | ||
|  *  the Free Software Foundation, either version 3 of the License, or
 | ||
|  *  (at your option) any later version.
 | ||
|  *
 | ||
|  *  GRUB is distributed in the hope that it will be useful,
 | ||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||
|  *  GNU General Public License for more details.
 | ||
|  *
 | ||
|  *  You should have received a copy of the GNU General Public License
 | ||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||
|  */
 | ||
| 
 | ||
| #include <grub/dl.h>
 | ||
| #include <grub/disk.h>
 | ||
| #include <grub/mm.h>
 | ||
| #include <grub/err.h>
 | ||
| #include <grub/misc.h>
 | ||
| #include <grub/raid.h>
 | ||
| 
 | ||
| /* Linked list of RAID arrays. */
 | ||
| static struct grub_raid_array *array_list;
 | ||
| grub_raid5_recover_func_t grub_raid5_recover_func;
 | ||
| grub_raid6_recover_func_t grub_raid6_recover_func;
 | ||
| 
 | ||
| 
 | ||
| static char
 | ||
| grub_is_array_readable (struct grub_raid_array *array)
 | ||
| {
 | ||
|   switch (array->level)
 | ||
|     {
 | ||
|     case 0:
 | ||
|       if (array->nr_devs == array->total_devs)
 | ||
| 	return 1;
 | ||
|       break;
 | ||
| 
 | ||
|     case 1:
 | ||
|       if (array->nr_devs >= 1)
 | ||
| 	return 1;
 | ||
|       break;
 | ||
| 
 | ||
|     case 4:
 | ||
|     case 5:
 | ||
|     case 6:
 | ||
|     case 10:
 | ||
|       {
 | ||
|         unsigned int n;
 | ||
| 
 | ||
|         if (array->level == 10)
 | ||
|           {
 | ||
|             n = array->layout & 0xFF;
 | ||
|             if (n == 1)
 | ||
|               n = (array->layout >> 8) & 0xFF;
 | ||
| 
 | ||
|             n--;
 | ||
|           }
 | ||
|         else
 | ||
|           n = array->level / 3;
 | ||
| 
 | ||
|         if (array->nr_devs >= array->total_devs - n)
 | ||
|           return 1;
 | ||
| 
 | ||
|         break;
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| static int
 | ||
| grub_raid_iterate (int (*hook) (const char *name))
 | ||
| {
 | ||
|   struct grub_raid_array *array;
 | ||
| 
 | ||
|   for (array = array_list; array != NULL; array = array->next)
 | ||
|     {
 | ||
|       if (grub_is_array_readable (array))
 | ||
| 	if (hook (array->name))
 | ||
| 	  return 1;
 | ||
|     }
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| #ifdef GRUB_UTIL
 | ||
| static grub_disk_memberlist_t
 | ||
| grub_raid_memberlist (grub_disk_t disk)
 | ||
| {
 | ||
|   struct grub_raid_array *array = disk->data;
 | ||
|   grub_disk_memberlist_t list = NULL, tmp;
 | ||
|   unsigned int i;
 | ||
| 
 | ||
|   for (i = 0; i < array->total_devs; i++)
 | ||
|     if (array->device[i])
 | ||
|       {
 | ||
|         tmp = grub_malloc (sizeof (*tmp));
 | ||
|         tmp->disk = array->device[i];
 | ||
|         tmp->next = list;
 | ||
|         list = tmp;
 | ||
|       }
 | ||
| 
 | ||
|   return list;
 | ||
| }
 | ||
| #endif
 | ||
| 
 | ||
| static grub_err_t
 | ||
| grub_raid_open (const char *name, grub_disk_t disk)
 | ||
| {
 | ||
|   struct grub_raid_array *array;
 | ||
|   unsigned n;
 | ||
| 
 | ||
|   for (array = array_list; array != NULL; array = array->next)
 | ||
|     {
 | ||
|       if (!grub_strcmp (array->name, name))
 | ||
| 	if (grub_is_array_readable (array))
 | ||
| 	  break;
 | ||
|     }
 | ||
| 
 | ||
|   if (!array)
 | ||
|     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
 | ||
|                        name);
 | ||
| 
 | ||
|   disk->has_partitions = 1;
 | ||
|   disk->id = array->number;
 | ||
|   disk->data = array;
 | ||
| 
 | ||
|   grub_dprintf ("raid", "%s: total_devs=%d, disk_size=%lld\n", name,
 | ||
| 		array->total_devs, (unsigned long long) array->disk_size);
 | ||
| 
 | ||
|   switch (array->level)
 | ||
|     {
 | ||
|     case 1:
 | ||
|       disk->total_sectors = array->disk_size;
 | ||
|       break;
 | ||
| 
 | ||
|     case 10:
 | ||
|       n = array->layout & 0xFF;
 | ||
|       if (n == 1)
 | ||
|         n = (array->layout >> 8) & 0xFF;
 | ||
| 
 | ||
|       disk->total_sectors = grub_divmod64 (array->total_devs *
 | ||
|                                            array->disk_size,
 | ||
|                                            n, 0);
 | ||
|       break;
 | ||
| 
 | ||
|     case 0:
 | ||
|     case 4:
 | ||
|     case 5:
 | ||
|     case 6:
 | ||
|       n = array->level / 3;
 | ||
| 
 | ||
|       disk->total_sectors = (array->total_devs - n) * array->disk_size;
 | ||
|       break;
 | ||
|     }
 | ||
| 
 | ||
|   grub_dprintf ("raid", "%s: level=%d, total_sectors=%lld\n", name,
 | ||
| 		array->level, (unsigned long long) disk->total_sectors);
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| grub_raid_close (grub_disk_t disk __attribute ((unused)))
 | ||
| {
 | ||
|   return;
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| grub_raid_block_xor (char *buf1, const char *buf2, int size)
 | ||
| {
 | ||
|   grub_size_t *p1;
 | ||
|   const grub_size_t *p2;
 | ||
| 
 | ||
|   p1 = (grub_size_t *) buf1;
 | ||
|   p2 = (const grub_size_t *) buf2;
 | ||
|   size /= GRUB_CPU_SIZEOF_VOID_P;
 | ||
| 
 | ||
|   while (size)
 | ||
|     {
 | ||
|       *(p1++) ^= *(p2++);
 | ||
|       size--;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| static grub_err_t
 | ||
| grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector,
 | ||
| 		grub_size_t size, char *buf)
 | ||
| {
 | ||
|   struct grub_raid_array *array = disk->data;
 | ||
|   grub_err_t err = 0;
 | ||
| 
 | ||
|   switch (array->level)
 | ||
|     {
 | ||
|     case 0:
 | ||
|     case 1:
 | ||
|     case 10:
 | ||
|       {
 | ||
|         grub_disk_addr_t read_sector, far_ofs;
 | ||
| 	grub_uint32_t disknr, b, near, far, ofs;
 | ||
| 
 | ||
|         read_sector = grub_divmod64 (sector, array->chunk_size, &b);
 | ||
|         far = ofs = near = 1;
 | ||
|         far_ofs = 0;
 | ||
| 
 | ||
|         if (array->level == 1)
 | ||
|           near = array->total_devs;
 | ||
|         else if (array->level == 10)
 | ||
|           {
 | ||
|             near = array->layout & 0xFF;
 | ||
|             far = (array->layout >> 8) & 0xFF;
 | ||
|             if (array->layout >> 16)
 | ||
|               {
 | ||
|                 ofs = far;
 | ||
|                 far_ofs = 1;
 | ||
|               }
 | ||
|             else
 | ||
|               far_ofs = grub_divmod64 (array->disk_size,
 | ||
|                                        far * array->chunk_size, 0);
 | ||
| 
 | ||
|             far_ofs *= array->chunk_size;
 | ||
|           }
 | ||
| 
 | ||
|         read_sector = grub_divmod64 (read_sector * near, array->total_devs,
 | ||
|                                      &disknr);
 | ||
| 
 | ||
|         ofs *= array->chunk_size;
 | ||
|         read_sector *= ofs;
 | ||
| 
 | ||
|         while (1)
 | ||
|           {
 | ||
|             grub_size_t read_size;
 | ||
|             unsigned int i, j;
 | ||
| 
 | ||
|             read_size = array->chunk_size - b;
 | ||
|             if (read_size > size)
 | ||
|               read_size = size;
 | ||
| 
 | ||
|             for (i = 0; i < near; i++)
 | ||
|               {
 | ||
|                 unsigned int k;
 | ||
| 
 | ||
|                 k = disknr;
 | ||
|                 for (j = 0; j < far; j++)
 | ||
|                   {
 | ||
|                     if (array->device[k])
 | ||
|                       {
 | ||
|                         if (grub_errno == GRUB_ERR_READ_ERROR)
 | ||
|                           grub_errno = GRUB_ERR_NONE;
 | ||
| 
 | ||
|                         err = grub_disk_read (array->device[k],
 | ||
|                                               read_sector + j * far_ofs + b,
 | ||
|                                               0,
 | ||
|                                               read_size << GRUB_DISK_SECTOR_BITS,
 | ||
|                                               buf);
 | ||
|                         if (! err)
 | ||
|                           break;
 | ||
|                         else if (err != GRUB_ERR_READ_ERROR)
 | ||
|                           return err;
 | ||
|                       }
 | ||
|                     else
 | ||
|                       err = grub_error (GRUB_ERR_READ_ERROR,
 | ||
|                                         "disk missing");
 | ||
| 
 | ||
|                     k++;
 | ||
|                     if (k == array->total_devs)
 | ||
|                       k = 0;
 | ||
|                   }
 | ||
| 
 | ||
|                 if (! err)
 | ||
|                   break;
 | ||
| 
 | ||
|                 disknr++;
 | ||
|                 if (disknr == array->total_devs)
 | ||
|                   {
 | ||
|                     disknr = 0;
 | ||
|                     read_sector += ofs;
 | ||
|                   }
 | ||
|               }
 | ||
| 
 | ||
|             if (err)
 | ||
|               return err;
 | ||
| 
 | ||
|             buf += read_size << GRUB_DISK_SECTOR_BITS;
 | ||
| 	    size -= read_size;
 | ||
| 	    if (! size)
 | ||
| 	      break;
 | ||
| 
 | ||
|             b = 0;
 | ||
|             disknr += (near - i);
 | ||
|             while (disknr >= array->total_devs)
 | ||
|               {
 | ||
|                 disknr -= array->total_devs;
 | ||
|                 read_sector += ofs;
 | ||
|               }
 | ||
|           }
 | ||
|         break;
 | ||
|       }
 | ||
| 
 | ||
|     case 4:
 | ||
|     case 5:
 | ||
|     case 6:
 | ||
|       {
 | ||
| 	grub_disk_addr_t read_sector;
 | ||
| 	grub_uint32_t b, p, n, disknr, e;
 | ||
| 
 | ||
|         /* n = 1 for level 4 and 5, 2 for level 6.  */
 | ||
|         n = array->level / 3;
 | ||
| 
 | ||
| 	/* Find the first sector to read. */
 | ||
| 	read_sector = grub_divmod64 (sector, array->chunk_size, &b);
 | ||
| 	read_sector = grub_divmod64 (read_sector, array->total_devs - n,
 | ||
|                                      &disknr);
 | ||
|         if (array->level >= 5)
 | ||
|           {
 | ||
|             grub_divmod64 (read_sector, array->total_devs, &p);
 | ||
| 
 | ||
|             if (! (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK))
 | ||
|               p = array->total_devs - 1 - p;
 | ||
| 
 | ||
|             if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
 | ||
|               {
 | ||
|                 disknr += p + n;
 | ||
|               }
 | ||
|             else
 | ||
|               {
 | ||
|                 grub_uint32_t q;
 | ||
| 
 | ||
|                 q = p + (n - 1);
 | ||
|                 if (q >= array->total_devs)
 | ||
|                   q -= array->total_devs;
 | ||
| 
 | ||
|                 if (disknr >= p)
 | ||
|                   disknr += n;
 | ||
|                 else if (disknr >= q)
 | ||
|                   disknr += q + 1;
 | ||
|               }
 | ||
| 
 | ||
|             if (disknr >= array->total_devs)
 | ||
|               disknr -= array->total_devs;
 | ||
|           }
 | ||
|         else
 | ||
|           p = array->total_devs - n;
 | ||
| 
 | ||
| 	read_sector *= array->chunk_size;
 | ||
| 
 | ||
| 	while (1)
 | ||
| 	  {
 | ||
|             grub_size_t read_size;
 | ||
|             int next_level;
 | ||
| 
 | ||
|             read_size = array->chunk_size - b;
 | ||
|             if (read_size > size)
 | ||
|               read_size = size;
 | ||
| 
 | ||
|             e = 0;
 | ||
|             if (array->device[disknr])
 | ||
|               {
 | ||
|                 /* Reset read error.  */
 | ||
|                 if (grub_errno == GRUB_ERR_READ_ERROR)
 | ||
|                   grub_errno = GRUB_ERR_NONE;
 | ||
| 
 | ||
|                 err = grub_disk_read (array->device[disknr],
 | ||
|                                       read_sector + b, 0,
 | ||
|                                       read_size << GRUB_DISK_SECTOR_BITS,
 | ||
|                                       buf);
 | ||
| 
 | ||
|                 if ((err) && (err != GRUB_ERR_READ_ERROR))
 | ||
|                   break;
 | ||
|                 e++;
 | ||
|               }
 | ||
|             else
 | ||
|               err = GRUB_ERR_READ_ERROR;
 | ||
| 
 | ||
| 	    if (err)
 | ||
|               {
 | ||
|                 if (array->nr_devs < array->total_devs - n + e)
 | ||
|                   break;
 | ||
| 
 | ||
|                 grub_errno = GRUB_ERR_NONE;
 | ||
|                 if (array->level == 6)
 | ||
|                   {
 | ||
|                     err = ((grub_raid6_recover_func) ?
 | ||
|                            (*grub_raid6_recover_func) (array, disknr, p,
 | ||
|                                                        buf, read_sector + b,
 | ||
|                                                        read_size) :
 | ||
|                            grub_error (GRUB_ERR_BAD_DEVICE,
 | ||
|                                        "raid6rec is not loaded"));
 | ||
|                   }
 | ||
|                 else
 | ||
|                   {
 | ||
|                     err = ((grub_raid5_recover_func) ?
 | ||
|                            (*grub_raid5_recover_func) (array, disknr,
 | ||
|                                                        buf, read_sector + b,
 | ||
|                                                        read_size) :
 | ||
|                            grub_error (GRUB_ERR_BAD_DEVICE,
 | ||
|                                        "raid5rec is not loaded"));
 | ||
|                   }
 | ||
| 
 | ||
|                 if (err)
 | ||
|                   break;
 | ||
|               }
 | ||
| 
 | ||
| 	    buf += read_size << GRUB_DISK_SECTOR_BITS;
 | ||
| 	    size -= read_size;
 | ||
| 	    if (! size)
 | ||
| 	      break;
 | ||
| 
 | ||
|             b = 0;
 | ||
| 	    disknr++;
 | ||
| 
 | ||
|             if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
 | ||
|               {
 | ||
|                 if (disknr == array->total_devs)
 | ||
|                   disknr = 0;
 | ||
| 
 | ||
|                 next_level = (disknr == p);
 | ||
|               }
 | ||
|             else
 | ||
|               {
 | ||
|                 if (disknr == p)
 | ||
|                   disknr += n;
 | ||
| 
 | ||
|                 next_level = (disknr >= array->total_devs);
 | ||
|               }
 | ||
| 
 | ||
|             if (next_level)
 | ||
|               {
 | ||
|                 read_sector += array->chunk_size;
 | ||
| 
 | ||
|                 if (array->level >= 5)
 | ||
|                   {
 | ||
|                     if (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK)
 | ||
|                       p = (p == array->total_devs - 1) ? 0 : p + 1;
 | ||
|                     else
 | ||
|                       p = (p == 0) ? array->total_devs - 1 : p - 1;
 | ||
| 
 | ||
|                     if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
 | ||
|                       {
 | ||
|                         disknr = p + n;
 | ||
|                         if (disknr >= array->total_devs)
 | ||
|                           disknr -= array->total_devs;
 | ||
|                       }
 | ||
|                     else
 | ||
|                       {
 | ||
|                         disknr -= array->total_devs;
 | ||
|                         if (disknr == p)
 | ||
|                           disknr += n;
 | ||
|                       }
 | ||
|                   }
 | ||
|                 else
 | ||
|                   disknr = 0;
 | ||
|               }
 | ||
| 	  }
 | ||
|       }
 | ||
|       break;
 | ||
|     }
 | ||
| 
 | ||
|   return err;
 | ||
| }
 | ||
| 
 | ||
| static grub_err_t
 | ||
| grub_raid_write (grub_disk_t disk __attribute ((unused)),
 | ||
| 		 grub_disk_addr_t sector __attribute ((unused)),
 | ||
| 		 grub_size_t size __attribute ((unused)),
 | ||
| 		 const char *buf __attribute ((unused)))
 | ||
| {
 | ||
|   return GRUB_ERR_NOT_IMPLEMENTED_YET;
 | ||
| }
 | ||
| 
 | ||
| static grub_err_t
 | ||
| insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
 | ||
|               const char *scanner_name)
 | ||
| {
 | ||
|   struct grub_raid_array *array = 0, *p;
 | ||
| 
 | ||
|   /* See whether the device is part of an array we have already seen a
 | ||
|      device from. */
 | ||
|   for (p = array_list; p != NULL; p = p->next)
 | ||
|     if ((p->uuid_len == new_array->uuid_len) &&
 | ||
|         (! grub_memcmp (p->uuid, new_array->uuid, p->uuid_len)))
 | ||
|       {
 | ||
|         grub_free (new_array->uuid);
 | ||
|         array = p;
 | ||
| 
 | ||
|         /* Do some checks before adding the device to the array.  */
 | ||
| 
 | ||
|         /* FIXME: Check whether the update time of the superblocks are
 | ||
|            the same. */
 | ||
| 
 | ||
|         if (array->total_devs == array->nr_devs)
 | ||
|           /* We found more members of the array than the array
 | ||
|              actually has according to its superblock.  This shouldn't
 | ||
|              happen normally.  */
 | ||
|           grub_dprintf ("raid", "array->nr_devs > array->total_devs (%d)?!?",
 | ||
| 			array->total_devs);
 | ||
| 
 | ||
|         if (array->device[new_array->index] != NULL)
 | ||
|           /* We found multiple devices with the same number. Again,
 | ||
|              this shouldn't happen.*/
 | ||
|           grub_dprintf ("raid", "Found two disks with the number %d?!?",
 | ||
| 			new_array->number);
 | ||
| 
 | ||
|         if (new_array->disk_size < array->disk_size)
 | ||
|           array->disk_size = new_array->disk_size;
 | ||
|         break;
 | ||
|       }
 | ||
| 
 | ||
|   /* Add an array to the list if we didn't find any.  */
 | ||
|   if (!array)
 | ||
|     {
 | ||
|       array = grub_malloc (sizeof (*array));
 | ||
|       if (!array)
 | ||
|         {
 | ||
|           grub_free (new_array->uuid);
 | ||
|           return grub_errno;
 | ||
|         }
 | ||
| 
 | ||
|       *array = *new_array;
 | ||
|       array->nr_devs = 0;
 | ||
|       grub_memset (&array->device, 0, sizeof (array->device));
 | ||
| 
 | ||
|       /* Check whether we don't have multiple arrays with the same number. */
 | ||
|       for (p = array_list; p != NULL; p = p->next)
 | ||
|         {
 | ||
|           if (p->number == array->number)
 | ||
|             break;
 | ||
|         }
 | ||
| 
 | ||
|       if (p)
 | ||
|         {
 | ||
|           /* The number is already in use, so we need to find an new number. */
 | ||
|           int i = 0;
 | ||
| 
 | ||
|           while (1)
 | ||
|             {
 | ||
|               for (p = array_list; p != NULL; p = p->next)
 | ||
|                 {
 | ||
|                   if (p->number == i)
 | ||
|                     break;
 | ||
|                 }
 | ||
| 
 | ||
|               if (!p)
 | ||
|                 {
 | ||
|                   /* We found an unused number.  */
 | ||
|                   array->number = i;
 | ||
|                   break;
 | ||
|                 }
 | ||
| 
 | ||
|               i++;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|       array->name = grub_xasprintf ("md%d", array->number);
 | ||
|       if (! array->name)
 | ||
|         {
 | ||
|           grub_free (array->uuid);
 | ||
|           grub_free (array);
 | ||
| 
 | ||
|           return grub_errno;
 | ||
|         }
 | ||
| 
 | ||
|       grub_dprintf ("raid", "Found array %s (%s)\n", array->name,
 | ||
|                     scanner_name);
 | ||
| 
 | ||
|       /* Add our new array to the list.  */
 | ||
|       array->next = array_list;
 | ||
|       array_list = array;
 | ||
| 
 | ||
|       /* RAID 1 doesn't use a chunksize but code assumes one so set
 | ||
| 	 one. */
 | ||
|       if (array->level == 1)
 | ||
| 	array->chunk_size = 64;
 | ||
|     }
 | ||
| 
 | ||
|   /* Add the device to the array. */
 | ||
|   array->device[new_array->index] = disk;
 | ||
|   array->nr_devs++;
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| static grub_raid_t grub_raid_list;
 | ||
| 
 | ||
| static void
 | ||
| free_array (void)
 | ||
| {
 | ||
|   struct grub_raid_array *array;
 | ||
| 
 | ||
|   array = array_list;
 | ||
|   while (array)
 | ||
|     {
 | ||
|       struct grub_raid_array *p;
 | ||
|       int i;
 | ||
| 
 | ||
|       p = array;
 | ||
|       array = array->next;
 | ||
| 
 | ||
|       for (i = 0; i < GRUB_RAID_MAX_DEVICES; i++)
 | ||
|         if (p->device[i])
 | ||
|           grub_disk_close (p->device[i]);
 | ||
| 
 | ||
|       grub_free (p->uuid);
 | ||
|       grub_free (p->name);
 | ||
|       grub_free (p);
 | ||
|     }
 | ||
| 
 | ||
|   array_list = 0;
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| grub_raid_register (grub_raid_t raid)
 | ||
| {
 | ||
|   auto int hook (const char *name);
 | ||
|   int hook (const char *name)
 | ||
|     {
 | ||
|       grub_disk_t disk;
 | ||
|       struct grub_raid_array array;
 | ||
| 
 | ||
|       grub_dprintf ("raid", "Scanning for RAID devices on disk %s\n", name);
 | ||
| 
 | ||
|       disk = grub_disk_open (name);
 | ||
|       if (!disk)
 | ||
|         return 0;
 | ||
| 
 | ||
|       if ((disk->total_sectors != GRUB_ULONG_MAX) &&
 | ||
| 	  (! grub_raid_list->detect (disk, &array)) &&
 | ||
| 	  (! insert_array (disk, &array, grub_raid_list->name)))
 | ||
| 	return 0;
 | ||
| 
 | ||
|       /* This error usually means it's not raid, no need to display
 | ||
| 	 it.  */
 | ||
|       if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
 | ||
| 	grub_print_error ();
 | ||
| 
 | ||
|       grub_errno = GRUB_ERR_NONE;
 | ||
| 
 | ||
|       grub_disk_close (disk);
 | ||
| 
 | ||
|       return 0;
 | ||
|     }
 | ||
| 
 | ||
|   raid->next = grub_raid_list;
 | ||
|   grub_raid_list = raid;
 | ||
|   grub_device_iterate (&hook);
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| grub_raid_unregister (grub_raid_t raid)
 | ||
| {
 | ||
|   grub_raid_t *p, q;
 | ||
| 
 | ||
|   for (p = &grub_raid_list, q = *p; q; p = &(q->next), q = q->next)
 | ||
|     if (q == raid)
 | ||
|       {
 | ||
| 	*p = q->next;
 | ||
| 	break;
 | ||
|       }
 | ||
| }
 | ||
| 
 | ||
| static struct grub_disk_dev grub_raid_dev =
 | ||
|   {
 | ||
|     .name = "raid",
 | ||
|     .id = GRUB_DISK_DEVICE_RAID_ID,
 | ||
|     .iterate = grub_raid_iterate,
 | ||
|     .open = grub_raid_open,
 | ||
|     .close = grub_raid_close,
 | ||
|     .read = grub_raid_read,
 | ||
|     .write = grub_raid_write,
 | ||
| #ifdef GRUB_UTIL
 | ||
|     .memberlist = grub_raid_memberlist,
 | ||
| #endif
 | ||
|     .next = 0
 | ||
|   };
 | ||
| 
 | ||
| 
 | ||
| GRUB_MOD_INIT(raid)
 | ||
| {
 | ||
|   grub_disk_dev_register (&grub_raid_dev);
 | ||
| }
 | ||
| 
 | ||
| GRUB_MOD_FINI(raid)
 | ||
| {
 | ||
|   grub_disk_dev_unregister (&grub_raid_dev);
 | ||
|   free_array ();
 | ||
| }
 | 
