~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to disk/raid.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* raid.c - module to read RAID arrays.  */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
5
 
 *
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.
10
 
 *
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.
15
 
 *
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/>.
18
 
 */
19
 
 
20
 
#include <grub/dl.h>
21
 
#include <grub/disk.h>
22
 
#include <grub/mm.h>
23
 
#include <grub/err.h>
24
 
#include <grub/misc.h>
25
 
#include <grub/raid.h>
26
 
 
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;
31
 
 
32
 
 
33
 
static char
34
 
grub_is_array_readable (struct grub_raid_array *array)
35
 
{
36
 
  switch (array->level)
37
 
    {
38
 
    case 0:
39
 
      if (array->nr_devs == array->total_devs)
40
 
        return 1;
41
 
      break;
42
 
 
43
 
    case 1:
44
 
      if (array->nr_devs >= 1)
45
 
        return 1;
46
 
      break;
47
 
 
48
 
    case 4:
49
 
    case 5:
50
 
    case 6:
51
 
    case 10:
52
 
      {
53
 
        unsigned int n;
54
 
 
55
 
        if (array->level == 10)
56
 
          {
57
 
            n = array->layout & 0xFF;
58
 
            if (n == 1)
59
 
              n = (array->layout >> 8) & 0xFF;
60
 
 
61
 
            n--;
62
 
          }
63
 
        else
64
 
          n = array->level / 3;
65
 
 
66
 
        if (array->nr_devs >= array->total_devs - n)
67
 
          return 1;
68
 
 
69
 
        break;
70
 
      }
71
 
    }
72
 
 
73
 
  return 0;
74
 
}
75
 
 
76
 
static int
77
 
grub_raid_iterate (int (*hook) (const char *name))
78
 
{
79
 
  struct grub_raid_array *array;
80
 
 
81
 
  for (array = array_list; array != NULL; array = array->next)
82
 
    {
83
 
      if (grub_is_array_readable (array))
84
 
        if (hook (array->name))
85
 
          return 1;
86
 
    }
87
 
 
88
 
  return 0;
89
 
}
90
 
 
91
 
#ifdef GRUB_UTIL
92
 
static grub_disk_memberlist_t
93
 
grub_raid_memberlist (grub_disk_t disk)
94
 
{
95
 
  struct grub_raid_array *array = disk->data;
96
 
  grub_disk_memberlist_t list = NULL, tmp;
97
 
  unsigned int i;
98
 
 
99
 
  for (i = 0; i < array->total_devs; i++)
100
 
    if (array->device[i])
101
 
      {
102
 
        tmp = grub_malloc (sizeof (*tmp));
103
 
        tmp->disk = array->device[i];
104
 
        tmp->next = list;
105
 
        list = tmp;
106
 
      }
107
 
 
108
 
  return list;
109
 
}
110
 
#endif
111
 
 
112
 
static grub_err_t
113
 
grub_raid_open (const char *name, grub_disk_t disk)
114
 
{
115
 
  struct grub_raid_array *array;
116
 
  unsigned n;
117
 
 
118
 
  for (array = array_list; array != NULL; array = array->next)
119
 
    {
120
 
      if (!grub_strcmp (array->name, name))
121
 
        if (grub_is_array_readable (array))
122
 
          break;
123
 
    }
124
 
 
125
 
  if (!array)
126
 
    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
127
 
                       name);
128
 
 
129
 
  disk->has_partitions = 1;
130
 
  disk->id = array->number;
131
 
  disk->data = array;
132
 
 
133
 
  grub_dprintf ("raid", "%s: total_devs=%d, disk_size=%lld\n", name,
134
 
                array->total_devs, (unsigned long long) array->disk_size);
135
 
 
136
 
  switch (array->level)
