~ubuntu-branches/ubuntu/dapper/mdadm/dapper

« back to all changes in this revision

Viewing changes to {arch}/++pristine-trees/unlocked/mdadm/mdadm--upstream/mdadm--upstream--1.12.0/pkg-mdadm-devel@lists.alioth.debian.org--2005/mdadm--upstream--1.12.0--patch-1/Assemble.c

  • Committer: Package Import Robot
  • Author(s): Fabio M. Di Nitto
  • Date: 2005-11-28 07:35:36 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20051128073536-ph8pstb6ams9huk4
Tags: 1.12.0-1ubuntu1
Resyncronize with Debian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * mdadm - manage Linux "md" devices aka RAID arrays.
 
3
 *
 
4
 * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
 
5
 *
 
6
 *
 
7
 *    This program is free software; you can redistribute it and/or modify
 
8
 *    it under the terms of the GNU General Public License as published by
 
9
 *    the Free Software Foundation; either version 2 of the License, or
 
10
 *    (at your option) any later version.
 
11
 *
 
12
 *    This program is distributed in the hope that it will be useful,
 
13
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 *    GNU General Public License for more details.
 
16
 *
 
17
 *    You should have received a copy of the GNU General Public License
 
18
 *    along with this program; if not, write to the Free Software
 
19
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
20
 *
 
21
 *    Author: Neil Brown
 
22
 *    Email: <neilb@cse.unsw.edu.au>
 
23
 *    Paper: Neil Brown
 
24
 *           School of Computer Science and Engineering
 
25
 *           The University of New South Wales
 
26
 *           Sydney, 2052
 
27
 *           Australia
 
28
 */
 
29
 
 
30
#include        "mdadm.h"
 
31
#include        "md_u.h"
 
32
#include        "md_p.h"
 
33
 
 
34
int Assemble(char *mddev, int mdfd,
 
35
             mddev_ident_t ident, char *conffile,
 
36
             mddev_dev_t devlist,
 
37
             int readonly, int runstop,
 
38
             char *update,
 
39
             int verbose, int force)
 
