Support external metadata recovery-resume
[thirdparty/mdadm.git] / sysfs.c
1 /*
2  * sysfs - extract md related information from sysfs.  Part of:
3  * mdadm - manage Linux "md" devices aka RAID arrays.
4  *
5  * Copyright (C) 2006-2009 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  */
25
26 #include        "mdadm.h"
27 #include        <dirent.h>
28 #include        <ctype.h>
29
30 int load_sys(char *path, char *buf)
31 {
32         int fd = open(path, O_RDONLY);
33         int n;
34         if (fd < 0)
35                 return -1;
36         n = read(fd, buf, 1024);
37         close(fd);
38         if (n <0 || n >= 1024)
39                 return -1;
40         buf[n] = 0;
41         if (n && buf[n-1] == '\n')
42                 buf[n-1] = 0;
43         return 0;
44 }
45
46 void sysfs_free(struct mdinfo *sra)
47 {
48         while (sra) {
49                 struct mdinfo *sra2 = sra->next;
50                 while (sra->devs) {
51                         struct mdinfo *d = sra->devs;
52                         sra->devs = d->next;
53                         free(d);
54                 }
55                 free(sra);
56                 sra = sra2;
57         }
58 }
59
60 int sysfs_open(int devnum, char *devname, char *attr)
61 {
62         char fname[50];
63         int fd;
64         char *mdname = devnum2devname(devnum);
65
66         if (!mdname)
67                 return -1;
68
69         sprintf(fname, "/sys/block/%s/md/", mdname);
70         if (devname) {
71                 strcat(fname, devname);
72                 strcat(fname, "/");
73         }
74         strcat(fname, attr);
75         fd = open(fname, O_RDWR);
76         if (fd < 0 && errno == EACCES)
77                 fd = open(fname, O_RDONLY);
78         free(mdname);
79         return fd;
80 }
81
82 void sysfs_init(struct mdinfo *mdi, int fd, int devnum)
83 {
84         mdi->sys_name[0] = 0;
85         if (fd >= 0) {
86                 mdu_version_t vers;
87                 if (ioctl(fd, RAID_VERSION, &vers) != 0)
88                         return;
89                 devnum = fd2devnum(fd);
90         }
91         if (devnum == NoMdDev)
92                 return;
93         if (devnum >= 0)
94                 sprintf(mdi->sys_name, "md%d", devnum);
95         else
96                 sprintf(mdi->sys_name, "md_d%d",
97                         -1-devnum);
98 }
99
100
101 struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
102 {
103         /* Longest possible name in sysfs, mounted at /sys, is
104          *  /sys/block/md_dXXX/md/dev-XXXXX/block/dev
105          *  /sys/block/md_dXXX/md/metadata_version
106          * which is about 41 characters.  50 should do for now
107          */
108         char fname[50];
109         char buf[1024];
110         char *base;
111         char *dbase;
112         struct mdinfo *sra;
113         struct mdinfo *dev;
114         DIR *dir = NULL;
115         struct dirent *de;
116
117         sra = malloc(sizeof(*sra));
118         if (sra == NULL)
119                 return sra;
120         memset(sra, 0, sizeof(*sra));
121         sysfs_init(sra, fd, devnum);
122         if (sra->sys_name[0] == 0) {
123                 free(sra);
124                 return NULL;
125         }
126
127         sprintf(fname, "/sys/block/%s/md/", sra->sys_name);
128         base = fname + strlen(fname);
129
130         sra->devs = NULL;
131         if (options & GET_VERSION) {
132                 strcpy(base, "metadata_version");
133                 if (load_sys(fname, buf))
134                         goto abort;
135                 if (strncmp(buf, "none", 4) == 0) {
136                         sra->array.major_version =
137                                 sra->array.minor_version = -1;
138                         strcpy(sra->text_version, "");
139                 } else if (strncmp(buf, "external:", 9) == 0) {
140                         sra->array.major_version = -1;
141                         sra->array.minor_version = -2;
142                         strcpy(sra->text_version, buf+9);
143                 } else {
144                         sscanf(buf, "%d.%d",
145                                &sra->array.major_version,
146                                &sra->array.minor_version);
147                         strcpy(sra->text_version, buf);
148                 }
149         }
150         if (options & GET_LEVEL) {
151                 strcpy(base, "level");
152                 if (load_sys(fname, buf))
153                         goto abort;
154                 sra->array.level = map_name(pers, buf);
155         }
156         if (options & GET_LAYOUT) {
157                 strcpy(base, "layout");
158                 if (load_sys(fname, buf))
159                         goto abort;
160                 sra->array.layout = strtoul(buf, NULL, 0);
161         }
162         if (options & GET_DISKS) {
163                 strcpy(base, "raid_disks");
164                 if (load_sys(fname, buf))
165                         goto abort;
166                 sra->array.raid_disks = strtoul(buf, NULL, 0);
167         }
168         if (options & GET_DEGRADED) {
169                 strcpy(base, "degraded");
170                 if (load_sys(fname, buf))
171                         goto abort;
172                 sra->array.failed_disks = strtoul(buf, NULL, 0);
173         }
174         if (options & GET_COMPONENT) {
175                 strcpy(base, "component_size");
176                 if (load_sys(fname, buf))
177                         goto abort;
178                 sra->component_size = strtoull(buf, NULL, 0);
179                 /* sysfs reports "K", but we want sectors */
180                 sra->component_size *= 2;
181         }
182         if (options & GET_CHUNK) {
183                 strcpy(base, "chunk_size");
184                 if (load_sys(fname, buf))
185                         goto abort;
186                 sra->array.chunk_size = strtoul(buf, NULL, 0);
187         }
188         if (options & GET_CACHE) {
189                 strcpy(base, "stripe_cache_size");
190                 if (load_sys(fname, buf))
191                         goto abort;
192                 sra->cache_size = strtoul(buf, NULL, 0);
193         }
194         if (options & GET_MISMATCH) {
195                 strcpy(base, "mismatch_cnt");
196                 if (load_sys(fname, buf))
197                         goto abort;
198                 sra->mismatch_cnt = strtoul(buf, NULL, 0);
199         }
200         if (options & GET_SAFEMODE) {
201                 int scale = 1;
202                 int dot = 0;
203                 int i;
204                 unsigned long msec;
205                 size_t len;
206
207                 strcpy(base, "safe_mode_delay");
208                 if (load_sys(fname, buf))
209                         goto abort;
210
211                 /* remove a period, and count digits after it */
212                 len = strlen(buf);
213                 for (i = 0; i < len; i++) {
214                         if (dot) {
215                                 if (isdigit(buf[i])) {
216                                         buf[i-1] = buf[i];
217                                         scale *= 10;
218                                 }
219                                 buf[i] = 0;
220                         } else if (buf[i] == '.') {
221                                 dot=1;
222                                 buf[i] = 0;
223                         }
224                 }
225                 msec = strtoul(buf, NULL, 10);
226                 msec = (msec * 1000) / scale;
227                 sra->safe_mode_delay = msec;
228         }
229
230         if (! (options & GET_DEVS))
231                 return sra;
232
233         /* Get all the devices as well */
234         *base = 0;
235         dir = opendir(fname);
236         if (!dir)
237                 goto abort;
238         sra->array.spare_disks = 0;
239
240         while ((de = readdir(dir)) != NULL) {
241                 char *ep;
242                 if (de->d_ino == 0 ||
243                     strncmp(de->d_name, "dev-", 4) != 0)
244                         continue;
245                 strcpy(base, de->d_name);
246                 dbase = base + strlen(base);
247                 *dbase++ = '/';
248
249                 dev = malloc(sizeof(*dev));
250                 if (!dev)
251                         goto abort;
252
253                 /* Always get slot, major, minor */
254                 strcpy(dbase, "slot");
255                 if (load_sys(fname, buf)) {
256                         /* hmm... unable to read 'slot' maybe the device
257                          * is going away?
258                          */
259                         strcpy(dbase, "block");
260                         if (readlink(fname, buf, sizeof(buf)) < 0 &&
261                             errno != ENAMETOOLONG) {
262                                 /* ...yup device is gone */
263                                 free(dev);
264                                 continue;
265                         } else {
266                                 /* slot is unreadable but 'block' link
267                                  * still intact... something bad is happening
268                                  * so abort
269                                  */
270                                 free(dev);
271                                 goto abort;
272                         }
273                         
274                 }
275                 strcpy(dev->sys_name, de->d_name);
276                 dev->disk.raid_disk = strtoul(buf, &ep, 10);
277                 if (*ep) dev->disk.raid_disk = -1;
278
279                 strcpy(dbase, "block/dev");
280                 if (load_sys(fname, buf)) {
281                         free(dev);
282                         if (options & SKIP_GONE_DEVS)
283                                 continue;
284                         else
285                                 goto abort;
286                 }
287                 sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
288
289                 /* special case check for block devices that can go 'offline' */
290                 if (options & SKIP_GONE_DEVS) {
291                         strcpy(dbase, "block/device/state");
292                         if (load_sys(fname, buf) == 0 &&
293                             strncmp(buf, "offline", 7) == 0) {
294                                 free(dev);
295                                 continue;
296                         }
297                 }
298
299                 /* finally add this disk to the array */
300                 dev->next = sra->devs;
301                 sra->devs = dev;
302
303                 if (options & GET_OFFSET) {
304                         strcpy(dbase, "offset");
305                         if (load_sys(fname, buf))
306                                 goto abort;
307                         dev->data_offset = strtoull(buf, NULL, 0);
308                 }
309                 if (options & GET_SIZE) {
310                         strcpy(dbase, "size");
311                         if (load_sys(fname, buf))
312                                 goto abort;
313                         dev->component_size = strtoull(buf, NULL, 0) * 2;
314                 }
315                 if (options & GET_STATE) {
316                         dev->disk.state = 0;
317                         strcpy(dbase, "state");
318                         if (load_sys(fname, buf))
319                                 goto abort;
320                         if (strstr(buf, "in_sync"))
321                                 dev->disk.state |= (1<<MD_DISK_SYNC);
322                         if (strstr(buf, "faulty"))
323                                 dev->disk.state |= (1<<MD_DISK_FAULTY);
324                         if (dev->disk.state == 0)
325                                 sra->array.spare_disks++;
326                 }
327                 if (options & GET_ERROR) {
328                         strcpy(buf, "errors");
329                         if (load_sys(fname, buf))
330                                 goto abort;
331                         dev->errors = strtoul(buf, NULL, 0);
332                 }
333         }
334         closedir(dir);
335         return sra;
336
337  abort:
338         if (dir)
339                 closedir(dir);
340         sysfs_free(sra);
341         return NULL;
342 }
343
344 int sysfs_attr_match(const char *attr, const char *str)
345 {
346         /* See if attr, read from a sysfs file, matches
347          * str.  They must either be the same, or attr can
348          * have a trailing newline or comma
349          */
350         while (*attr && *str && *attr == *str) {
351                 attr++;
352                 str++;
353         }
354
355         if (*str || (*attr && *attr != ',' && *attr != '\n'))
356                 return 0;
357         return 1;
358 }
359
360 int sysfs_match_word(const char *word, char **list)
361 {
362         int n;
363         for (n=0; list[n]; n++)
364                 if (sysfs_attr_match(word, list[n]))
365                         break;
366         return n;
367 }
368
369 unsigned long long get_component_size(int fd)
370 {
371         /* Find out the component size of the array.
372          * We cannot trust GET_ARRAY_INFO ioctl as it's
373          * size field is only 32bits.
374          * So look in /sys/block/mdXXX/md/component_size
375          *
376          * This returns in units of sectors.
377          */
378         struct stat stb;
379         char fname[50];
380         int n;
381         if (fstat(fd, &stb)) return 0;
382         if (major(stb.st_rdev) != get_mdp_major())
383                 sprintf(fname, "/sys/block/md%d/md/component_size",
384                         (int)minor(stb.st_rdev));
385         else
386                 sprintf(fname, "/sys/block/md_d%d/md/component_size",
387                         (int)minor(stb.st_rdev)>>MdpMinorShift);
388         fd = open(fname, O_RDONLY);
389         if (fd < 0)
390                 return 0;
391         n = read(fd, fname, sizeof(fname));
392         close(fd);
393         if (n == sizeof(fname))
394                 return 0;
395         fname[n] = 0;
396         return strtoull(fname, NULL, 10) * 2;
397 }
398
399 int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev,
400                   char *name, char *val)
401 {
402         char fname[50];
403         int n;
404         int fd;
405
406         sprintf(fname, "/sys/block/%s/md/%s/%s",
407                 sra->sys_name, dev?dev->sys_name:"", name);
408         fd = open(fname, O_WRONLY);
409         if (fd < 0)
410                 return -1;
411         n = write(fd, val, strlen(val));
412         close(fd);
413         if (n != strlen(val)) {
414                 dprintf(Name ": failed to write '%s' to '%s' (%s)\n",
415                         val, fname, strerror(errno));
416                 return -1;
417         }
418         return 0;
419 }
420
421 int sysfs_set_num(struct mdinfo *sra, struct mdinfo *dev,
422                   char *name, unsigned long long val)
423 {
424         char valstr[50];
425         sprintf(valstr, "%llu", val);
426         return sysfs_set_str(sra, dev, name, valstr);
427 }
428
429 int sysfs_uevent(struct mdinfo *sra, char *event)
430 {
431         char fname[50];
432         int n;
433         int fd;
434
435         sprintf(fname, "/sys/block/%s/uevent",
436                 sra->sys_name);
437         fd = open(fname, O_WRONLY);
438         if (fd < 0)
439                 return -1;
440         n = write(fd, event, strlen(event));
441         close(fd);
442         return 0;
443 }       
444
445 int sysfs_get_fd(struct mdinfo *sra, struct mdinfo *dev,
446                        char *name)
447 {
448         char fname[50];
449         int fd;
450
451         sprintf(fname, "/sys/block/%s/md/%s/%s",
452                 sra->sys_name, dev?dev->sys_name:"", name);
453         fd = open(fname, O_RDWR);
454         if (fd < 0)
455                 fd = open(fname, O_RDONLY);
456         return fd;
457 }
458
459 int sysfs_fd_get_ll(int fd, unsigned long long *val)
460 {
461         char buf[50];
462         int n;
463         char *ep;
464
465         lseek(fd, 0, 0);
466         n = read(fd, buf, sizeof(buf));
467         if (n <= 0)
468                 return -1;
469         buf[n] = 0;
470         *val = strtoull(buf, &ep, 0);
471         if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
472                 return -1;
473         return 0;
474 }
475
476 int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev,
477                        char *name, unsigned long long *val)
478 {
479         int n;
480         int fd;
481
482         fd = sysfs_get_fd(sra, dev, name);
483         if (fd < 0)
484                 return -1;
485         n = sysfs_fd_get_ll(fd, val);
486         close(fd);
487         return n;
488 }
489
490 int sysfs_fd_get_str(int fd, char *val, int size)
491 {
492         int n;
493
494         lseek(fd, 0, 0);
495         n = read(fd, val, size);
496         if (n <= 0)
497                 return -1;
498         val[n] = 0;
499         return n;
500 }
501
502 int sysfs_get_str(struct mdinfo *sra, struct mdinfo *dev,
503                        char *name, char *val, int size)
504 {
505         int n;
506         int fd;
507
508         fd = sysfs_get_fd(sra, dev, name);
509         if (fd < 0)
510                 return -1;
511         n = sysfs_fd_get_str(fd, val, size);
512         close(fd);
513         return n;
514 }
515
516 int sysfs_set_safemode(struct mdinfo *sra, unsigned long ms)
517 {
518         unsigned long sec;
519         unsigned long msec;
520         char delay[30];
521
522         sec = ms / 1000;
523         msec = ms % 1000;
524
525         sprintf(delay, "%ld.%03ld\n", sec, msec);
526         /*             this '\n' ^ needed for kernels older than 2.6.28 */
527         return sysfs_set_str(sra, NULL, "safe_mode_delay", delay);
528 }
529
530 int sysfs_set_array(struct mdinfo *info, int vers)
531 {
532         int rv = 0;
533         char ver[100];
534
535         ver[0] = 0;
536         if (info->array.major_version == -1 &&
537             info->array.minor_version == -2) {
538                 strcat(strcpy(ver, "external:"), info->text_version);
539
540                 if ((vers % 100) < 2 ||
541                     sysfs_set_str(info, NULL, "metadata_version",
542                                   ver) < 0) {
543                         fprintf(stderr, Name ": This kernel does not "
544                                 "support external metadata.\n");
545                         return 1;
546                 }
547         }
548         if (info->array.level < 0)
549                 return 0; /* FIXME */
550         rv |= sysfs_set_str(info, NULL, "level",
551                             map_num(pers, info->array.level));
552         rv |= sysfs_set_num(info, NULL, "raid_disks", info->array.raid_disks);
553         rv |= sysfs_set_num(info, NULL, "chunk_size", info->array.chunk_size);
554         rv |= sysfs_set_num(info, NULL, "layout", info->array.layout);
555         rv |= sysfs_set_num(info, NULL, "component_size", info->component_size/2);
556         if (info->custom_array_size) {
557                 int rc;
558
559                 rc = sysfs_set_num(info, NULL, "array_size",
560                                    info->custom_array_size/2);
561                 if (rc && errno == ENOENT) {
562                         fprintf(stderr, Name ": This kernel does not "
563                                 "have the md/array_size attribute, "
564                                 "the array may be larger than expected\n");
565                         rc = 0;
566                 }
567                 rv |= rc;
568         }
569
570         if (info->array.level > 0)
571                 rv |= sysfs_set_num(info, NULL, "resync_start", info->resync_start);
572         return rv;
573 }
574
575 int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
576 {
577         char dv[100];
578         char nm[100];
579         char *dname;
580         int rv;
581
582         sprintf(dv, "%d:%d", sd->disk.major, sd->disk.minor);
583         rv = sysfs_set_str(sra, NULL, "new_dev", dv);
584         if (rv)
585                 return rv;
586
587         memset(nm, 0, sizeof(nm));
588         sprintf(dv, "/sys/dev/block/%d:%d", sd->disk.major, sd->disk.minor);
589         rv = readlink(dv, nm, sizeof(nm));
590         if (rv <= 0)
591                 return -1;
592         nm[rv] = '\0';
593         dname = strrchr(nm, '/');
594         if (dname) dname++;
595         strcpy(sd->sys_name, "dev-");
596         strcpy(sd->sys_name+4, dname);
597
598         /* test write to see if 'recovery_start' is available */
599         if (resume && sd->recovery_start < MaxSector &&
600             sysfs_set_num(sra, sd, "recovery_start", 0)) {
601                 sysfs_set_str(sra, sd, "state", "remove");
602                 return -1;
603         }
604
605         rv = sysfs_set_num(sra, sd, "offset", sd->data_offset);
606         rv |= sysfs_set_num(sra, sd, "size", (sd->component_size+1) / 2);
607         if (sra->array.level != LEVEL_CONTAINER) {
608                 if (sd->recovery_start == MaxSector)
609                         /* This can correctly fail if array isn't started,
610                          * yet, so just ignore status for now.
611                          */
612                         sysfs_set_str(sra, sd, "state", "insync");
613                 rv |= sysfs_set_num(sra, sd, "slot", sd->disk.raid_disk);
614                 if (resume)
615                         sysfs_set_num(sra, sd, "recovery_start", sd->recovery_start);
616         }
617         return rv;
618 }
619
620 #if 0
621 int sysfs_disk_to_sg(int fd)
622 {
623         /* from an open block device, try find and open its corresponding
624          * scsi_generic interface
625          */
626         struct stat st;
627         char path[256];
628         char sg_path[256];
629         char sg_major_minor[8];
630         char *c;
631         DIR *dir;
632         struct dirent *de;
633         int major, minor, rv;
634
635         if (fstat(fd, &st))
636                 return -1;
637
638         snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device",
639                  major(st.st_rdev), minor(st.st_rdev));
640
641         dir = opendir(path);
642         if (!dir)
643                 return -1;
644
645         de = readdir(dir);
646         while (de) {
647                 if (strncmp("scsi_generic:", de->d_name,
648                             strlen("scsi_generic:")) == 0)
649                         break;
650                 de = readdir(dir);
651         }
652         closedir(dir);
653
654         if (!de)
655                 return -1;
656
657         snprintf(sg_path, sizeof(sg_path), "%s/%s/dev", path, de->d_name);
658         fd = open(sg_path, O_RDONLY);
659         if (fd < 0)
660                 return fd;
661
662         rv = read(fd, sg_major_minor, sizeof(sg_major_minor));
663         close(fd);
664         if (rv < 0)
665                 return -1;
666         else
667                 sg_major_minor[rv - 1] = '\0';
668
669         c = strchr(sg_major_minor, ':');
670         *c = '\0';
671         c++;
672         major = strtol(sg_major_minor, NULL, 10);
673         minor = strtol(c, NULL, 10);
674         snprintf(path, sizeof(path), "/dev/.tmp.md.%d:%d:%d",
675                  (int) getpid(), major, minor);
676         if (mknod(path, S_IFCHR|0600, makedev(major, minor))==0) {
677                         fd = open(path, O_RDONLY);
678                         unlink(path);
679                         return fd;
680         }
681
682         return -1;
683 }
684 #endif
685
686 int sysfs_disk_to_scsi_id(int fd, __u32 *id)
687 {
688         /* from an open block device, try to retrieve it scsi_id */
689         struct stat st;
690         char path[256];
691         char *c1, *c2;
692         DIR *dir;
693         struct dirent *de;
694
695         if (fstat(fd, &st))
696                 return 1;
697
698         snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device",
699                  major(st.st_rdev), minor(st.st_rdev));
700
701         dir = opendir(path);
702         if (!dir)
703                 return 1;
704
705         de = readdir(dir);
706         while (de) {
707                 if (strncmp("scsi_disk:", de->d_name,
708                             strlen("scsi_disk:")) == 0)
709                         break;
710                 de = readdir(dir);
711         }
712         closedir(dir);
713
714         if (!de)
715                 return 1;
716
717         c1 = strchr(de->d_name, ':');
718         c1++;
719         c2 = strchr(c1, ':');
720         *c2 = '\0';
721         *id = strtol(c1, NULL, 10) << 24; /* host */
722         c1 = c2 + 1;
723         c2 = strchr(c1, ':');
724         *c2 = '\0';
725         *id |= strtol(c1, NULL, 10) << 16; /* channel */
726         c1 = c2 + 1;
727         c2 = strchr(c1, ':');
728         *c2 = '\0';
729         *id |= strtol(c1, NULL, 10) << 8; /* lun */
730         c1 = c2 + 1;
731         *id |= strtol(c1, NULL, 10); /* id */
732
733         return 0;
734 }
735
736
737 int sysfs_unique_holder(int devnum, long rdev)
738 {
739         /* Check that devnum is a holder of rdev,
740          * and is the only holder.
741          * we should be locked against races by
742          * an O_EXCL on devnum
743          */
744         DIR *dir;
745         struct dirent *de;
746         char dirname[100];
747         char l;
748         int found = 0;
749         sprintf(dirname, "/sys/dev/block/%d:%d/holders",
750                 major(rdev), minor(rdev));
751         dir = opendir(dirname);
752         errno = ENOENT;
753         if (!dir)
754                 return 0;
755         l = strlen(dirname);
756         while ((de = readdir(dir)) != NULL) {
757                 char buf[10];
758                 int n;
759                 int mj, mn;
760                 char c;
761                 int fd;
762
763                 if (de->d_ino == 0)
764                         continue;
765                 if (de->d_name[0] == '.')
766                         continue;
767                 strcpy(dirname+l, "/");
768                 strcat(dirname+l, de->d_name);
769                 strcat(dirname+l, "/dev");
770                 fd = open(dirname, O_RDONLY);
771                 if (fd < 0) {
772                         errno = ENOENT;
773                         break;
774                 }
775                 n = read(fd, buf, sizeof(buf)-1);
776                 close(fd);
777                 buf[n] = 0;
778                 if (sscanf(buf, "%d:%d%c", &mj, &mn, &c) != 3 ||
779                     c != '\n') {
780                         errno = ENOENT;
781                         break;
782                 }
783                 if (mj != MD_MAJOR)
784                         mn = -1-(mn>>6);
785
786                 if (devnum != mn) {
787                         errno = EEXIST;
788                         break;
789                 }
790                 found = 1;
791         }
792         closedir(dir);
793         if (de)
794                 return 0;
795         else
796                 return found;
797 }
798
799 #ifndef MDASSEMBLE
800
801 static char *clean_states[] = {
802         "clear", "inactive", "readonly", "read-auto", "clean", NULL };
803
804 int WaitClean(char *dev, int sock, int verbose)
805 {
806         int fd;
807         struct mdinfo *mdi;
808         int rv = 1;
809         int devnum;
810
811         fd = open(dev, O_RDONLY); 
812         if (fd < 0) {
813                 if (verbose)
814                         fprintf(stderr, Name ": Couldn't open %s: %s\n", dev, strerror(errno));
815                 return 1;
816         }
817
818         devnum = fd2devnum(fd);
819         mdi = sysfs_read(fd, devnum, GET_VERSION|GET_LEVEL|GET_SAFEMODE);
820         if (!mdi) {
821                 if (verbose)
822                         fprintf(stderr, Name ": Failed to read sysfs attributes for "
823                                 "%s\n", dev);
824                 close(fd);
825                 return 0;
826         }
827
828         switch(mdi->array.level) {
829         case LEVEL_LINEAR:
830         case LEVEL_MULTIPATH:
831         case 0:
832                 /* safemode delay is irrelevant for these levels */
833                 rv = 0;
834                 
835         }
836
837         /* for internal metadata the kernel handles the final clean
838          * transition, containers can never be dirty
839          */
840         if (!is_subarray(mdi->text_version))
841                 rv = 0;
842
843         /* safemode disabled ? */
844         if (mdi->safe_mode_delay == 0)
845                 rv = 0;
846
847         if (rv) {
848                 int state_fd = sysfs_open(fd2devnum(fd), NULL, "array_state");
849                 char buf[20];
850                 fd_set fds;
851                 struct timeval tm;
852
853                 /* minimize the safe_mode_delay and prepare to wait up to 5s
854                  * for writes to quiesce
855                  */
856                 sysfs_set_safemode(mdi, 1);
857                 tm.tv_sec = 5;
858                 tm.tv_usec = 0;
859
860                 /* give mdmon a chance to checkpoint resync */
861                 sysfs_set_str(mdi, NULL, "sync_action", "idle");
862
863                 FD_ZERO(&fds);
864
865                 /* wait for array_state to be clean */
866                 while (1) {
867                         rv = read(state_fd, buf, sizeof(buf));
868                         if (rv < 0)
869                                 break;
870                         if (sysfs_match_word(buf, clean_states) <= 4)
871                                 break;
872                         FD_SET(state_fd, &fds);
873                         rv = select(state_fd + 1, NULL, NULL, &fds, &tm);
874                         if (rv < 0 && errno != EINTR)
875                                 break;
876                         lseek(state_fd, 0, SEEK_SET);
877                 }
878                 if (rv < 0)
879                         rv = 1;
880                 else if (fping_monitor(sock) == 0 ||
881                          ping_monitor(mdi->text_version) == 0) {
882                         /* we need to ping to close the window between array
883                          * state transitioning to clean and the metadata being
884                          * marked clean
885                          */
886                         rv = 0;
887                 } else
888                         rv = 1;
889                 if (rv && verbose)
890                         fprintf(stderr, Name ": Error waiting for %s to be clean\n",
891                                 dev);
892
893                 /* restore the original safe_mode_delay */
894                 sysfs_set_safemode(mdi, mdi->safe_mode_delay);
895                 close(state_fd);
896         }
897
898         sysfs_free(mdi);
899         close(fd);
900
901         return rv;
902 }
903 #endif /* MDASSEMBLE */