137
 
    {
138
 
    case 1:
139
 
      disk->total_sectors = array->disk_size;
140
 
      break;
141
 
 
142
 
    case 10:
143
 
      n = array->layout & 0xFF;
144
 
      if (n == 1)
145
 
        n = (array->layout >> 8) & 0xFF;
146
 
 
147
 
      disk->total_sectors = grub_divmod64 (array->total_devs *
148
 
                                           array->disk_size,
149
 
                                           n, 0);
150
 
      break;
151
 
 
152
 
    case 0:
153
 
    case 4:
154
 
    case 5:
155
 
    case 6:
156
 
      n = array->level / 3;
157
 
 
158
 
      disk->total_sectors = (array->total_devs - n) * array->disk_size;
159
 
      break;
160
 
    }
161
 
 
162
 
  grub_dprintf ("raid", "%s: level=%d, total_sectors=%lld\n", name,
163
 
                array->level, (unsigned long long) disk->total_sectors);
164
 
 
165
 
  return 0;
166
 
}
167
 
 
168
 
static void
169
 
grub_raid_close (grub_disk_t disk __attribute ((unused)))
170
 
{
171
 
  return;
172
 
}
173
 
 
174
 
void
175
 
grub_raid_block_xor (char *buf1, const char *buf2, int size)
176
 
{
177
 
  grub_size_t *p1;
178
 
  const grub_size_t *p2;
179
 
 
180
 
  p1 = (grub_size_t *) buf1;
181
 
  p2 = (const grub_size_t *) buf2;
182
 
  size /= GRUB_CPU_SIZEOF_VOID_P;
183
 
 
184
 
  while (size)
185
 
    {
186
 
      *(p1++) ^= *(p2++);
187
 
      size--;
188
 
    }
189
 
}
190
 
 
191
 
static grub_err_t
192
 
grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector,
193
 
                grub_size_t size, char *buf)
194
 