40
{
 
41
        /*
 
42
         * The task of Assemble is to find a collection of
 
43
         * devices that should (according to their superblocks)
 
44
         * form an array, and to give this collection to the MD driver.
 
45
         * In Linux-2.4 and later, this involves submitting a
 
46
         * SET_ARRAY_INFO ioctl with no arg - to prepare
 
47
         * the array - and then submit a number of
 
48
         * ADD_NEW_DISK ioctls to add disks into
 
49
         * the array.  Finally RUN_ARRAY might
 
50
         * be submitted to start the array.
 
51
         *
 
52
         * Much of the work of Assemble is in finding and/or
 
53
         * checking the disks to make sure they look right.
 
54
         *
 
55
         * If mddev is not set, then scan must be and we
 
56
         *  read through the config file for dev+uuid mapping
 
57
         *  We recurse, setting mddev, for each device that
 
58
         *    - isn't running
 
59
         *    - has a valid uuid (or any uuid if !uuidset
 
60
         *
 
61
         * If mddev is set, we try to determine state of md.
 
62
         *   check version - must be at least 0.90.0
 
63
         *   check kernel version.  must be at least 2.4.
 
64
         *    If not, we can possibly fall back on START_ARRAY
 
65
         *   Try to GET_ARRAY_INFO.
 
66
         *     If possible, give up
 
67
         *     If not, try to STOP_ARRAY just to make sure
 
68
         *
 
69
         * If !uuidset and scan, look in conf-file for uuid
 
70
         *       If not found, give up
 
71
         * If !devlist and scan and uuidset, get list of devs from conf-file 
 
72
         *
 
73
         * For each device:
 
74
         *   Check superblock - discard if bad
 
75
         *   Check uuid (set if we don't have one) - discard if no match
 
76
         *   Check superblock similarity if we have a superblock - discard if different
 
77
         *   Record events, devicenum, utime
 
78
         * This should give us a list of devices for the array
 
79
         * We should collect the most recent event and utime numbers
 
80
         *
 
81
         * Count disks with recent enough event count
 
82
         * While force && !enough disks
 
83
         *    Choose newest rejected disks, update event count
 
84
         *     mark clean and rewrite superblock
 
85
         * If recent kernel:
 
86
         *    SET_ARRAY_INFO
 
87
         *    foreach device with recent events : ADD_NEW_DISK
 
88
         *    if runstop == 1 || "enough" disks and runstop==0 -> RUN_ARRAY
 
89
         * If old kernel:
 
90
         *    Check the device numbers in superblock are right
 
91
         *    update superblock if any changes
 
92
         *    START_ARRAY
 
93
         *
 
94
         */
 
95
        int old_linux = 0;
 
96
        int vers;
 
97
        mdu_array_info_t array;
 
98
        mdp_super_t first_super, super;
 
99
        struct {
 
100
                char *devname;
 
101
                unsigned int major, minor;
 
102
                unsigned int oldmajor, oldminor;
 
103
                long long events;
 
104
                time_t utime;
 
105
                int uptodate;
 
106
                int state;
 
107
                int raid_disk;
 
108
        } *devices;
 
109
        int *best = NULL; /* indexed by raid_disk */
 
110
        unsigned int bestcnt = 0;
 
111
        int devcnt = 0;
 
112
        unsigned int okcnt, sparecnt;
 
113
        unsigned int req_cnt;
 
114
        unsigned int i;
 
115
        int most_recent = 0;
 
116
        int chosen_drive;
 
117
        int change = 0;
 
118
        int inargv = 0;
 
119
        int start_partial_ok = force || devlist==NULL;
 
120
        unsigned int num_devs;
 
121
        mddev_dev_t tmpdev;
 
122
        
 
123
        vers = md_get_version(mdfd);
 
124
        if (vers <= 0) {
 
125
                fprintf(stderr, Name ": %s appears not to be an md device.\n", mddev);
 
126
                return 1;
 
127
        }
 
128
        if (vers < 9000) {
 
129
                fprintf(stderr, Name ": Assemble requires driver version 0.90.0 or later.\n"
 
130
                        "    Upgrade your kernel or try --build\n");
 
131
                return 1;
 
132
        }
 
133
        if (get_linux_version() < 2004000)
 
134
                old_linux = 1;
 
135
 
 
136
        if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0) {
 
137
                fprintf(stderr, Name ": device %s already active - cannot assemble it\n",
 
138
                        mddev);
 
139
                return 1;
 
140
        }
 
141
        ioctl(mdfd, STOP_ARRAY, NULL); /* just incase it was started but has no content */
 
142
 
 
143
        /*
 
144
         * If any subdevs are listed, then any that don't
 
145
         * match ident are discarded.  Remainder must all match and
 
146
         * become the array.
 
147
         * If no subdevs, then we scan all devices in the config file, but
 
148
         * there must be something in the identity
 
149
         */
 
150
 
 
151
        if (!devlist &&
 
152
            ident->uuid_set == 0 &&
 
153
            ident->super_minor < 0 &&
 
154
            ident->devices == NULL) {
 
155
                fprintf(stderr, Name ": No identity information available for %s - cannot assemble.\n",
 
156
                        mddev);
 
157
                return 1;
 
158
        }
 
159
        if (devlist == NULL)
 
160
                devlist = conf_get_devs(conffile);
 
161
        else inargv = 1;
 
162
 
 
163
        tmpdev = devlist; num_devs = 0;
 
164
        while (tmpdev) {
 
165
                num_devs++;
 
166
                tmpdev = tmpdev->next;
 
167
        }
 
168
        best = malloc(num_devs * sizeof(*best));
 
169
        devices = malloc(num_devs * sizeof(*devices));
 
170
 
 
171
        first_super.md_magic = 0;
 
172
        for (i=0; i<num_devs; i++)
 
