wait_for improvement.
[thirdparty/mdadm.git] / Incremental.c
1 /*
2  * Incremental.c - support --incremental.  Part of:
3  * mdadm - manage Linux "md" devices aka RAID arrays.
4  *
5  * Copyright (C) 2006 Neil Brown <neilb@suse.de>
6  *
7  *
8  *    This program is free software; you can redistribute it and/or modify
9  *    it under the terms of the GNU General Public License as published by
10  *    the Free Software Foundation; either version 2 of the License, or
11  *    (at your option) any later version.
12  *
13  *    This program is distributed in the hope that it will be useful,
14  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *    GNU General Public License for more details.
17  *
18  *    You should have received a copy of the GNU General Public License
19  *    along with this program; if not, write to the Free Software
20  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  *    Author: Neil Brown
23  *    Email: <neilb@suse.de>
24  *    Paper: Neil Brown
25  *           Novell Inc
26  *           GPO Box Q1283
27  *           QVB Post Office, NSW 1230
28  *           Australia
29  */
30
31 #include        "mdadm.h"
32
33 static int count_active(struct supertype *st, int mdfd, char **availp,
34                         struct mdinfo *info);
35 static void find_reject(int mdfd, struct supertype *st, struct mdinfo *sra,
36                         int number, __u64 events, int verbose,
37                         char *array_name);
38
39 int Incremental(char *devname, int verbose, int runstop,
40                 struct supertype *st, char *homehost, int autof)
41 {
42         /* Add this device to an array, creating the array if necessary
43          * and starting the array if sensible or - if runstop>0 - if possible.
44          *
45          * This has several steps:
46          *
47          * 1/ Check if device is permitted by mdadm.conf, reject if not.
48          * 2/ Find metadata, reject if none appropriate (check
49          *       version/name from args)
50          * 3/ Check if there is a match in mdadm.conf
51          * 3a/ if not, check for homehost match.  If no match, assemble as
52          *    a 'foreign' array.
53          * 4/ Determine device number.
54          * - If in mdadm.conf with std name, use that
55          * - UUID in /var/run/mdadm.map  use that
56          * - If name is suggestive, use that. unless in use with different uuid.
57          * - Choose a free, high number.
58          * - Use a partitioned device unless strong suggestion not to.
59          *         e.g. auto=md
60          *   Don't choose partitioned for containers.
61          * 5/ Find out if array already exists
62          * 5a/ if it does not
63          * - choose a name, from mdadm.conf or 'name' field in array.
64          * - create the array
65          * - add the device
66          * 5b/ if it does
67          * - check one drive in array to make sure metadata is a reasonably
68          *       close match.  Reject if not (e.g. different type)
69          * - add the device
70          * 6/ Make sure /var/run/mdadm.map contains this array.
71          * 7/ Is there enough devices to possibly start the array?
72          *     For a container, this means running Incremental_container.
73          * 7a/ if not, finish with success.
74          * 7b/ if yes,
75          * - read all metadata and arrange devices like -A does
76          * - if number of OK devices match expected, or -R and there are enough,
77          *   start the array (auto-readonly).
78          */
79         struct stat stb;
80         struct mdinfo info;
81         struct mddev_ident_s *array_list, *match;
82         char chosen_name[1024];
83         int rv;
84         struct map_ent *mp, *map = NULL;
85         int dfd, mdfd;
86         char *avail;
87         int active_disks;
88         int trustworthy = FOREIGN;
89         char *name_to_use;
90         mdu_array_info_t ainf;
91
92         struct createinfo *ci = conf_get_create_info();
93
94
95         /* 1/ Check if device is permitted by mdadm.conf */
96
97         if (!conf_test_dev(devname)) {
98                 if (verbose >= 0)
99                         fprintf(stderr, Name
100                                 ": %s not permitted by mdadm.conf.\n",
101                                 devname);
102                 return 1;
103         }
104
105         /* 2/ Find metadata, reject if none appropriate (check
106          *            version/name from args) */
107
108         dfd = dev_open(devname, O_RDONLY|O_EXCL);
109         if (dfd < 0) {
110                 if (verbose >= 0)
111                         fprintf(stderr, Name ": cannot open %s: %s.\n",
112                                 devname, strerror(errno));
113                 return 1;
114         }
115         if (fstat(dfd, &stb) < 0) {
116                 if (verbose >= 0)
117                         fprintf(stderr, Name ": fstat failed for %s: %s.\n",
118                                 devname, strerror(errno));
119                 close(dfd);
120                 return 1;
121         }
122         if ((stb.st_mode & S_IFMT) != S_IFBLK) {
123                 if (verbose >= 0)
124                         fprintf(stderr, Name ": %s is not a block device.\n",
125                                 devname);
126                 close(dfd);
127                 return 1;
128         }
129
130         if (st == NULL && (st = guess_super(dfd)) == NULL) {
131                 if (verbose >= 0)
132                         fprintf(stderr, Name
133                                 ": no recognisable superblock on %s.\n",
134                                 devname);
135                 close(dfd);
136                 return 1;
137         }
138         if (st->ss->load_super(st, dfd, NULL)) {
139                 if (verbose >= 0)
140                         fprintf(stderr, Name ": no RAID superblock on %s.\n",
141                                 devname);
142                 close(dfd);
143                 return 1;
144         }
145         close (dfd);
146
147         memset(&info, 0, sizeof(info));
148         st->ss->getinfo_super(st, &info);
149         /* 3/ Check if there is a match in mdadm.conf */
150
151         array_list = conf_get_ident(NULL);
152         match = NULL;
153         for (; array_list; array_list = array_list->next) {
154                 if (array_list->uuid_set &&
155                     same_uuid(array_list->uuid, info.uuid, st->ss->swapuuid)
156                     == 0) {
157                         if (verbose >= 2 && array_list->devname)
158                                 fprintf(stderr, Name
159                                         ": UUID differs from %s.\n",
160                                         array_list->devname);
161                         continue;
162                 }
163                 if (array_list->name[0] &&
164                     strcasecmp(array_list->name, info.name) != 0) {
165                         if (verbose >= 2 && array_list->devname)
166                                 fprintf(stderr, Name
167                                         ": Name differs from %s.\n",
168                                         array_list->devname);
169                         continue;
170                 }
171                 if (array_list->devices &&
172                     !match_oneof(array_list->devices, devname)) {
173                         if (verbose >= 2 && array_list->devname)
174                                 fprintf(stderr, Name
175                                         ": Not a listed device for %s.\n",
176                                         array_list->devname);
177                         continue;
178                 }
179                 if (array_list->super_minor != UnSet &&
180                     array_list->super_minor != info.array.md_minor) {
181                         if (verbose >= 2 && array_list->devname)
182                                 fprintf(stderr, Name
183                                         ": Different super-minor to %s.\n",
184                                         array_list->devname);
185                         continue;
186                 }
187                 if (!array_list->uuid_set &&
188                     !array_list->name[0] &&
189                     !array_list->devices &&
190                     array_list->super_minor == UnSet) {
191                         if (verbose >= 2 && array_list->devname)
192                                 fprintf(stderr, Name
193                              ": %s doesn't have any identifying information.\n",
194                                         array_list->devname);
195                         continue;
196                 }
197                 /* FIXME, should I check raid_disks and level too?? */
198
199                 if (match) {
200                         if (verbose >= 0) {
201                                 if (match->devname && array_list->devname)
202                                         fprintf(stderr, Name
203                    ": we match both %s and %s - cannot decide which to use.\n",
204                                                 match->devname, array_list->devname);
205                                 else
206                                         fprintf(stderr, Name
207                                                 ": multiple lines in mdadm.conf match\n");
208                         }
209                         return 2;
210                 }
211                 match = array_list;
212         }
213
214         /* 3a/ if not, check for homehost match.  If no match, continue
215          * but don't trust the 'name' in the array. Thus a 'random' minor
216          * number will be assigned, and the device name will be based
217          * on that. */
218         if (match)
219                 trustworthy = LOCAL;
220         else if (homehost == NULL ||
221                  st->ss->match_home(st, homehost) != 1)
222                 trustworthy = FOREIGN;
223         else
224                 trustworthy = LOCAL;
225
226         /* There are three possible sources for 'autof':  command line,
227          * ARRAY line in mdadm.conf, or CREATE line in mdadm.conf.
228          * ARRAY takes precedence, then command line, then
229          * CREATE.
230          */
231         if (match && match->autof)
232                 autof = match->autof;
233         if (autof == 0)
234                 autof = ci->autof;
235
236         if (st->ss->container_content && st->loaded_container) {
237                 /* This is a pre-built container array, so we do something
238                  * rather different.
239                  */
240                 return Incremental_container(st, devname, verbose, runstop,
241                                              autof, trustworthy);
242         }
243         name_to_use = strchr(info.name, ':');
244         if (name_to_use)
245                 name_to_use++;
246         else
247                 name_to_use = info.name;
248
249         if ((!name_to_use || name_to_use[0] == 0) &&
250             info.array.level == LEVEL_CONTAINER &&
251             trustworthy == LOCAL) {
252                 name_to_use = info.text_version;
253                 trustworthy = METADATA;
254         }
255
256         /* 4/ Check if array exists.
257          */
258         map_lock(&map);
259         mp = map_by_uuid(&map, info.uuid);
260         if (mp) {
261                 mdfd = open_mddev(mp->path, 0);
262                 if (mdfd < 0 && mddev_busy(mp->devnum)) {
263                         /* maybe udev hasn't created it yet. */
264                         char buf[50];
265                         sprintf(buf, "%d:%d", dev2major(mp->devnum),
266                                 dev2minor(mp->devnum));
267                         mdfd = dev_open(buf, O_RDWR);
268                 }
269         } else
270                 mdfd = -1;
271
272         if (mdfd < 0) {
273                 struct mdinfo *sra;
274                 struct mdinfo dinfo;
275
276                 /* Couldn't find an existing array, maybe make a new one */
277                 mdfd = create_mddev(match ? match->devname : NULL,
278                                     name_to_use, autof, trustworthy, chosen_name);
279
280                 if (mdfd < 0)
281                         return 1;
282
283                 sysfs_init(&info, mdfd, 0);
284
285                 if (set_array_info(mdfd, st, &info) != 0) {
286                         fprintf(stderr, Name ": failed to set array info for %s: %s\n",
287                                 chosen_name, strerror(errno));
288                         close(mdfd);
289                         return 2;
290                 }
291
292                 dinfo = info;
293                 dinfo.disk.major = major(stb.st_rdev);
294                 dinfo.disk.minor = minor(stb.st_rdev);
295                 if (add_disk(mdfd, st, &info, &dinfo) != 0) {
296                         fprintf(stderr, Name ": failed to add %s to %s: %s.\n",
297                                 devname, chosen_name, strerror(errno));
298                         ioctl(mdfd, STOP_ARRAY, 0);
299                         close(mdfd);
300                         return 2;
301                 }
302                 sra = sysfs_read(mdfd, fd2devnum(mdfd), GET_DEVS);
303                 if (!sra || !sra->devs || sra->devs->disk.raid_disk >= 0) {
304                         /* It really should be 'none' - must be old buggy
305                          * kernel, and mdadm -I may not be able to complete.
306                          * So reject it.
307                          */
308                         ioctl(mdfd, STOP_ARRAY, NULL);
309                         fprintf(stderr, Name
310                       ": You have an old buggy kernel which cannot support\n"
311                                 "      --incremental reliably.  Aborting.\n");
312                         close(mdfd);
313                         sysfs_free(sra);
314                         return 2;
315                 }
316                 info.array.working_disks = 1;
317                 sysfs_free(sra);
318                 /* 6/ Make sure /var/run/mdadm.map contains this array. */
319                 map_update(&map, fd2devnum(mdfd),
320                            info.text_version,
321                            info.uuid, chosen_name);
322         } else {
323         /* 5b/ if it does */
324         /* - check one drive in array to make sure metadata is a reasonably */
325         /*        close match.  Reject if not (e.g. different type) */
326         /* - add the device */
327                 char dn[20];
328                 int dfd2;
329                 int err;
330                 struct mdinfo *sra;
331                 struct supertype *st2;
332                 struct mdinfo info2, *d;
333
334                 strcpy(chosen_name, mp->path);
335
336                 sra = sysfs_read(mdfd, fd2devnum(mdfd), (GET_DEVS | GET_STATE));
337
338                 sprintf(dn, "%d:%d", sra->devs->disk.major,
339                         sra->devs->disk.minor);
340                 dfd2 = dev_open(dn, O_RDONLY);
341                 st2 = dup_super(st);
342                 if (st2->ss->load_super(st2, dfd2, NULL) ||
343                     st->ss->compare_super(st, st2) != 0) {
344                         fprintf(stderr, Name
345                                 ": metadata mismatch between %s and "
346                                 "chosen array %s\n",
347                                 devname, chosen_name);
348                         close(mdfd);
349                         close(dfd2);
350                         return 2;
351                 }
352                 close(dfd2);
353                 memset(&info2, 0, sizeof(info2));
354                 st2->ss->getinfo_super(st2, &info2);
355                 st2->ss->free_super(st2);
356                 if (info.array.level != info2.array.level ||
357                     memcmp(info.uuid, info2.uuid, 16) != 0 ||
358                     info.array.raid_disks != info2.array.raid_disks) {
359                         fprintf(stderr, Name
360                                 ": unexpected difference between %s and %s.\n",
361                                 chosen_name, devname);
362                         close(mdfd);
363                         return 2;
364                 }
365                 info2.disk.major = major(stb.st_rdev);
366                 info2.disk.minor = minor(stb.st_rdev);
367                 /* add disk needs to know about containers */
368                 if (st->ss->external)
369                         sra->array.level = LEVEL_CONTAINER;
370                 err = add_disk(mdfd, st2, sra, &info2);
371                 if (err < 0 && errno == EBUSY) {
372                         /* could be another device present with the same
373                          * disk.number. Find and reject any such
374                          */
375                         find_reject(mdfd, st, sra, info.disk.number,
376                                     info.events, verbose, chosen_name);
377                         err = add_disk(mdfd, st2, sra, &info2);
378                 }
379                 if (err < 0) {
380                         fprintf(stderr, Name ": failed to add %s to %s: %s.\n",
381                                 devname, chosen_name, strerror(errno));
382                         close(mdfd);
383                         return 2;
384                 }
385                 info.array.working_disks = 0;
386                 for (d = sra->devs; d; d=d->next)
387                         info.array.working_disks ++;
388                         
389         }
390
391         /* 7/ Is there enough devices to possibly start the array? */
392         /* 7a/ if not, finish with success. */
393         if (info.array.level == LEVEL_CONTAINER) {
394                 /* Try to assemble within the container */
395                 map_unlock(&map);
396                 sysfs_uevent(&info, "change");
397                 if (verbose >= 0)
398                         fprintf(stderr, Name
399                                 ": container %s now has %d devices\n",
400                                 chosen_name, info.array.working_disks);
401                 wait_for(chosen_name, mdfd);
402                 close(mdfd);
403                 if (runstop < 0)
404                         return 0; /* don't try to assemble */
405                 return Incremental(chosen_name, verbose, runstop,
406                                    NULL, homehost, autof);
407         }
408         avail = NULL;
409         active_disks = count_active(st, mdfd, &avail, &info);
410         if (enough(info.array.level, info.array.raid_disks,
411                    info.array.layout, info.array.state & 1,
412                    avail, active_disks) == 0 ||
413             (runstop < 0 && active_disks < info.array.raid_disks)) {
414                 free(avail);
415                 if (verbose >= 0)
416                         fprintf(stderr, Name
417                              ": %s attached to %s, not enough to start (%d).\n",
418                                 devname, chosen_name, active_disks);
419                 map_unlock(&map);
420                 close(mdfd);
421                 return 0;
422         }
423         free(avail);
424
425         /* 7b/ if yes, */
426         /* - if number of OK devices match expected, or -R and there */
427         /*             are enough, */
428         /*   + add any bitmap file  */
429         /*   + start the array (auto-readonly). */
430
431         if (ioctl(mdfd, GET_ARRAY_INFO, &ainf) == 0) {
432                 if (verbose >= 0)
433                         fprintf(stderr, Name
434                            ": %s attached to %s which is already active.\n",
435                                 devname, chosen_name);
436                 close(mdfd);
437                 map_unlock(&map);
438                 return 0;
439         }
440
441         map_unlock(&map);
442         if (runstop > 0 || active_disks >= info.array.working_disks) {
443                 struct mdinfo *sra;
444                 /* Let's try to start it */
445                 if (match && match->bitmap_file) {
446                         int bmfd = open(match->bitmap_file, O_RDWR);
447                         if (bmfd < 0) {
448                                 fprintf(stderr, Name
449                                         ": Could not open bitmap file %s.\n",
450                                         match->bitmap_file);
451                                 close(mdfd);
452                                 return 1;
453                         }
454                         if (ioctl(mdfd, SET_BITMAP_FILE, bmfd) != 0) {
455                                 close(bmfd);
456                                 fprintf(stderr, Name
457                                         ": Failed to set bitmapfile for %s.\n",
458                                         chosen_name);
459                                 close(mdfd);
460                                 return 1;
461                         }
462                         close(bmfd);
463                 }
464                 sra = sysfs_read(mdfd, fd2devnum(mdfd), 0);
465                 if ((sra == NULL || active_disks >= info.array.working_disks)
466                     && trustworthy != FOREIGN)
467                         rv = ioctl(mdfd, RUN_ARRAY, NULL);
468                 else
469                         rv = sysfs_set_str(sra, NULL,
470                                            "array_state", "read-auto");
471                 if (rv == 0) {
472                         if (verbose >= 0)
473                                 fprintf(stderr, Name
474                            ": %s attached to %s, which has been started.\n",
475                                         devname, chosen_name);
476                         rv = 0;
477                         wait_for(chosen_name, mdfd);
478                 } else {
479                         fprintf(stderr, Name
480                              ": %s attached to %s, but failed to start: %s.\n",
481                                 devname, chosen_name, strerror(errno));
482                         rv = 1;
483                 }
484         } else {
485                 if (verbose >= 0)
486                         fprintf(stderr, Name
487                           ": %s attached to %s, not enough to start safely.\n",
488                                 devname, chosen_name);
489                 rv = 0;
490         }
491         close(mdfd);
492         return rv;
493 }
494
495 static void find_reject(int mdfd, struct supertype *st, struct mdinfo *sra,
496                         int number, __u64 events, int verbose,
497                         char *array_name)
498 {
499         /* Find a device attached to this array with a disk.number of number
500          * and events less than the passed events, and remove the device.
501          */
502         struct mdinfo *d;
503         mdu_array_info_t ra;
504
505         if (ioctl(mdfd, GET_ARRAY_INFO, &ra) == 0)
506                 return; /* not safe to remove from active arrays
507                          * without thinking more */
508
509         for (d = sra->devs; d ; d = d->next) {
510                 char dn[10];
511                 int dfd;
512                 struct mdinfo info;
513                 sprintf(dn, "%d:%d", d->disk.major, d->disk.minor);
514                 dfd = dev_open(dn, O_RDONLY);
515                 if (dfd < 0)
516                         continue;
517                 if (st->ss->load_super(st, dfd, NULL)) {
518                         close(dfd);
519                         continue;
520                 }
521                 st->ss->getinfo_super(st, &info);
522                 st->ss->free_super(st);
523                 close(dfd);
524
525                 if (info.disk.number != number ||
526                     info.events >= events)
527                         continue;
528
529                 if (d->disk.raid_disk > -1)
530                         sysfs_set_str(sra, d, "slot", "none");
531                 if (sysfs_set_str(sra, d, "state", "remove") == 0)
532                         if (verbose >= 0)
533                                 fprintf(stderr, Name
534                                         ": removing old device %s from %s\n",
535                                         d->sys_name+4, array_name);
536         }
537 }
538
539 static int count_active(struct supertype *st, int mdfd, char **availp,
540                         struct mdinfo *bestinfo)
541 {
542         /* count how many devices in sra think they are active */
543         struct mdinfo *d;
544         int cnt = 0, cnt1 = 0;
545         __u64 max_events = 0;
546         struct mdinfo *sra = sysfs_read(mdfd, -1, GET_DEVS | GET_STATE);
547         char *avail = NULL;
548
549         for (d = sra->devs ; d ; d = d->next) {
550                 char dn[30];
551                 int dfd;
552                 int ok;
553                 struct mdinfo info;
554
555                 sprintf(dn, "%d:%d", d->disk.major, d->disk.minor);
556                 dfd = dev_open(dn, O_RDONLY);
557                 if (dfd < 0)
558                         continue;
559                 ok =  st->ss->load_super(st, dfd, NULL);
560                 close(dfd);
561                 if (ok != 0)
562                         continue;
563                 st->ss->getinfo_super(st, &info);
564                 if (!avail) {
565                         avail = malloc(info.array.raid_disks);
566                         if (!avail) {
567                                 fprintf(stderr, Name ": out of memory.\n");
568                                 exit(1);
569                         }
570                         memset(avail, 0, info.array.raid_disks);
571                         *availp = avail;
572                 }
573
574                 if (info.disk.state & (1<<MD_DISK_SYNC))
575                 {
576                         if (cnt == 0) {
577                                 cnt++;
578                                 max_events = info.events;
579                                 avail[info.disk.raid_disk] = 2;
580                                 st->ss->getinfo_super(st, bestinfo);
581                         } else if (info.events == max_events) {
582                                 cnt++;
583                                 avail[info.disk.raid_disk] = 2;
584                         } else if (info.events == max_events-1) {
585                                 cnt1++;
586                                 avail[info.disk.raid_disk] = 1;
587                         } else if (info.events < max_events - 1)
588                                 ;
589                         else if (info.events == max_events+1) {
590                                 int i;
591                                 cnt1 = cnt;
592                                 cnt = 1;
593                                 max_events = info.events;
594                                 for (i=0; i<info.array.raid_disks; i++)
595                                         if (avail[i])
596                                                 avail[i]--;
597                                 avail[info.disk.raid_disk] = 2;
598                                 st->ss->getinfo_super(st, bestinfo);
599                         } else { /* info.events much bigger */
600                                 cnt = 1; cnt1 = 0;
601                                 memset(avail, 0, info.disk.raid_disk);
602                                 max_events = info.events;
603                                 st->ss->getinfo_super(st, bestinfo);
604                         }
605                 }
606                 st->ss->free_super(st);
607         }
608         return cnt + cnt1;
609 }
610
611 int IncrementalScan(int verbose)
612 {
613         /* look at every device listed in the 'map' file.
614          * If one is found that is not running then:
615          *  look in mdadm.conf for bitmap file.
616          *   if one exists, but array has none, add it.
617          *  try to start array in auto-readonly mode
618          */
619         struct map_ent *mapl = NULL;
620         struct map_ent *me;
621         mddev_ident_t devs, mddev;
622         int rv = 0;
623
624         map_read(&mapl);
625         devs = conf_get_ident(NULL);
626
627         for (me = mapl ; me ; me = me->next) {
628                 mdu_array_info_t array;
629                 mdu_bitmap_file_t bmf;
630                 struct mdinfo *sra;
631                 int mdfd = open_mddev(me->path, 0);
632
633                 if (mdfd < 0)
634                         continue;
635                 if (ioctl(mdfd, GET_ARRAY_INFO, &array) == 0 ||
636                     errno != ENODEV) {
637                         close(mdfd);
638                         continue;
639                 }
640                 /* Ok, we can try this one.   Maybe it needs a bitmap */
641                 for (mddev = devs ; mddev ; mddev = mddev->next)
642                         if (mddev->devname
643                             && strcmp(mddev->devname, me->path) == 0)
644                                 break;
645                 if (mddev && mddev->bitmap_file) {
646                         /*
647                          * Note: early kernels will wrongly fail this, so it
648                          * is a hint only
649                          */
650                         int added = -1;
651                         if (ioctl(mdfd, GET_ARRAY_INFO, &bmf) < 0) {
652                                 int bmfd = open(mddev->bitmap_file, O_RDWR);
653                                 if (bmfd >= 0) {
654                                         added = ioctl(mdfd, SET_BITMAP_FILE,
655                                                       bmfd);
656                                         close(bmfd);
657                                 }
658                         }
659                         if (verbose >= 0) {
660                                 if (added == 0)
661                                         fprintf(stderr, Name
662                                                 ": Added bitmap %s to %s\n",
663                                                 mddev->bitmap_file, me->path);
664                                 else if (errno != EEXIST)
665                                         fprintf(stderr, Name
666                                            ": Failed to add bitmap to %s: %s\n",
667                                                 me->path, strerror(errno));
668                         }
669                 }
670                 sra = sysfs_read(mdfd, 0, 0);
671                 if (sra) {
672                         if (sysfs_set_str(sra, NULL,
673                                           "array_state", "read-auto") == 0) {
674                                 if (verbose >= 0)
675                                         fprintf(stderr, Name
676                                                 ": started array %s\n",
677                                                 me->path);
678                         } else {
679                                 fprintf(stderr, Name
680                                         ": failed to start array %s: %s\n",
681                                         me->path, strerror(errno));
682                                 rv = 1;
683                         }
684                 }
685         }
686         return rv;
687 }
688
689 static char *container2devname(char *devname)
690 {
691         char *mdname = NULL;
692
693         if (devname[0] == '/') {
694                 int fd = open(devname, O_RDONLY);
695                 if (fd >= 0) {
696                         mdname = devnum2devname(fd2devnum(fd));
697                         close(fd);
698                 }
699         } else {
700                 int uuid[4];
701                 struct map_ent *mp, *map = NULL;
702                                         
703                 if (!parse_uuid(devname, uuid))
704                         return mdname;
705                 mp = map_by_uuid(&map, uuid);
706                 if (mp)
707                         mdname = devnum2devname(mp->devnum);
708                 map_free(map);
709         }
710
711         return mdname;
712 }
713
714 int Incremental_container(struct supertype *st, char *devname, int verbose,
715                           int runstop, int autof, int trustworthy)
716 {
717         /* Collect the contents of this container and for each
718          * array, choose a device name and assemble the array.
719          */
720
721         struct mdinfo *list = st->ss->container_content(st);
722         struct mdinfo *ra;
723         struct map_ent *map = NULL;
724
725         map_lock(&map);
726
727         for (ra = list ; ra ; ra = ra->next) {
728                 int mdfd;
729                 char chosen_name[1024];
730                 struct map_ent *mp;
731                 struct mddev_ident_s *match = NULL;
732                 int err;
733
734                 mp = map_by_uuid(&map, ra->uuid);
735
736                 if (mp) {
737                         mdfd = open_dev(mp->devnum);
738                         strcpy(chosen_name, mp->path);
739                 } else {
740
741                         /* Check in mdadm.conf for devices == devname and
742                          * member == ra->text_version after second slash.
743                          */
744                         char *sub = strchr(ra->text_version+1, '/');
745                         struct mddev_ident_s *array_list;
746                         if (sub) {
747                                 sub++;
748                                 array_list = conf_get_ident(NULL);
749                         } else
750                                 array_list = NULL;
751                         for(; array_list ; array_list = array_list->next) {
752                                 char *dn;
753                                 if (array_list->member == NULL ||
754                                     array_list->container == NULL)
755                                         continue;
756                                 if (strcmp(array_list->member, sub) != 0)
757                                         continue;
758                                 if (array_list->uuid_set &&
759                                     !same_uuid(ra->uuid, array_list->uuid, st->ss->swapuuid))
760                                         continue;
761                                 dn = container2devname(array_list->container);
762                                 if (dn == NULL)
763                                         continue;
764                                 if (strncmp(dn, ra->text_version+1,
765                                             strlen(dn)) != 0 ||
766                                     ra->text_version[strlen(dn)+1] != '/') {
767                                         free(dn);
768                                         continue;
769                                 }
770                                 free(dn);
771                                 /* we have a match */
772                                 match = array_list;
773                                 if (verbose>0)
774                                         fprintf(stderr, Name ": match found for member %s\n",
775                                                 array_list->member);
776                                 break;
777                         }
778
779                         mdfd = create_mddev(match ? match->devname : NULL,
780                                             ra->name,
781                                             autof,
782                                             trustworthy,
783                                             chosen_name);
784                 }
785
786                 if (mdfd < 0) {
787                         fprintf(stderr, Name ": failed to open %s: %s.\n",
788                                 chosen_name, strerror(errno));
789                         return 2;
790                 }
791
792                 err = assemble_container_content(st, mdfd, ra, runstop,
793                                                  chosen_name, verbose);
794                 if (err)
795                         return err;
796         }
797         map_unlock(&map);
798         return 0;
799 }