{
195
 
  struct grub_raid_array *array = disk->data;
196
 
  grub_err_t err = 0;
197
 
 
198
 
  switch (array->level)
199
 
    {
200
 
    case 0:
201
 
    case 1:
202
 
    case 10:
203
 
      {
204
 
        grub_disk_addr_t read_sector, far_ofs;
205
 
        grub_uint32_t disknr, b, near, far, ofs;
206
 
 
207
 
        read_sector = grub_divmod64 (sector, array->chunk_size, &b);
208
 
        far = ofs = near = 1;
209
 
        far_ofs = 0;
210
 
 
211
 
        if (array->level == 1)
212
 
          near = array->total_devs;
213
 
        else if (array->level == 10)
214
 
          {
215
 
            near = array->layout & 0xFF;
216
 
            far = (array->layout >> 8) & 0xFF;
217
 
            if (array->layout >> 16)
218
 
              {
219
 
                ofs = far;
220
 
                far_ofs = 1;
221
 
              }
222
 
            else
223
 
              far_ofs = grub_divmod64 (array->disk_size,
224
 
                                       far * array->chunk_size, 0);
225
 
 
226
 
            far_ofs *= array->chunk_size;
227
 
          }
228
 
 
229
 
        read_sector = grub_divmod64 (read_sector * near, array->total_devs,
230
 
                                     &disknr);
231
 
 
232
 
        ofs *= array->chunk_size;
233
 
        read_sector *= ofs;
234
 
 
235
 
        while (1)
236
 
          {
237
 
            grub_size_t read_size;
238
 
            unsigned int i, j;
239
 
 
240
 
            read_size = array->chunk_size - b;
241
 
            if (read_size > size)
242
 
              read_size = size;
243
 
 
244
 
            for (i = 0; i < near; i++)
245
 
              {
246
 
                unsigned int k;
247
 
 
248
 
                k = disknr;
249
 
                for (j = 0; j < far; j++)
250
 
                  {
251
 
                    if (array->device[k])
252
 
                      {
253
 
                        if (grub_errno == GRUB_ERR_READ_ERROR)
254
 
                          grub_errno = GRUB_ERR_NONE;
255
 
 
256
 
                        err = grub_disk_read (array->device[k],
257
 
                                              array->start_sector[k] +
258
 
                                                read_sector + j * far_ofs + b,
259
 
                                              0,
260
 
                                              read_size << GRUB_DISK_SECTOR_BITS,
261
 
                                              buf);
262
 
                        if (! err)
263
 
                          break;
264
 
                        else if (err != GRUB_ERR_READ_ERROR)
265
 
                          return err;
266
 
                      }
267
 
                    else
268
 
                      err = grub_error (GRUB_ERR_READ_ERROR,
269
 
                                        "disk missing");
270
 
 
271
 
                    k++;
272
 
                    if (k == array->total_devs)
273
 
                      k = 0;
274
 
                  }
275
 
 
276
 
                if (! err)
277
 
                  break;
278
 
 
279
 
                disknr++;
280
 
                if (disknr == array->total_devs)
281
 
                  {
282
 
                    disknr = 0;
283
 
                    read_sector += ofs;
284
 
                  }
285
 
              }
286
 
 
287
 
            if (err)
288
 
              return err;
289
 
 
290
 
            buf += read_size << GRUB_DISK_SECTOR_BITS;
291
 
            size -= read_size;
292
 
            if (! size)
293
 
              break;
294
 
 
295
 
            b = 0;
296
 
            disknr += (near - i);
297
 
            while (disknr >= array->total_devs)
298
 
              {
299
 
                disknr -= array->total_devs;
300
 
                read_sector += ofs;
301
 
              }
302
 
          }
303
 
        break;
304
 
      }
305
 
 
306
 
    case 4:
307
 
    case 5:
308
 
    case 6:
309
 
      {
310
 
        grub_disk_addr_t read_sector;
311
 
        grub_uint32_t b, p, n, disknr, e;
312
 
 
313
 
        /* n = 1 for level 4 and 5, 2 for level 6.  */
314
 
        n = array->level / 3;
315
 
 
316
 
        /* Find the first sector to read. */
317
 
        read_sector = grub_divmod64 (sector, array->chunk_size, &b);
318
 
        read_sector = grub_divmod64 (read_sector, array->total_devs - n,
319
 
                                     &disknr);
320
 
        if (array->level >= 5)
321
 
          {
322
 
            grub_divmod64 (read_sector, array->total_devs, &p);
323
 
 
324
 
            if (! (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK))
325
 
              p = array->total_devs - 1 - p;
326
 
 
327
 
            if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
328
 
              {
329
 
                disknr += p + n;
330
 
              }
331
 
            else
332
 
              {
333
 
                grub_uint32_t q;
334
 
 
335
 
                q = p + (n - 1);
336
 
                if (q >= array->total_devs)
337
 
                  q -= array->total_devs;
338
 
 
339
 
                if (disknr >= p)
340
 
                  disknr += n;
341
 
                else if (disknr >= q)
342
 
                  disknr += q + 1;
343
 
              }
344
 
 
345
 
            if (disknr >= array->total_devs)
346
 
              disknr -= array->total_devs;
347
 
          }
348
 
        else
349
 
          p = array->total_devs - n;
350
 
 
351
 
        read_sector *= array->chunk_size;
352
 
 
353
 
        while (1)
354
 
          {
355
 
            grub_size_t read_size;
356
 
            int next_level;
357
 
 
358
 
            read_size = array->chunk_size - b;
359
 
            if (read_size > size)
360
 
              read_size = size;
361
 
 
362
 
            e = 0;
363
 
            if (array->device[disknr])
364
 
              {
365
 
                /* Reset read error.  */
366
 
                if (grub_errno == GRUB_ERR_READ_ERROR)
367
 
                  grub_errno = GRUB_ERR_NONE;
368
 
 
369
 
                err = grub_disk_read (array->device[disknr],
370
 
                                      array->start_sector[disknr] +
371
 
                                        read_sector + b, 0,
372
 
                                      read_size << GRUB_DISK_SECTOR_BITS,
373
 
                                      buf);
374
 
 
375
 
                if ((err) && (err != GRUB_ERR_READ_ERROR))
376
 
                  break;
377
 
                e++;
378
 
              }
379
 
            else
380
 
              err = GRUB_ERR_READ_ERROR;
381
 
 
382
 
            if (err)
383
 
              {
384
 
                if (array->nr_devs < array->total_devs - n + e)
385
 
                  break;
386
 
 
387
 
                grub_errno = GRUB_ERR_NONE;
388
 
                if (array->level == 6)
389
 
                  {
390
 
                    err = ((grub_raid6_recover_func) ?
391
 
                           (*grub_raid6_recover_func) (array, disknr, p,
392
 
                                                       buf, read_sector + b,
393
 
                                                       read_size) :
394
 
                           grub_error (GRUB_ERR_BAD_DEVICE,
395
 
                                       "raid6rec is not loaded"));
396
 
                  }
397
 
                else
398
 
                  {
399
 
                    err = ((grub_raid5_recover_func) ?
400
 
                           (*grub_raid5_recover_func) (array, disknr,
401
 
                                                       buf, read_sector + b,
402
 
                                                       read_size) :
403
 
                           grub_error (GRUB_ERR_BAD_DEVICE,
404
 
                                       "raid5rec is not loaded"));
405
 
                  }
406
 
 
407
 
                if (err)
408
 
                  break;
409
 
              }
410
 
 
411
 
            buf += read_size << GRUB_DISK_SECTOR_BITS;
412
 
            size -= read_size;
413
 
            if (! size)
414
 
              break;
415
 
 
416
 
            b = 0;
417
 
            disknr++;
418
 
 
419
 
            if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
420
 
              {
421
 
                if (disknr == array->total_devs)
422
 
                  disknr = 0;
423
 
 
424
 
                next_level = (disknr == p);
425
 
              }
426
 
            else
427
 
              {
428
 
                if (disknr == p)
429
 
                  disknr += n;
430
 
 
431
 
                next_level = (disknr >= array->total_devs);
432
 
              }
433
 
 
434
 
            if (next_level)
435
 
              {
436
 
                read_sector += array->chunk_size;
437
 
 
438
 
                if (array->level >= 5)
439
 
                  {
440
 
                    if (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK)
441
 
                      p = (p == array->total_devs - 1) ? 0 : p + 1;
442
 
                    else
443
 
                      p = (p == 0) ? array->total_devs - 1 : p - 1;
444
 
 
445
 
                    if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
446
 
                      {
447
 
                        disknr = p + n;
448
 
                        if (disknr >= array->total_devs)
449
 
                          disknr -= array->total_devs;
450
 
                      }
451
 
                    else
452
 
                      {
453
 
                        disknr -= array->total_devs;
454
 
                        if (disknr == p)
455
 
                          disknr += n;
456
 
                      }
457
 
                  }
458
 
                else
459
 
                  disknr = 0;
460
 
              }
461
 
          }
462
 
      }
463
 
      break;
464
 
    }
465
 
 
466
 
  return err;
467
 
}
468
 
 
469
 