173
                best[i] = -1;
 
174
 
 
175
        if (verbose)
 
176
            fprintf(stderr, Name ": looking for devices for %s\n",
 
177
                    mddev);
 
178
 
 
179
        while ( devlist) {
 
180
                char *devname;
 
181
                int this_uuid[4];
 
182
                int dfd;
 
183
                struct stat stb;
 
184
                int havesuper=0;
 
185
 
 
186
                devname = devlist->devname;
 
187
                devlist = devlist->next;
 
188
 
 
189
                if (ident->devices &&
 
190
                    !match_oneof(ident->devices, devname)) {
 
191
                        if (inargv || verbose)
 
192
                                fprintf(stderr, Name ": %s is not one of %s\n", devname, ident->devices);
 
193
                        continue;
 
194
                }
 
195
                
 
196
                dfd = open(devname, O_RDONLY|O_EXCL, 0);
 
197
                if (dfd < 0) {
 
198
                        if (inargv || verbose)
 
199
                                fprintf(stderr, Name ": cannot open device %s: %s\n",
 
200
                                        devname, strerror(errno));
 
201
                } else if (fstat(dfd, &stb)< 0) {
 
202
                        /* Impossible! */
 
203
                        fprintf(stderr, Name ": fstat failed for %s: %s\n",
 
204
                                devname, strerror(errno));
 
205
                        close(dfd);
 
206
                } else if ((stb.st_mode & S_IFMT) != S_IFBLK) {
 
207
                        fprintf(stderr, Name ": %s is not a block device.\n",
 
208
                                devname);
 
209
                        close(dfd);
 
210
                } else if (load_super(dfd, &super)) {
 
211
                        if (inargv || verbose)
 
212
                                fprintf( stderr, Name ": no RAID superblock on %s\n",
 
213
                                         devname);
 
214
                        close(dfd);
 
215
                } else {
 
216
                        havesuper =1;
 
217
                        uuid_from_super(this_uuid, &super);
 
218
                        close(dfd);
 
219
                }
 
220
 
 
221
                if (ident->uuid_set &&
 
222
                    (!havesuper || same_uuid(this_uuid, ident->uuid)==0)) {
 
223
                        if (inargv || verbose)
 
224
                                fprintf(stderr, Name ": %s has wrong uuid.\n",
 
225
                                        devname);
 
226
                        continue;
 
227
                }
 
228
                if (ident->super_minor != UnSet &&
 
229
                    (!havesuper || ident->super_minor != super.md_minor)) {
 
230
                        if (inargv || verbose)
 
231
                                fprintf(stderr, Name ": %s has wrong super-minor.\n",
 
232
                                        devname);
 
233
                        continue;
 
234
                }
 
235
                if (ident->level != UnSet &&
 
236
                    (!havesuper|| ident->level != (int)super.level)) {
 
237
                        if (inargv || verbose)
 
238
                                fprintf(stderr, Name ": %s has wrong raid level.\n",
 
239
                                        devname);
 
240
                        continue;
 
241
                }
 
242
                if (ident->raid_disks != UnSet &&
 
243
                    (!havesuper || ident->raid_disks!= super.raid_disks)) {
 
244
                        if (inargv || verbose)
 
245
                                fprintf(stderr, Name ": %s requires wrong number of drives.\n",
 
246
                                        devname);
 
247
                        continue;
 
248
                }
 
249
 
 
250
                /* If we are this far, then we are commited to this device.
 
251
                 * If the super_block doesn't exist, or doesn't match others,
 
252
                 * then we cannot continue
 
253
                 */
 
254
 
 
255
                if (!havesuper) {
 
256
                        fprintf(stderr, Name ": %s has no superblock - assembly aborted\n",
 
257
                                devname);
 
258
                        return 1;
 
259
                }
 
260
                if (compare_super(&first_super, &super)) {
 
261
                        fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n",
 
262
                                devname);
 
263
                        return 1;
 
264
                }
 
