~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

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