static grub_err_t
470
 
grub_raid_write (grub_disk_t disk __attribute ((unused)),
471
 
                 grub_disk_addr_t sector __attribute ((unused)),
472
 
                 grub_size_t size __attribute ((unused)),
473
 
                 const char *buf __attribute ((unused)))
474
 
{
475
 
  return GRUB_ERR_NOT_IMPLEMENTED_YET;
476
 
}
477
 
 
478
 
static grub_err_t
479
 
insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
480
 
              grub_disk_addr_t start_sector, const char *scanner_name)
481
 
{
482
 
  struct grub_raid_array *array = 0, *p;
483
 
 
484
 
  /* See whether the device is part of an array we have already seen a
485
 
     device from.  */
486
 
  for (p = array_list; p != NULL; p = p->next)
487
 
    if ((p->uuid_len == new_array->uuid_len) &&
488
 
        (! grub_memcmp (p->uuid, new_array->uuid, p->uuid_len)))
489
 
      {
490
 
        grub_free (new_array->uuid);
491
 
        array = p;
492
 
 
493
 
        /* Do some checks before adding the device to the array.  */
494
 
 
495
 
        /* FIXME: Check whether the update time of the superblocks are
496
 
           the same.  */
497
 
 
498
 
        if (array->total_devs == array->nr_devs)
499
 
          /* We found more members of the array than the array
500
 
             actually has according to its superblock.  This shouldn't
501
 
             happen normally.  */
502
 
          grub_dprintf ("raid", "array->nr_devs > array->total_devs (%d)?!?",
503
 
                        array->total_devs);
504
 
 
505
 
        if (array->device[new_array->index] != NULL)
506
 
          /* We found multiple devices with the same number. Again,
507
 
             this shouldn't happen.  */
508
 
          grub_dprintf ("raid", "Found two disks with the number %d?!?",
509
 
                        new_array->number);
510
 
 
511
 
        if (new_array->disk_size < array->disk_size)
512
 
          array->disk_size = new_array->disk_size;
513
 
        break;
514
 
      }
515
 
 
516
 
  /* Add an array to the list if we didn't find any.  */
517
 
  if (!array)
518
 
    {
519
 
      array = grub_malloc (sizeof (*array));
520
 
      if (!array)
521
 
        {
522
 
          grub_free (new_array->uuid);
523
 
          return grub_errno;
524
 
        }
525
 
 
526
 
      *array = *new_array;
527
 
      array->nr_devs = 0;
528
 
      grub_memset (&array->device, 0, sizeof (array->device));
529
 
      grub_memset (&array->start_sector, 0, sizeof (array->start_sector));
530
 
 
531
 
      if (! array->name)
532
 
        {
533
 
          for (p = array_list; p != NULL; p = p->next)
534
 
            {
535
 
              if (! p->name && p->number == array->number) 
536
 
                break;
537
 
            }
538
 
        }
539
 
 
540
 
      if (array->name || p)
541
 
        {
542
 
          /* The number is already in use, so we need to find a new one.
543
 
             (Or, in the case of named arrays, the array doesn't have its
544
 
             own number, but we need one that doesn't clash for use as a key
545
 
             in the disk cache.  */
546
 
          int i = array->name ? 0x40000000 : 0;
547
 
 
548
 
          while (1)
549
 
            {
550
 
              for (p = array_list; p != NULL; p = p->next)
551
 
                {
552
 
                  if (p->number == i)
553
 
                    break;
554
 
                }
555
 
 
556
 
              if (! p)
557
 
                {
558
 
                  /* We found an unused number.  */
559
 
                  array->number = i;
560
 
                  break;
561
 
                }
562
 
 
563
 
              i++;
564
 
            }
565
 
        }
566
 
 
567
 
      /* mdraid 1.x superblocks have only a name stored not a number.
568
 
         Use it directly as GRUB device.  */
569
 
      if (! array->name)
570
 
        {
571
 
          array->name = grub_xasprintf ("md%d", array->number);
572
 
          if (! array->name)
573
 
            {
574
 
              grub_free (array->uuid);
575
 
              grub_free (array);
576
 
 
577
 
              return grub_errno;
578
 
            }
579
 
        }
580
 
      else
581
 
        {
582
 
          /* Strip off the homehost if present.  */
583
 
          char *colon = grub_strchr (array->name, ':');
584
 
          char *new_name = grub_xasprintf ("md/%s",
585
 
                                           colon ? colon + 1 : array->name);
586
 
 
587
 
          if (! new_name)
588
 
            {
589
 
              grub_free (array->uuid);
590
 
              grub_free (array);
591
 
 
592
 
              return grub_errno;
593
 
            }
594
 
 
595
 
          grub_free (array->name);
596
 
          array->name = new_name;
597
 
        }
598
 
 
599
 
      grub_dprintf ("raid", "Found array %s (%s)\n", array->name,
600
 
                    scanner_name);
601
 
 
602
 
      /* Add our new array to the list.  */
603
 
      array->next = array_list;
604
 
      array_list = array;
605
 
 
606
 
      /* RAID 1 doesn't use a chunksize but code assumes one so set
607
 
         one. */
608
 
      if (array->level == 1)
609
 
        array->chunk_size = 64;
610
 
    }
611
 
 
612
 
  /* Add the device to the array. */
613
 
  array->device[new_array->index] = disk;
614
 
  array->start_sector[new_array->index] = start_sector;
615
 
  array->nr_devs++;
616
 
 
617
 
  return 0;
618
 
}
619
 
 
620
 