265
 
 
266
 
 
267
                /* this is needed until we get a more relaxed super block format */
 
268
                if (devcnt >= MD_SB_DISKS) {
 
269
                    fprintf(stderr, Name ": ouch - too many devices appear to be in this array. Ignoring %s\n",
 
270
                            devname);
 
271
                    continue;
 
272
                }
 
273
                
 
274
                /* looks like a good enough match to update the super block if needed */
 
275
                if (update) {
 
276
                        if (strcmp(update, "sparc2.2")==0 ) {
 
277
                                /* 2.2 sparc put the events in the wrong place
 
278
                                 * So we copy the tail of the superblock
 
279
                                 * up 4 bytes before continuing
 
280
                                 */
 
281
                                __u32 *sb32 = (__u32*)&super;
 
282
                                memcpy(sb32+MD_SB_GENERIC_CONSTANT_WORDS+7,
 
283
                                       sb32+MD_SB_GENERIC_CONSTANT_WORDS+7+1,
 
284
                                       (MD_SB_WORDS - (MD_SB_GENERIC_CONSTANT_WORDS+7+1))*4);
 
285
                                fprintf (stderr, Name ": adjusting superblock of %s for 2.2/sparc compatability.\n",
 
286
                                         devname);
 
287
                        }
 
288
                        if (strcmp(update, "super-minor") ==0) {
 
289
                                struct stat stb2;
 
290
                                fstat(mdfd, &stb2);
 
291
                                super.md_minor = minor(stb2.st_rdev);
 
292
                                if (verbose)
 
293
                                        fprintf(stderr, Name ": updating superblock of %s with minor number %d\n",
 
294
                                                devname, super.md_minor);
 
295
                        }
 
296
                        if (strcmp(update, "summaries") == 0) {
 
297
                                /* set nr_disks, active_disks, working_disks,
 
298
                                 * failed_disks, spare_disks based on disks[] 
 
299
                                 * array in superblock.
 
300
                                 * Also make sure extra slots aren't 'failed'
 
301
                                 */
 
302
                                super.nr_disks = super.active_disks =
 
303
                                        super.working_disks = super.failed_disks =
 
304
                                        super.spare_disks = 0;
 
305
                                for (i=0; i < MD_SB_DISKS ; i++) 
 
306
                                        if (super.disks[i].major ||
 
307
                                            super.disks[i].minor) {
 
308
                                                int state = super.disks[i].state;
 
309
                                                if (state & (1<<MD_DISK_REMOVED))
 
310
                                                        continue;
 
311
                                                super.nr_disks++;
 
312
                                                if (state & (1<<MD_DISK_ACTIVE))
 
313
                                                        super.active_disks++;
 
314
                                                if (state & (1<<MD_DISK_FAULTY))
 
315
                                                        super.failed_disks++;
 
316
                                                else
 
317
                                                        super.working_disks++;
 
318
                                                if (state == 0)
 
319
                                                        super.spare_disks++;
 
320
                                        } else if (i >= super.raid_disks && super.disks[i].number == 0)
 
321
                                                super.disks[i].state = 0;
 
322
                        }
 
323
                        if (strcmp(update, "resync") == 0) {
 
324
                                /* make sure resync happens */
 
325
                                super.state &= ~(1<<MD_SB_CLEAN);
 
326
                                super.recovery_cp = 0;
 
327
                        }
 
328
                        super.sb_csum = calc_sb_csum(&super);
 
329
                        dfd = open(devname, O_RDWR|O_EXCL, 0);
 
330
                        if (dfd < 0) 
 
331
                                fprintf(stderr, Name ": Cannot open %s for superblock update\n",
 
332
                                        devname);
 
333
                        else if (store_super(dfd, &super))
 
334
                                fprintf(stderr, Name ": Could not re-write superblock on %s.\n",
 
335
                                        devname);
 
336
                        if (dfd >= 0)
 
337
                                close(dfd);
 
338
                }
 
