Replace sysarray with mdinfo
[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 sensibe 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, reject.
52          * 4/ Determine device number.
53          * - If in mdadm.conf with std name, use that
54          * - UUID in /var/run/mdadm.map  use that
55          * - If name is suggestive, use that. unless in use with different uuid.
56          * - Choose a free, high number.
57          * - Use a partitioned device unless strong suggestion not to.
58          *         e.g. auto=md
59          * 5/ Find out if array already exists
60          * 5a/ if it does not
61          * - choose a name, from mdadm.conf or 'name' field in array.
62          * - create the array
63          * - add the device
64          * 5b/ if it does
65          * - check one drive in array to make sure metadata is a reasonably
66          *       close match.  Reject if not (e.g. different type)
67          * - add the device
68          * 6/ Make sure /var/run/mdadm.map contains this array.
69          * 7/ Is there enough devices to possibly start the array?
70          * 7a/ if not, finish with success.
71          * 7b/ if yes,
72          * - read all metadata and arrange devices like -A does
73          * - if number of OK devices match expected, or -R and there are enough,
74          *   start the array (auto-readonly).
75          */
76         struct stat stb;
77         struct mdinfo info, info2;
78         struct mddev_ident_s *array_list, *match;
79         char chosen_name[1024];
80         int rv;
81         int devnum;
82         struct map_ent *mp, *map = NULL;
83         int dfd, mdfd;
84         char *avail;
85         int active_disks;
86
87
88         struct createinfo *ci = conf_get_create_info();
89
90         if (autof == 0)
91                 autof = ci->autof;
92
93         /* 1/ Check if devices is permitted by mdadm.conf */
94
95         if (!conf_test_dev(devname)) {
96                 if (verbose >= 0)
97                         fprintf(stderr, Name
98                                 ": %s not permitted by mdadm.conf.\n",
99                                 devname);
100                 return 1;
101         }
102
103         /* 2/ Find metadata, reject if none appropriate (check
104          *            version/name from args) */
105
106         dfd = dev_open(devname, O_RDONLY|O_EXCL);
107         if (dfd < 0) {
108                 if (verbose >= 0)
109                         fprintf(stderr, Name ": cannot open %s: %s.\n",
110                                 devname, strerror(errno));
111                 return 1;
112         }
113         if (fstat(dfd, &stb) < 0) {
114                 if (verbose >= 0)
115                         fprintf(stderr, Name ": fstat failed for %s: %s.\n",
116                                 devname, strerror(errno));
117                 close(dfd);
118                 return 1;
119         }
120         if ((stb.st_mode & S_IFMT) != S_IFBLK) {
121                 if (verbose >= 0)
122                         fprintf(stderr, Name ": %s is not a block device.\n",
123                                 devname);
124                 close(dfd);
125                 return 1;
126         }
127
128         if (st == NULL && (st = guess_super(dfd)) == NULL) {
129                 if (verbose >= 0)
130                         fprintf(stderr, Name
131                                 ": no recognisable superblock on %s.\n",
132                                 devname);
133                 close(dfd);
134                 return 1;
135         }
136         if (st->ss->load_super(st, dfd, NULL)) {
137                 if (verbose >= 0)
138                         fprintf(stderr, Name ": no RAID superblock on %s.\n",
139                                 devname);
140                 close(dfd);
141                 return 1;
142         }
143         st->ss->getinfo_super(st, &info);
144         close (dfd);
145
146         /* 3/ Check if there is a match in mdadm.conf */
147
148         array_list = conf_get_ident(NULL);
149         match = NULL;
150         for (; array_list; array_list = array_list->next) {
151                 if (array_list->uuid_set &&
152                     same_uuid(array_list->uuid, info.uuid, st->ss->swapuuid)
153                     == 0) {
154                         if (verbose >= 2)
155                                 fprintf(stderr, Name
156                                         ": UUID differs from %s.\n",
157                                         array_list->devname);
158                         continue;
159                 }
160                 if (array_list->name[0] &&
161                     strcasecmp(array_list->name, info.name) != 0) {
162                         if (verbose >= 2)
163                                 fprintf(stderr, Name
164                                         ": Name differs from %s.\n",
165                                         array_list->devname);
166                         continue;
167                 }
168                 if (array_list->devices &&
169                     !match_oneof(array_list->devices, devname)) {
170                         if (verbose >= 2)
171                                 fprintf(stderr, Name
172                                         ": Not a listed device for %s.\n",
173                                         array_list->devname);
174                         continue;
175                 }
176                 if (array_list->super_minor != UnSet &&
177                     array_list->super_minor != info.array.md_minor) {
178                         if (verbose >= 2)
179                                 fprintf(stderr, Name
180                                         ": Different super-minor to %s.\n",
181                                         array_list->devname);
182                         continue;
183                 }
184                 if (!array_list->uuid_set &&
185                     !array_list->name[0] &&
186                     !array_list->devices &&
187                     array_list->super_minor == UnSet) {
188                         if (verbose  >= 2)
189                                 fprintf(stderr, Name
190                              ": %s doesn't have any identifying information.\n",
191                                         array_list->devname);
192                         continue;
193                 }
194                 /* FIXME, should I check raid_disks and level too?? */
195
196                 if (match) {
197                         if (verbose >= 0)
198                                 fprintf(stderr, Name
199                    ": we match both %s and %s - cannot decide which to use.\n",
200                                         match->devname, array_list->devname);
201                         return 2;
202                 }
203                 match = array_list;
204         }
205
206         /* 3a/ if not, check for homehost match.  If no match, reject. */
207         if (!match) {
208                 if (homehost == NULL ||
209                     st->ss->match_home(st, homehost) == 0) {
210                         if (verbose >= 0)
211                                 fprintf(stderr, Name
212               ": not found in mdadm.conf and not identified by homehost.\n");
213                         return 2;
214                 }
215         }
216         /* 4/ Determine device number. */
217         /* - If in mdadm.conf with std name, use that */
218         /* - UUID in /var/run/mdadm.map  use that */
219         /* - If name is suggestive, use that. unless in use with */
220         /*           different uuid. */
221         /* - Choose a free, high number. */
222         /* - Use a partitioned device unless strong suggestion not to. */
223         /*         e.g. auto=md */
224         if (match && is_standard(match->devname, &devnum))
225                 /* We have devnum now */;
226         else if ((mp = map_by_uuid(&map, info.uuid)) != NULL)
227                 devnum = mp->devnum;
228         else {
229                 /* Have to guess a bit. */
230                 int use_partitions = 1;
231                 char *np, *ep;
232                 if ((autof&7) == 3 || (autof&7) == 5)
233                         use_partitions = 0;
234                 np = strchr(info.name, ':');
235                 if (np)
236                         np++;
237                 else
238                         np = info.name;
239                 devnum = strtoul(np, &ep, 10);
240                 if (ep > np && *ep == 0) {
241                         /* This is a number.  Let check that it is unused. */
242                         if (mddev_busy(use_partitions ? (-1-devnum) : devnum))
243                                 devnum = -1;
244                 } else
245                         devnum = -1;
246
247                 if (devnum < 0) {
248                         /* Haven't found anything yet, choose something free */
249                         /* There is similar code in mdopen.c - should unify */
250                         for (devnum = 127 ; devnum != 128 ;
251                              devnum = devnum ? devnum-1 : (1<<22)-1) {
252                                 if (mddev_busy(use_partitions ?
253                                                (-1-devnum) : devnum))
254                                         break;
255                         }
256                         if (devnum == 128) {
257                                 fprintf(stderr, Name
258                                         ": No spare md devices!!\n");
259                                 return 2;
260                         }
261                 }
262                 devnum = use_partitions ? (-1-devnum) : devnum;
263         }
264         mdfd = open_mddev_devnum(match ? match->devname : NULL,
265                                  devnum,
266                                  info.name,
267                                  chosen_name);
268         if (mdfd < 0) {
269                 fprintf(stderr, Name ": failed to open %s: %s.\n",
270                         chosen_name, strerror(errno));
271                 return 2;
272         }
273         /* 5/ Find out if array already exists */
274         if (! mddev_busy(devnum)) {
275         /* 5a/ if it does not */
276         /* - choose a name, from mdadm.conf or 'name' field in array. */
277         /* - create the array */
278         /* - add the device */
279                 mdu_array_info_t ainf;
280                 mdu_disk_info_t disk;
281                 char md[20];
282                 struct mdinfo *sra;
283
284                 memset(&ainf, 0, sizeof(ainf));
285                 ainf.major_version = st->ss->major;
286                 ainf.minor_version = st->minor_version;
287                 if (ioctl(mdfd, SET_ARRAY_INFO, &ainf) != 0) {
288                         fprintf(stderr, Name
289                                 ": SET_ARRAY_INFO failed for %s: %s\b",
290                                 chosen_name, strerror(errno));
291                         close(mdfd);
292                         return 2;
293                 }
294                 sprintf(md, "%d.%d\n", st->ss->major, st->minor_version);
295                 sra = sysfs_read(mdfd, devnum, GET_VERSION);
296                 sysfs_set_str(sra, NULL, "metadata_version", md);
297                 memset(&disk, 0, sizeof(disk));
298                 disk.major = major(stb.st_rdev);
299                 disk.minor = minor(stb.st_rdev);
300                 sysfs_free(sra);
301                 if (ioctl(mdfd, ADD_NEW_DISK, &disk) != 0) {
302                         fprintf(stderr, Name ": failed to add %s to %s: %s.\n",
303                                 devname, chosen_name, strerror(errno));
304                         ioctl(mdfd, STOP_ARRAY, 0);
305                         close(mdfd);
306                         return 2;
307                 }
308                 sra = sysfs_read(mdfd, devnum, GET_DEVS);
309                 if (!sra || !sra->devs || sra->devs->disk.raid_disk >= 0) {
310                         /* It really should be 'none' - must be old buggy
311                          * kernel, and mdadm -I may not be able to complete.
312                          * So reject it.
313                          */
314                         ioctl(mdfd, STOP_ARRAY, NULL);
315                         fprintf(stderr, Name
316                       ": You have an old buggy kernel which cannot support\n"
317                                 "      --incremental reliably.  Aborting.\n");
318                         close(mdfd);
319                         sysfs_free(sra);
320                         return 2;
321                 }
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                 mdu_disk_info_t disk;
330                 int err;
331                 struct mdinfo *sra;
332                 struct supertype *st2;
333                 sra = sysfs_read(mdfd, devnum, (GET_VERSION | GET_DEVS |
334                                                 GET_STATE));
335                 if (sra->array.major_version != st->ss->major ||
336                     sra->array.minor_version != st->minor_version) {
337                         if (verbose >= 0)
338                                 fprintf(stderr, Name
339               ": %s has different metadata to chosen array %s %d.%d %d.%d.\n",
340                                         devname, chosen_name,
341                                         sra->array.major_version,
342                                         sra->array.minor_version,
343                                         st->ss->major, st->minor_version);
344                         close(mdfd);
345                         return 1;
346                 }
347                 sprintf(dn, "%d:%d", sra->devs->disk.major,
348                         sra->devs->disk.minor);
349                 dfd2 = dev_open(dn, O_RDONLY);
350                 st2 = dup_super(st);
351                 if (st2->ss->load_super(st2, dfd2, NULL)) {
352                         fprintf(stderr, Name
353                                 ": Strange error loading metadata for %s.\n",
354                                 chosen_name);
355                         close(mdfd);
356                         close(dfd2);
357                         return 2;
358                 }
359                 close(dfd2);
360                 st2->ss->getinfo_super(st2, &info2);
361                 st2->ss->free_super(st2);
362                 if (info.array.level != info2.array.level ||
363                     memcmp(info.uuid, info2.uuid, 16) != 0 ||
364                     info.array.raid_disks != info2.array.raid_disks) {
365                         fprintf(stderr, Name
366                                 ": unexpected difference between %s and %s.\n",
367                                 chosen_name, devname);
368                         close(mdfd);
369                         return 2;
370                 }
371                 memset(&disk, 0, sizeof(disk));
372                 disk.major = major(stb.st_rdev);
373                 disk.minor = minor(stb.st_rdev);
374                 err = ioctl(mdfd, ADD_NEW_DISK, &disk);
375                 if (err < 0 && errno == EBUSY) {
376                         /* could be another device present with the same
377                          * disk.number. Find and reject any such
378                          */
379                         find_reject(mdfd, st, sra, info.disk.number,
380                                     info.events, verbose, chosen_name);
381                         err = ioctl(mdfd, ADD_NEW_DISK, &disk);
382                 }
383                 if (err < 0) {
384                         fprintf(stderr, Name ": failed to add %s to %s: %s.\n",
385                                 devname, chosen_name, strerror(errno));
386                         close(mdfd);
387                         return 2;
388                 }
389         }
390         /* 6/ Make sure /var/run/mdadm.map contains this array. */
391         map_update(&map, devnum,
392                    info.array.major_version,
393                    info.array.minor_version,
394                    info.uuid, chosen_name);
395
396         /* 7/ Is there enough devices to possibly start the array? */
397         /* 7a/ if not, finish with success. */
398         avail = NULL;
399         active_disks = count_active(st, mdfd, &avail, &info);
400         if (enough(info.array.level, info.array.raid_disks,
401                    info.array.layout, info.array.state & 1,
402                    avail, active_disks) == 0) {
403                 free(avail);
404                 if (verbose >= 0)
405                         fprintf(stderr, Name
406                              ": %s attached to %s, not enough to start (%d).\n",
407                                 devname, chosen_name, active_disks);
408                 close(mdfd);
409                 return 0;
410         }
411         free(avail);
412
413         /* 7b/ if yes, */
414         /* - if number of OK devices match expected, or -R and there */
415         /*             are enough, */
416         /*   + add any bitmap file  */
417         /*   + start the array (auto-readonly). */
418 {
419         mdu_array_info_t ainf;
420
421         if (ioctl(mdfd, GET_ARRAY_INFO, &ainf) == 0) {
422                 if (verbose >= 0)
423                         fprintf(stderr, Name
424                            ": %s attached to %s which is already active.\n",
425                                 devname, chosen_name);
426                 close (mdfd);
427                 return 0;
428         }
429 }
430         if (runstop > 0 || active_disks >= info.array.working_disks) {
431                 struct mdinfo *sra;
432                 /* Let's try to start it */
433                 if (match && match->bitmap_file) {
434                         int bmfd = open(match->bitmap_file, O_RDWR);
435                         if (bmfd < 0) {
436                                 fprintf(stderr, Name
437                                         ": Could not open bitmap file %s.\n",
438                                         match->bitmap_file);
439                                 close(mdfd);
440                                 return 1;
441                         }
442                         if (ioctl(mdfd, SET_BITMAP_FILE, bmfd) != 0) {
443                                 close(bmfd);
444                                 fprintf(stderr, Name
445                                         ": Failed to set bitmapfile for %s.\n",
446                                         chosen_name);
447                                 close(mdfd);
448                                 return 1;
449                         }
450                         close(bmfd);
451                 }
452                 sra = sysfs_read(mdfd, devnum, 0);
453                 if (sra == NULL || active_disks >= info.array.working_disks)
454                         rv = ioctl(mdfd, RUN_ARRAY, NULL);
455                 else
456                         rv = sysfs_set_str(sra, NULL,
457                                            "array_state", "read-auto");
458                 if (rv == 0) {
459                         if (verbose >= 0)
460                                 fprintf(stderr, Name
461                            ": %s attached to %s, which has been started.\n",
462                                         devname, chosen_name);
463                         rv = 0;
464                 } else {
465                         fprintf(stderr, Name
466                              ": %s attached to %s, but failed to start: %s.\n",
467                                 devname, chosen_name, strerror(errno));
468                         rv = 1;
469                 }
470         } else {
471                 if (verbose >= 0)
472                         fprintf(stderr, Name
473                           ": %s attached to %s, not enough to start safely.\n",
474                                 devname, chosen_name);
475                 rv = 0;
476         }
477         close(mdfd);
478         return rv;
479 }
480
481 static void find_reject(int mdfd, struct supertype *st, struct mdinfo *sra,
482                         int number, __u64 events, int verbose,
483                         char *array_name)
484 {
485         /* Find a device attached to this array with a disk.number of number
486          * and events less than the passed events, and remove the device.
487          */
488         struct mdinfo *d;
489         mdu_array_info_t ra;
490
491         if (ioctl(mdfd, GET_ARRAY_INFO, &ra) == 0)
492                 return; /* not safe to remove from active arrays
493                          * without thinking more */
494
495         for (d = sra->devs; d ; d = d->next) {
496                 char dn[10];
497                 int dfd;
498                 struct mdinfo info;
499                 sprintf(dn, "%d:%d", d->disk.major, d->disk.minor);
500                 dfd = dev_open(dn, O_RDONLY);
501                 if (dfd < 0)
502                         continue;
503                 if (st->ss->load_super(st, dfd, NULL)) {
504                         close(dfd);
505                         continue;
506                 }
507                 st->ss->getinfo_super(st, &info);
508                 st->ss->free_super(st);
509                 close(dfd);
510
511                 if (info.disk.number != number ||
512                     info.events >= events)
513                         continue;
514
515                 if (d->disk.raid_disk > -1)
516                         sysfs_set_str(sra, d, "slot", "none");
517                 if (sysfs_set_str(sra, d, "state", "remove") == 0)
518                         if (verbose >= 0)
519                                 fprintf(stderr, Name
520                                         ": removing old device %s from %s\n",
521                                         d->sys_name+4, array_name);
522         }
523 }
524
525 static int count_active(struct supertype *st, int mdfd, char **availp,
526                         struct mdinfo *bestinfo)
527 {
528         /* count how many devices in sra think they are active */
529         struct mdinfo *d;
530         int cnt = 0, cnt1 = 0;
531         __u64 max_events = 0;
532         struct mdinfo *sra = sysfs_read(mdfd, -1, GET_DEVS | GET_STATE);
533         char *avail = NULL;
534
535         for (d = sra->devs ; d ; d = d->next) {
536                 char dn[30];
537                 int dfd;
538                 int ok;
539                 struct mdinfo info;
540
541                 sprintf(dn, "%d:%d", d->disk.major, d->disk.minor);
542                 dfd = dev_open(dn, O_RDONLY);
543                 if (dfd < 0)
544                         continue;
545                 ok =  st->ss->load_super(st, dfd, NULL);
546                 close(dfd);
547                 if (ok != 0)
548                         continue;
549                 st->ss->getinfo_super(st, &info);
550                 if (info.disk.state & (1<<MD_DISK_SYNC))
551                 {
552                         if (avail == NULL) {
553                                 avail = malloc(info.array.raid_disks);
554                                 memset(avail, 0, info.array.raid_disks);
555                         }
556                         if (cnt == 0) {
557                                 cnt++;
558                                 max_events = info.events;
559                                 avail[info.disk.raid_disk] = 2;
560                                 st->ss->getinfo_super(st, bestinfo);
561                         } else if (info.events == max_events) {
562                                 cnt++;
563                                 avail[info.disk.raid_disk] = 2;
564                         } else if (info.events == max_events-1) {
565                                 cnt1++;
566                                 avail[info.disk.raid_disk] = 1;
567                         } else if (info.events < max_events - 1)
568                                 ;
569                         else if (info.events == max_events+1) {
570                                 int i;
571                                 cnt1 = cnt;
572                                 cnt = 1;
573                                 max_events = info.events;
574                                 for (i=0; i<info.array.raid_disks; i++)
575                                         if (avail[i])
576                                                 avail[i]--;
577                                 avail[info.disk.raid_disk] = 2;
578                                 st->ss->getinfo_super(st, bestinfo);
579                         } else { /* info.events much bigger */
580                                 cnt = 1; cnt1 = 0;
581                                 memset(avail, 0, info.disk.raid_disk);
582                                 max_events = info.events;
583                                 st->ss->getinfo_super(st, bestinfo);
584                         }
585                 }
586                 st->ss->free_super(st);
587         }
588         return cnt + cnt1;
589 }
590
591 void RebuildMap(void)
592 {
593         struct mdstat_ent *mdstat = mdstat_read(0, 0);
594         struct mdstat_ent *md;
595         struct map_ent *map = NULL;
596         int mdp = get_mdp_major();
597
598         for (md = mdstat ; md ; md = md->next) {
599                 struct mdinfo *sra = sysfs_read(-1, md->devnum, GET_DEVS);
600                 struct mdinfo *sd;
601
602                 for (sd = sra->devs ; sd ; sd = sd->next) {
603                         char dn[30];
604                         int dfd;
605                         int ok;
606                         struct supertype *st;
607                         char *path;
608                         struct mdinfo info;
609
610                         sprintf(dn, "%d:%d", sd->disk.major, sd->disk.minor);
611                         dfd = dev_open(dn, O_RDONLY);
612                         if (dfd < 0)
613                                 continue;
614                         st = guess_super(dfd);
615                         if ( st == NULL)
616                                 ok = -1;
617                         else
618                                 ok = st->ss->load_super(st, dfd, NULL);
619                         close(dfd);
620                         if (ok != 0)
621                                 continue;
622                         st->ss->getinfo_super(st, &info);
623                         if (md->devnum > 0)
624                                 path = map_dev(MD_MAJOR, md->devnum, 0);
625                         else
626                                 path = map_dev(mdp, (-1-md->devnum)<< 6, 0);
627                         map_add(&map, md->devnum, st->ss->major,
628                                 st->minor_version,
629                                 info.uuid, path ? : "/unknown");
630                         st->ss->free_super(st);
631                         break;
632                 }
633         }
634         map_write(map);
635         map_free(map);
636 }
637
638 int IncrementalScan(int verbose)
639 {
640         /* look at every device listed in the 'map' file.
641          * If one is found that is not running then:
642          *  look in mdadm.conf for bitmap file.
643          *   if one exists, but array has none, add it.
644          *  try to start array in auto-readonly mode
645          */
646         struct map_ent *mapl = NULL;
647         struct map_ent *me;
648         mddev_ident_t devs, mddev;
649         int rv = 0;
650
651         map_read(&mapl);
652         devs = conf_get_ident(NULL);
653
654         for (me = mapl ; me ; me = me->next) {
655                 char path[1024];
656                 mdu_array_info_t array;
657                 mdu_bitmap_file_t bmf;
658                 struct mdinfo *sra;
659                 int mdfd = open_mddev_devnum(me->path, me->devnum, NULL, path);
660                 if (mdfd < 0)
661                         continue;
662                 if (ioctl(mdfd, GET_ARRAY_INFO, &array) == 0 ||
663                     errno != ENODEV) {
664                         close(mdfd);
665                         continue;
666                 }
667                 /* Ok, we can try this one.   Maybe it needs a bitmap */
668                 for (mddev = devs ; mddev ; mddev = mddev->next)
669                         if (strcmp(mddev->devname, me->path) == 0)
670                                 break;
671                 if (mddev && mddev->bitmap_file) {
672                         /*
673                          * Note: early kernels will wrongly fail this, so it
674                          * is a hint only
675                          */
676                         int added = -1;
677                         if (ioctl(mdfd, GET_ARRAY_INFO, &bmf) < 0) {
678                                 int bmfd = open(mddev->bitmap_file, O_RDWR);
679                                 if (bmfd >= 0) {
680                                         added = ioctl(mdfd, SET_BITMAP_FILE,
681                                                       bmfd);
682                                         close(bmfd);
683                                 }
684                         }
685                         if (verbose >= 0) {
686                                 if (added == 0)
687                                         fprintf(stderr, Name
688                                                 ": Added bitmap %s to %s\n",
689                                                 mddev->bitmap_file, me->path);
690                                 else if (errno != EEXIST)
691                                         fprintf(stderr, Name
692                                            ": Failed to add bitmap to %s: %s\n",
693                                                 me->path, strerror(errno));
694                         }
695                 }
696                 sra = sysfs_read(mdfd, 0, 0);
697                 if (sra) {
698                         if (sysfs_set_str(sra, NULL,
699                                           "array_state", "read-auto") == 0) {
700                                 if (verbose >= 0)
701                                         fprintf(stderr, Name
702                                                 ": started array %s\n",
703                                                 me->path);
704                         } else {
705                                 fprintf(stderr, Name
706                                         ": failed to start array %s: %s\n",
707                                         me->path, strerror(errno));
708                                 rv = 1;
709                         }
710                 }
711         }
712         return rv;
713 }