static grub_raid_t grub_raid_list;
621
 
 
622
 
static void
623
 
free_array (void)
624
 
{
625
 
  struct grub_raid_array *array;
626
 
 
627
 
  array = array_list;
628
 
  while (array)
629
 
    {
630
 
      struct grub_raid_array *p;
631
 
      int i;
632
 
 
633
 
      p = array;
634
 
      array = array->next;
635
 
 
636
 
      for (i = 0; i < GRUB_RAID_MAX_DEVICES; i++)
637
 
        if (p->device[i])
638
 
          grub_disk_close (p->device[i]);
639
 
 
640
 
      grub_free (p->uuid);
641
 
      grub_free (p->name);
642
 
      grub_free (p);
643
 
    }
644
 
 
645
 
  array_list = 0;
646
 
}
647
 
 
648
 
void
649
 
grub_raid_register (grub_raid_t raid)
650
 
{
651
 
  auto int hook (const char *name);
652
 
  int hook (const char *name)
653
 
    {
654
 
      grub_disk_t disk;
655
 
      struct grub_raid_array array;
656
 
      grub_disk_addr_t start_sector;
657
 
 
658
 
      grub_dprintf ("raid", "Scanning for RAID devices on disk %s\n", name);
659
 
 
660
 
      disk = grub_disk_open (name);
661
 
      if (!disk)
662
 
        return 0;
663
 
 
664
 
      if ((disk->total_sectors != GRUB_ULONG_MAX) &&
665
 
          (! grub_raid_list->detect (disk, &array, &start_sector)) &&
666
 
          (! insert_array (disk, &array, start_sector, grub_raid_list->name)))
667
 
        return 0;
668
 
 
669
 
      /* This error usually means it's not raid, no need to display
670
 
         it.  */
671
 
      if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
672
 
        grub_print_error ();
673
 
 
674
 
      grub_errno = GRUB_ERR_NONE;
675
 
 
676
 
      grub_disk_close (disk);
677
 
 
678
 
      return 0;
679
 
    }
680
 
 
681
 
  raid->next = grub_raid_list;
682
 
  grub_raid_list = raid;
683
 
  grub_device_iterate (&hook);
684
 
}
685
 
 
686
 