339
 
 
340
                if (verbose)
 
341
                        fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n",
 
342
                                devname, mddev, super.this_disk.raid_disk);
 
343
                devices[devcnt].devname = devname;
 
344
                devices[devcnt].major = major(stb.st_rdev);
 
345
                devices[devcnt].minor = minor(stb.st_rdev);
 
346
                devices[devcnt].oldmajor = super.this_disk.major;
 
347
                devices[devcnt].oldminor = super.this_disk.minor;
 
348
                devices[devcnt].events = md_event(&super);
 
349
                devices[devcnt].utime = super.utime;
 
350
                devices[devcnt].raid_disk = super.this_disk.raid_disk;
 
351
                devices[devcnt].uptodate = 0;
 
352
                devices[devcnt].state = super.this_disk.state;
 
353
                if (most_recent < devcnt) {
 
354
                        if (devices[devcnt].events
 
355
                            > devices[most_recent].events)
 
356
                                most_recent = devcnt;
 
357
                }
 
358
                if ((int)super.level == -4) 
 
359
                        /* with multipath, the raid_disk from the superblock is meaningless */
 
360
                        i = devcnt;
 
361
                else
 
362
                        i = devices[devcnt].raid_disk;
 
363
                if (i < 10000) {
 
364
                        if (i >= bestcnt) {
 
365
                                unsigned int newbestcnt = i+10;
 
366
                                int *newbest = malloc(sizeof(int)*newbestcnt);
 
367
                                unsigned int c;
 
368
                                for (c=0; c < newbestcnt; c++)
 
369
                                        if (c < bestcnt)
 
370
                                                newbest[c] = best[c];
 
371
                                        else
 
372
                                                newbest[c] = -1;
 
373
                                if (best)free(best);
 
374
                                best = newbest;
 
375
                                bestcnt = newbestcnt;
 
376
                        }
 
377
                        if (best[i] == -1
 
378
                            || devices[best[i]].events < devices[devcnt].events)
 
379
                                best[i] = devcnt;
 
380
                }
 
381
                devcnt++;
 
382
        }
 
383
 
 
384
        if (devcnt == 0) {
 
385
                fprintf(stderr, Name ": no devices found for %s\n",
 
386
                        mddev);
 
387
                return 1;
 
388
        }
 
389
        /* now we have some devices that might be suitable.
 
390
         * I wonder how many
 
391
         */
 
392
        okcnt = 0;
 
393
        sparecnt=0;
 
394
        for (i=0; i< bestcnt ;i++) {
 
395
                int j = best[i];
 
396
                int event_margin = !force;
 
397
                if (j < 0) continue;
 
398
                /* note: we ignore error flags in multipath arrays
 
399
                 * as they don't make sense
 
400
                 */
 
401
                if ((int)first_super.level != -4)
 
402
                        if (!(devices[j].state & (1<<MD_DISK_SYNC))) {
 
403
                                if (!(devices[j].state & (1<<MD_DISK_FAULTY)))
 
404
                                        sparecnt++;
 
405
                                continue;
 
406
                        }
 
407
                if (devices[j].events+event_margin >=
 
408
                    devices[most_recent].events) {
 
409
                        devices[j].uptodate = 1;
 
410
                        if (i < first_super.raid_disks)
 
411
                                okcnt++;
 
412
                        else
 
413
                                sparecnt++;
 
414
                }
 
415
        }
 
416
        while (force && !enough(first_super.level, first_super.raid_disks, okcnt)) {
 
417
                /* Choose the newest best drive which is
 
418
                 * not up-to-date, update the superblock
 
419
                 * and add it.
 
420
                 */
 
421
                int fd;
 
422
                chosen_drive = -1;
 
423
                for (i=0; i<first_super.raid_disks && i < bestcnt; i++) {
 
424
                        int j = best[i];
 
425
                        if (j>=0 &&
 
426
                            !devices[j].uptodate &&
 
427
                            devices[j].events > 0 &&
 
428
                            (chosen_drive < 0 ||
 
429
                             devices[j].events > devices[chosen_drive].events))
 
430
                                chosen_drive = j;
 
431
                }
 
432
                if (chosen_drive < 0)
 
433
                        break;
 
434
                fprintf(stderr, Name ": forcing event count in %s(%d) from %d upto %d\n",
 
435
                        devices[chosen_drive].devname, devices[chosen_drive].raid_disk,
 
436
                        (int)(devices[chosen_drive].events),
 
437
                        (int)(devices[most_recent].events));
 
438
                fd = open(devices[chosen_drive].devname, O_RDWR|O_EXCL);
 
439
                if (fd < 0) {
 
440
                        fprintf(stderr, Name ": Couldn't open %s for write - not updating\n",
 
441
                                devices[chosen_drive].devname);
 
442
                        devices[chosen_drive].events = 0;
 
443
                        continue;
 
444
                }
 
445
                if (load_super(fd, &super)) {
 
446
                        close(fd);
 
447
                        fprintf(stderr, Name ": RAID superblock disappeared from %s - not updating.\n",
 
448
                                devices[chosen_drive].devname);
 
449
                        devices[chosen_drive].events = 0;
 
450
                        continue;
 
451
                }
 
452
                super.events_hi = (devices[most_recent].events>>32)&0xFFFFFFFF;
 
453
                super.events_lo = (devices[most_recent].events)&0xFFFFFFFF;
 
454
                if (super.level == 5 || super.level == 4) {
 
455
                        /* need to force clean */
 
456
                        super.state = (1<<MD_SB_CLEAN);
 
457
                }
 
458
                super.sb_csum = calc_sb_csum(&super);
 
459
/*DRYRUN*/      if (store_super(fd, &super)) {
 
460
                        close(fd);
 
461
                        fprintf(stderr, Name ": Could not re-write superblock on %s\n",
 
462
                                devices[chosen_drive].devname);
 
463
                        devices[chosen_drive].events = 0;
 
464
                        continue;
 
465
                }
 
466
                close(fd);
 
467
                devices[chosen_drive].events = devices[most_recent].events;
 
468
                devices[chosen_drive].uptodate = 1;
 
469
                okcnt++;
 
470
        }
 
471
 
 
472
        /* Now we want to look at the superblock which the kernel will base things on
 
473
         * and compare the devices that we think are working with the devices that the
 
474
         * superblock thinks are working.
 
475
         * If there are differences and --force is given, then update this chosen
 
476
         * superblock.
 
477
         */
 
478
        chosen_drive = -1;
 
479
        for (i=0; chosen_drive < 0 && i<bestcnt; i++) {
 
480
                int j = best[i];
 
481
                int fd;
 
482
                if (j<0)
 
483
                        continue;
 
484
                if (!devices[j].uptodate)
 
485
                        continue;
 
486
                chosen_drive = j;
 
487
                if ((fd=open(devices[j].devname, O_RDONLY|O_EXCL))< 0) {
 
488
                        fprintf(stderr, Name ": Cannot open %s: %s\n",
 
489
                                devices[j].devname, strerror(errno));
 
490
                        return 1;
 
491
                }
 
492
                if (load_super(fd, &super)) {
 
493
                        close(fd);
 
494
                        fprintf(stderr, Name ": RAID superblock has disappeared from %s\n",
 
495
                                devices[j].devname);
 
496
                        return 1;
 
497
                }
 
498
                close(fd);
 
499
        }
 
500
 
 
501
        for (i=0; i<bestcnt; i++) {
 
502
                int j = best[i];
 
503
                unsigned int desired_state;
 
504
 
 
505
                if (i < super.raid_disks)
 
506
                        desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC);
 
507
                else
 
508
                        desired_state = 0;
 
509
 
 
510
                if (j<0)
 
511
                        continue;
 
512
                if (!devices[j].uptodate)
 
513
                        continue;
 
514
#if 0
 