void
687
 
grub_raid_unregister (grub_raid_t raid)
688
 
{
689
 
  grub_raid_t *p, q;
690
 
 
691
 
  for (p = &grub_raid_list, q = *p; q; p = &(q->next), q = q->next)
692
 
    if (q == raid)
693
 
      {
694
 
        *p = q->next;
695
 
        break;
696
 
      }
697
 
}
698
 
 
699
 
static struct grub_disk_dev grub_raid_dev =
700
 
  {
701
 
    .name = "raid",
702
 
    .id = GRUB_DISK_DEVICE_RAID_ID,
703
 
    .iterate = grub_raid_iterate,
704
 
    .open = grub_raid_open,
705
 
    .close = grub_raid_close,
706
 
    .read = grub_raid_read,
707
 
    .write = grub_raid_write,
708
 
#ifdef GRUB_UTIL
709
 
    .memberlist = grub_raid_memberlist,
710
 
#endif
711
 
    .next = 0
712
 
  };
713
 
 
714
 
 
715
 
GRUB_MOD_INIT(raid)
716
 
{
717
 
  grub_disk_dev_register (&grub_raid_dev);
718
 
}
719
 
 
720
 
GRUB_MOD_FINI(raid)
721
 
{
722
 
  grub_disk_dev_unregister (&grub_raid_dev);
723
 
  free_array ();
724
 
}