515
This doesnt work yet 
 
516
                if (devices[j].major != super.disks[i].major ||
 
517
                    devices[j].minor != super.disks[i].minor) {
 
518
                        change |= 1;
 
519
                        super.disks[i].major = devices[j].major;
 
520
                        super.disks[i].minor = devices[j].minor;
 
521
                }
 
522
#endif 
 
523
                if (devices[j].oldmajor != super.disks[i].major ||
 
524
                    devices[j].oldminor != super.disks[i].minor) {
 
525
                        change |= 2;
 
526
                        super.disks[i].major = devices[j].oldmajor;
 
527
                        super.disks[i].minor = devices[j].oldminor;
 
528
                }
 
529
                if (devices[j].uptodate &&
 
530
                    (super.disks[i].state != desired_state)) {
 
531
                        if (force) {
 
532
                                fprintf(stderr, Name ": "
 
533
                                        "clearing FAULTY flag for device %d in %s for %s\n",
 
534
                                        j, mddev, devices[j].devname);
 
535
                                super.disks[i].state = desired_state;
 
536
                                change |= 2;
 
537
                        } else {
 
538
                                fprintf(stderr, Name ": "
 
539
                                        "device %d in %s has wrong state in superblock, but %s seems ok\n",
 
540
                                        i, mddev, devices[j].devname);
 
541
                        }
 
542
                }
 
543
                if (!devices[j].uptodate &&
 
544
                    !(super.disks[i].state & (1 << MD_DISK_FAULTY))) {
 
545
                        fprintf(stderr, Name ": devices %d of %s is not marked FAULTY in superblock, but cannot be found\n",
 
546
                                i, mddev);
 
547
                }
 
548
        }
 
549
        if (force && (super.level == 4 || super.level == 5) && 
 
550
            okcnt == super.raid_disks-1) {
 
551
                super.state = (1<< MD_SB_CLEAN);
 
552
                change |= 2;
 
553
        }
 
554
 
 
555
        if ((force && (change & 2))
 
556
            || (old_linux && (change & 1))) {
 
557
                int fd;
 
558
                super.sb_csum = calc_sb_csum(&super);
 
559
                fd = open(devices[chosen_drive].devname, O_RDWR|O_EXCL);
 
560
                if (fd < 0) {
 
561
                        fprintf(stderr, Name ": Could open %s for write - cannot Assemble array.\n",
 
562
                                devices[chosen_drive].devname);
 
563
                        return 1;
 
564
                }
 
565
                if (store_super(fd, &super)) {
 
566
                        close(fd);
 
567
                        fprintf(stderr, Name ": Could not re-write superblock on %s\n",
 
568
                                devices[chosen_drive].devname);
 
569
                        return 1;
 
570
                }
 
571
                close(fd);
 
572
                change = 0;
 
573
        }
 
574
 
 
575
        /* count number of in-sync devices according to the superblock.
 
576
         * We must have this number to start the array without -s or -R
 
577
         */
 
578
        req_cnt = 0;
 
579
        for (i=0; i<MD_SB_DISKS; i++)
 
580
                if ((first_super.disks[i].state & (1<<MD_DISK_SYNC)) &&
 
581
                    (first_super.disks[i].state & (1<<MD_DISK_ACTIVE)) &&
 
582
                    !(first_super.disks[i].state & (1<<MD_DISK_FAULTY)))
 
583
                        req_cnt ++;
 
584
                                                                            
 
585
 
 
586
        /* Almost ready to actually *do* something */
 
587
        if (!old_linux) {
 
588
                if (ioctl(mdfd, SET_ARRAY_INFO, NULL) != 0) {
 
589
                        fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n",
 
590
                                mddev, strerror(errno));
 
591
                        return 1;
 
592
                }
 
593
                /* First, add the raid disks, but add the chosen one last */
 
594
                for (i=0; i<= bestcnt; i++) {
 
595
                        int j;
 
596
                        if (i < bestcnt) {
 
597
                                j = best[i];
 
598
                                if (j == chosen_drive)
 
599
                                        continue;
 
600
                        } else
 
601
                                j = chosen_drive;
 
602
 
 
603
                        if (j >= 0 /* && devices[j].uptodate */) {
 
604
                                mdu_disk_info_t disk;
 
605
                                memset(&disk, 0, sizeof(disk));
 
606
                                disk.major = devices[j].major;
 
607
                                disk.minor = devices[j].minor;
 
608
                                if (ioctl(mdfd, ADD_NEW_DISK, &disk)!=0) {
 
609
                                        fprintf(stderr, Name ": failed to add %s to %s: %s\n",
 
610
                                                devices[j].devname,
 
611
                                                mddev,
 
612
                                                strerror(errno));
 
613
                                        if (i < first_super.raid_disks || i == bestcnt)
 
614
                                                okcnt--;
 
615
                                        else
 
616
                                                sparecnt--;
 
617
                                } else if (verbose)
 
618
                                        fprintf(stderr, Name ": added %s to %s as %d\n",
 
619
                                                devices[j].devname, mddev, devices[j].raid_disk);
 
620
                        } else if (verbose && i < first_super.raid_disks)
 
621
                                fprintf(stderr, Name ": no uptodate device for slot %d of %s\n",
 
622
                                        i, mddev);
 
623
                }
 
624
                
 
625
                if (runstop == 1 ||
 
626
                    (runstop == 0 && 
 
627
                     ( enough(first_super.level, first_super.raid_disks, okcnt) &&
 
628
                       (okcnt >= req_cnt || start_partial_ok)
 
629
                             ))) {
 
630
                        if (ioctl(mdfd, RUN_ARRAY, NULL)==0) {
 
631
                                fprintf(stderr, Name ": %s has been started with %d drive%s",
 
632
                                        mddev, okcnt, okcnt==1?"":"s");
 
633
                                if (okcnt < first_super.raid_disks) 
 
634
                                        fprintf(stderr, " (out of %d)", first_super.raid_disks);
 
635
                                if (sparecnt)
 
636
                                        fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s");
 
637
                                fprintf(stderr, ".\n");
 
638
                                return 0;
 
639
                        }
 
640
                        fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n",
 
641
                                mddev, strerror(errno));
 
642
                        return 1;
 
643
                }
 
644
                if (runstop == -1) {
 
645
                        fprintf(stderr, Name ": %s assembled from %d drive%s, but not started.\n",
 
646
                                mddev, okcnt, okcnt==1?"":"s");
 
647
                        return 0;
 
648
                }
 
649
                fprintf(stderr, Name ": %s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s");
 
650
                if (sparecnt)
 
651
                        fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s");
 
652
                if (!enough(first_super.level, first_super.raid_disks, okcnt))
 
653
                        fprintf(stderr, " - not enough to start the array.\n");
 
654
                else {
 
655
                        if (req_cnt == first_super.raid_disks)
 
656
                                fprintf(stderr, " - need all %d to start it", req_cnt);
 
657
                        else
 
658
                                fprintf(stderr, " - need %d of %d to start", req_cnt, first_super.raid_disks);
 
659
                        fprintf(stderr, " (use --run to insist).\n");
 
660
                }
 
661
                return 1;
 
662
        } else {
 
663
                /* The "chosen_drive" is a good choice, and if necessary, the superblock has
 
664
                 * been updated to point to the current locations of devices.
 
665
                 * so we can just start the array
 
666
                 */
 
667
                unsigned long dev;
 
668
                dev = makedev(devices[chosen_drive].major,
 
669
                            devices[chosen_drive].minor);
 
670
                if (ioctl(mdfd, START_ARRAY, dev)) {
 
671
                    fprintf(stderr, Name ": Cannot start array: %s\n",
 
672
                            strerror(errno));
 
673
                }
 
674
                
 
675
        }
 
676
        return 0;
 
677
}