]> git.ipfire.org Git - thirdparty/mdadm.git/blob - Monitor.c
Break Monitor into smaller functions.
[thirdparty/mdadm.git] / Monitor.c
1 /*
2 * mdadm - manage Linux "md" devices aka RAID arrays.
3 *
4 * Copyright (C) 2001-2009 Neil Brown <neilb@suse.de>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * Author: Neil Brown
22 * Email: <neilb@suse.de>
23 */
24
25 #include "mdadm.h"
26 #include "md_p.h"
27 #include "md_u.h"
28 #include <sys/wait.h>
29 #include <signal.h>
30 #include <limits.h>
31 #include <syslog.h>
32
33 /* The largest number of disks current arrays can manage is 384
34 * This really should be dynamically, but that will have to wait
35 * At least it isn't MD_SB_DISKS.
36 */
37 #define MaxDisks 384
38 struct state {
39 char *devname;
40 int devnum; /* to sync with mdstat info */
41 long utime;
42 int err;
43 char *spare_group;
44 int active, working, failed, spare, raid;
45 int expected_spares;
46 int devstate[MaxDisks];
47 unsigned devid[MaxDisks];
48 int percent;
49 int parent_dev; /* For subarray, devnum of parent.
50 * For others, NoMdDev
51 */
52 struct supertype *metadata;
53 struct state *next;
54 };
55
56 static int make_daemon(char *pidfile);
57 static int check_one_sharer(int scan);
58 static void alert(char *event, char *dev, char *disc, char *mailaddr, char *mailfrom,
59 char *cmd, int dosyslog);
60 static void check_array(struct state *st, struct mdstat_ent *mdstat,
61 int test, char *mailaddr,
62 char *mailfrom, char *alert_cmd, int dosyslog,
63 int increments);
64 static int add_new_arrays(struct mdstat_ent *mdstat, struct state *statelist,
65 int test, char *mailaddr, char *mailfrom,
66 char *alert_cmd, int dosyslog);
67 static void try_spare_migration(struct state *statelist,
68 char *mailaddr, char *mailfrom,
69 char *alert_cmd, int dosyslog);
70
71 int Monitor(struct mddev_dev *devlist,
72 char *mailaddr, char *alert_cmd,
73 int period, int daemonise, int scan, int oneshot,
74 int dosyslog, int test, char *pidfile, int increments,
75 int share)
76 {
77 /*
78 * Every few seconds, scan every md device looking for changes
79 * When a change is found, log it, possibly run the alert command,
80 * and possibly send Email
81 *
82 * For each array, we record:
83 * Update time
84 * active/working/failed/spare drives
85 * State of each device.
86 * %rebuilt if rebuilding
87 *
88 * If the update time changes, check out all the data again
89 * It is possible that we cannot get the state of each device
90 * due to bugs in the md kernel module.
91 * We also read /proc/mdstat to get rebuild percent,
92 * and to get state on all active devices incase of kernel bug.
93 *
94 * Events are:
95 * Fail
96 * An active device had Faulty set or Active/Sync removed
97 * FailSpare
98 * A spare device had Faulty set
99 * SpareActive
100 * An active device had a reverse transition
101 * RebuildStarted
102 * percent went from -1 to +ve
103 * RebuildNN
104 * percent went from below to not-below NN%
105 * DeviceDisappeared
106 * Couldn't access a device which was previously visible
107 *
108 * if we detect an array with active<raid and spare==0
109 * we look at other arrays that have same spare-group
110 * If we find one with active==raid and spare>0,
111 * and if we can get_disk_info and find a name
112 * Then we hot-remove and hot-add to the other array
113 *
114 * If devlist is NULL, then we can monitor everything because --scan
115 * was given. We get an initial list from config file and add anything
116 * that appears in /proc/mdstat
117 */
118
119 struct state *statelist = NULL;
120 int finished = 0;
121 struct mdstat_ent *mdstat = NULL;
122 char *mailfrom = NULL;
123
124 if (!mailaddr) {
125 mailaddr = conf_get_mailaddr();
126 if (mailaddr && ! scan)
127 fprintf(stderr, Name ": Monitor using email address \"%s\" from config file\n",
128 mailaddr);
129 }
130 mailfrom = conf_get_mailfrom();
131
132 if (!alert_cmd) {
133 alert_cmd = conf_get_program();
134 if (alert_cmd && ! scan)
135 fprintf(stderr, Name ": Monitor using program \"%s\" from config file\n",
136 alert_cmd);
137 }
138 if (scan && !mailaddr && !alert_cmd) {
139 fprintf(stderr, Name ": No mail address or alert command - not monitoring.\n");
140 return 1;
141 }
142
143 if (daemonise)
144 if (make_daemon(pidfile))
145 return 1;
146
147 if (share)
148 if (check_one_sharer(scan))
149 return 1;
150
151 if (devlist == NULL) {
152 struct mddev_ident *mdlist = conf_get_ident(NULL);
153 for (; mdlist; mdlist=mdlist->next) {
154 struct state *st;
155 if (mdlist->devname == NULL)
156 continue;
157 if (strcasecmp(mdlist->devname, "<ignore>") == 0)
158 continue;
159 st = malloc(sizeof *st);
160 if (st == NULL)
161 continue;
162 if (mdlist->devname[0] == '/')
163 st->devname = strdup(mdlist->devname);
164 else {
165 st->devname = malloc(8+strlen(mdlist->devname)+1);
166 strcpy(strcpy(st->devname, "/dev/md/"),
167 mdlist->devname);
168 }
169 st->utime = 0;
170 st->next = statelist;
171 st->err = 0;
172 st->devnum = INT_MAX;
173 st->percent = -2;
174 st->expected_spares = mdlist->spare_disks;
175 if (mdlist->spare_group)
176 st->spare_group = strdup(mdlist->spare_group);
177 else
178 st->spare_group = NULL;
179 statelist = st;
180 }
181 } else {
182 struct mddev_dev *dv;
183 for (dv=devlist ; dv; dv=dv->next) {
184 struct mddev_ident *mdlist = conf_get_ident(dv->devname);
185 struct state *st = malloc(sizeof *st);
186 if (st == NULL)
187 continue;
188 st->devname = strdup(dv->devname);
189 st->utime = 0;
190 st->next = statelist;
191 st->err = 0;
192 st->devnum = INT_MAX;
193 st->percent = -2;
194 st->expected_spares = -1;
195 st->spare_group = NULL;
196 if (mdlist) {
197 st->expected_spares = mdlist->spare_disks;
198 if (mdlist->spare_group)
199 st->spare_group = strdup(mdlist->spare_group);
200 }
201 statelist = st;
202 }
203 }
204
205
206 while (! finished) {
207 int new_found = 0;
208 struct state *st;
209
210 if (mdstat)
211 free_mdstat(mdstat);
212 mdstat = mdstat_read(oneshot?0:1, 0);
213
214 for (st=statelist; st; st=st->next)
215 check_array(st, mdstat, test, mailaddr, mailfrom,
216 alert_cmd, dosyslog, increments);
217
218 /* now check if there are any new devices found in mdstat */
219 if (scan)
220 new_found = add_new_arrays(mdstat, statelist, test,
221 mailaddr, mailfrom, alert_cmd,
222 dosyslog);
223
224 /* If an array has active < raid && spare == 0 && spare_group != NULL
225 * Look for another array with spare > 0 and active == raid and same spare_group
226 * if found, choose a device and hotremove/hotadd
227 */
228 if (share)
229 try_spare_migration(statelist, mailaddr, mailfrom,
230 alert_cmd, dosyslog);
231 if (!new_found) {
232 if (oneshot)
233 break;
234 else
235 mdstat_wait(period);
236 }
237 test = 0;
238 }
239 if (pidfile)
240 unlink(pidfile);
241 return 0;
242 }
243
244 static int make_daemon(char *pidfile)
245 {
246 int pid = fork();
247 if (pid > 0) {
248 if (!pidfile)
249 printf("%d\n", pid);
250 else {
251 FILE *pid_file;
252 pid_file=fopen(pidfile, "w");
253 if (!pid_file)
254 perror("cannot create pid file");
255 else {
256 fprintf(pid_file,"%d\n", pid);
257 fclose(pid_file);
258 }
259 }
260 return 0;
261 }
262 if (pid < 0) {
263 perror("daemonise");
264 return 1;
265 }
266 close(0);
267 open("/dev/null", O_RDWR);
268 dup2(0,1);
269 dup2(0,2);
270 setsid();
271 return 0;
272 }
273
274 static int check_one_sharer(int scan)
275 {
276 int pid, rv;
277 FILE *fp;
278 char dir[20];
279 struct stat buf;
280 fp = fopen("/var/run/mdadm/autorebuild.pid", "r");
281 if (fp) {
282 fscanf(fp, "%d", &pid);
283 sprintf(dir, "/proc/%d", pid);
284 rv = stat(dir, &buf);
285 if (rv != -1) {
286 if (scan) {
287 fprintf(stderr, Name ": Only one "
288 "autorebuild process allowed"
289 " in scan mode, aborting\n");
290 fclose(fp);
291 return 1;
292 } else {
293 fprintf(stderr, Name ": Warning: One"
294 " autorebuild process already"
295 " running.");
296 }
297 }
298 fclose(fp);
299 }
300 if (scan) {
301 fp = fopen("/var/run/mdadm/autorebuild.pid", "w");
302 if (!fp)
303 fprintf(stderr, Name ": Cannot create"
304 " autorebuild.pid "
305 "file\n");
306 else {
307 pid = getpid();
308 fprintf(fp, "%d\n", pid);
309 fclose(fp);
310 }
311 }
312 return 0;
313 }
314
315 static void alert(char *event, char *dev, char *disc, char *mailaddr, char *mailfrom, char *cmd,
316 int dosyslog)
317 {
318 int priority;
319
320 if (!cmd && !mailaddr) {
321 time_t now = time(0);
322
323 printf("%1.15s: %s on %s %s\n", ctime(&now)+4, event, dev, disc?disc:"unknown device");
324 }
325 if (cmd) {
326 int pid = fork();
327 switch(pid) {
328 default:
329 waitpid(pid, NULL, 0);
330 break;
331 case -1:
332 break;
333 case 0:
334 execl(cmd, cmd, event, dev, disc, NULL);
335 exit(2);
336 }
337 }
338 if (mailaddr &&
339 (strncmp(event, "Fail", 4)==0 ||
340 strncmp(event, "Test", 4)==0 ||
341 strncmp(event, "Spares", 6)==0 ||
342 strncmp(event, "Degrade", 7)==0)) {
343 FILE *mp = popen(Sendmail, "w");
344 if (mp) {
345 FILE *mdstat;
346 char hname[256];
347 gethostname(hname, sizeof(hname));
348 signal(SIGPIPE, SIG_IGN);
349 if (mailfrom)
350 fprintf(mp, "From: %s\n", mailfrom);
351 else
352 fprintf(mp, "From: " Name " monitoring <root>\n");
353 fprintf(mp, "To: %s\n", mailaddr);
354 fprintf(mp, "Subject: %s event on %s:%s\n\n", event, dev, hname);
355
356 fprintf(mp, "This is an automatically generated mail message from " Name "\n");
357 fprintf(mp, "running on %s\n\n", hname);
358
359 fprintf(mp, "A %s event had been detected on md device %s.\n\n", event, dev);
360
361 if (disc && disc[0] != ' ')
362 fprintf(mp, "It could be related to component device %s.\n\n", disc);
363 if (disc && disc[0] == ' ')
364 fprintf(mp, "Extra information:%s.\n\n", disc);
365
366 fprintf(mp, "Faithfully yours, etc.\n");
367
368 mdstat = fopen("/proc/mdstat", "r");
369 if (mdstat) {
370 char buf[8192];
371 int n;
372 fprintf(mp, "\nP.S. The /proc/mdstat file currently contains the following:\n\n");
373 while ( (n=fread(buf, 1, sizeof(buf), mdstat)) > 0)
374 n=fwrite(buf, 1, n, mp); /* yes, i don't care about the result */
375 fclose(mdstat);
376 }
377 pclose(mp);
378 }
379
380 }
381
382 /* log the event to syslog maybe */
383 if (dosyslog) {
384 /* Log at a different severity depending on the event.
385 *
386 * These are the critical events: */
387 if (strncmp(event, "Fail", 4)==0 ||
388 strncmp(event, "Degrade", 7)==0 ||
389 strncmp(event, "DeviceDisappeared", 17)==0)
390 priority = LOG_CRIT;
391 /* Good to know about, but are not failures: */
392 else if (strncmp(event, "Rebuild", 7)==0 ||
393 strncmp(event, "MoveSpare", 9)==0 ||
394 strncmp(event, "Spares", 6) != 0)
395 priority = LOG_WARNING;
396 /* Everything else: */
397 else
398 priority = LOG_INFO;
399
400 if (disc)
401 syslog(priority, "%s event detected on md device %s, component device %s", event, dev, disc);
402 else
403 syslog(priority, "%s event detected on md device %s", event, dev);
404 }
405 }
406
407 static void check_array(struct state *st, struct mdstat_ent *mdstat,
408 int test, char *mailaddr,
409 char *mailfrom, char *alert_cmd, int dosyslog,
410 int increments)
411 {
412 struct { int state, major, minor; } info[MaxDisks];
413 mdu_array_info_t array;
414 struct mdstat_ent *mse = NULL, *mse2;
415 char *dev = st->devname;
416 int fd;
417 int i;
418
419 if (test)
420 alert("TestMessage", dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog);
421 fd = open(dev, O_RDONLY);
422 if (fd < 0) {
423 if (!st->err)
424 alert("DeviceDisappeared", dev, NULL,
425 mailaddr, mailfrom, alert_cmd, dosyslog);
426 /* fprintf(stderr, Name ": cannot open %s: %s\n",
427 dev, strerror(errno));
428 */ st->err=1;
429 return;
430 }
431 fcntl(fd, F_SETFD, FD_CLOEXEC);
432 if (ioctl(fd, GET_ARRAY_INFO, &array)<0) {
433 if (!st->err)
434 alert("DeviceDisappeared", dev, NULL,
435 mailaddr, mailfrom, alert_cmd, dosyslog);
436 /* fprintf(stderr, Name ": cannot get array info for %s: %s\n",
437 dev, strerror(errno));
438 */ st->err=1;
439 close(fd);
440 return;
441 }
442 /* It's much easier to list what array levels can't
443 * have a device disappear than all of them that can
444 */
445 if (array.level == 0 || array.level == -1) {
446 if (!st->err)
447 alert("DeviceDisappeared", dev, "Wrong-Level",
448 mailaddr, mailfrom, alert_cmd, dosyslog);
449 st->err = 1;
450 close(fd);
451 return;
452 }
453 if (st->devnum == INT_MAX) {
454 struct stat stb;
455 if (fstat(fd, &stb) == 0 &&
456 (S_IFMT&stb.st_mode)==S_IFBLK) {
457 if (major(stb.st_rdev) == MD_MAJOR)
458 st->devnum = minor(stb.st_rdev);
459 else
460 st->devnum = -1- (minor(stb.st_rdev)>>6);
461 }
462 }
463
464 for (mse2 = mdstat ; mse2 ; mse2=mse2->next)
465 if (mse2->devnum == st->devnum) {
466 mse2->devnum = INT_MAX; /* flag it as "used" */
467 mse = mse2;
468 }
469
470 if (!mse) {
471 /* duplicated array in statelist
472 * or re-created after reading mdstat*/
473 st->err = 1;
474 close(fd);
475 return;
476 }
477 /* this array is in /proc/mdstat */
478 if (array.utime == 0)
479 /* external arrays don't update utime, so
480 * just make sure it is always different. */
481 array.utime = st->utime + 1;;
482
483 if (st->utime == array.utime &&
484 st->failed == array.failed_disks &&
485 st->working == array.working_disks &&
486 st->spare == array.spare_disks &&
487 (mse == NULL || (
488 mse->percent == st->percent
489 ))) {
490 close(fd);
491 st->err = 0;
492 return;
493 }
494 if (st->utime == 0 && /* new array */
495 mse->pattern && strchr(mse->pattern, '_') /* degraded */
496 )
497 alert("DegradedArray", dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog);
498
499 if (st->utime == 0 && /* new array */
500 st->expected_spares > 0 &&
501 array.spare_disks < st->expected_spares)
502 alert("SparesMissing", dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog);
503 if (st->percent == -1 &&
504 mse->percent >= 0)
505 alert("RebuildStarted", dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog);
506 if (st->percent >= 0 &&
507 mse->percent >= 0 &&
508 (mse->percent / increments) > (st->percent / increments)) {
509 char percentalert[15]; // "RebuildNN" (10 chars) or "RebuildStarted" (15 chars)
510
511 if((mse->percent / increments) == 0)
512 snprintf(percentalert, sizeof(percentalert), "RebuildStarted");
513 else
514 snprintf(percentalert, sizeof(percentalert), "Rebuild%02d", mse->percent);
515
516 alert(percentalert,
517 dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog);
518 }
519
520 if (mse->percent == -1 &&
521 st->percent >= 0) {
522 /* Rebuild/sync/whatever just finished.
523 * If there is a number in /mismatch_cnt,
524 * we should report that.
525 */
526 struct mdinfo *sra =
527 sysfs_read(-1, st->devnum, GET_MISMATCH);
528 if (sra && sra->mismatch_cnt > 0) {
529 char cnt[40];
530 sprintf(cnt, " mismatches found: %d", sra->mismatch_cnt);
531 alert("RebuildFinished", dev, cnt, mailaddr, mailfrom, alert_cmd, dosyslog);
532 } else
533 alert("RebuildFinished", dev, NULL, mailaddr, mailfrom, alert_cmd, dosyslog);
534 if (sra)
535 free(sra);
536 }
537 st->percent = mse->percent;
538
539 for (i=0; i<MaxDisks && i <= array.raid_disks + array.nr_disks;
540 i++) {
541 mdu_disk_info_t disc;
542 disc.number = i;
543 if (ioctl(fd, GET_DISK_INFO, &disc) >= 0) {
544 info[i].state = disc.state;
545 info[i].major = disc.major;
546 info[i].minor = disc.minor;
547 } else
548 info[i].major = info[i].minor = 0;
549 }
550
551 if (strncmp(mse->metadata_version, "external:", 9) == 0 &&
552 is_subarray(mse->metadata_version+9))
553 st->parent_dev =
554 devname2devnum(mse->metadata_version+10);
555 else
556 st->parent_dev = NoMdDev;
557 if (st->metadata == NULL &&
558 st->parent_dev == NoMdDev)
559 st->metadata = super_by_fd(fd, NULL);
560
561 close(fd);
562
563 for (i=0; i<MaxDisks; i++) {
564 mdu_disk_info_t disc = {0,0,0,0,0};
565 int newstate=0;
566 int change;
567 char *dv = NULL;
568 disc.number = i;
569 if (i > array.raid_disks + array.nr_disks) {
570 newstate = 0;
571 disc.major = disc.minor = 0;
572 } else if (info[i].major || info[i].minor) {
573 newstate = info[i].state;
574 dv = map_dev(info[i].major, info[i].minor, 1);
575 disc.state = newstate;
576 disc.major = info[i].major;
577 disc.minor = info[i].minor;
578 } else if (mse && mse->pattern && i < (int)strlen(mse->pattern)) {
579 switch(mse->pattern[i]) {
580 case 'U': newstate = 6 /* ACTIVE/SYNC */; break;
581 case '_': newstate = 0; break;
582 }
583 disc.major = disc.minor = 0;
584 }
585 if (dv == NULL && st->devid[i])
586 dv = map_dev(major(st->devid[i]),
587 minor(st->devid[i]), 1);
588 change = newstate ^ st->devstate[i];
589 if (st->utime && change && !st->err) {
590 if (i < array.raid_disks &&
591 (((newstate&change)&(1<<MD_DISK_FAULTY)) ||
592 ((st->devstate[i]&change)&(1<<MD_DISK_ACTIVE)) ||
593 ((st->devstate[i]&change)&(1<<MD_DISK_SYNC)))
594 )
595 alert("Fail", dev, dv, mailaddr, mailfrom, alert_cmd, dosyslog);
596 else if (i >= array.raid_disks &&
597 (disc.major || disc.minor) &&
598 st->devid[i] == makedev(disc.major, disc.minor) &&
599 ((newstate&change)&(1<<MD_DISK_FAULTY))
600 )
601 alert("FailSpare", dev, dv, mailaddr, mailfrom, alert_cmd, dosyslog);
602 else if (i < array.raid_disks &&
603 ! (newstate & (1<<MD_DISK_REMOVED)) &&
604 (((st->devstate[i]&change)&(1<<MD_DISK_FAULTY)) ||
605 ((newstate&change)&(1<<MD_DISK_ACTIVE)) ||
606 ((newstate&change)&(1<<MD_DISK_SYNC)))
607 )
608 alert("SpareActive", dev, dv, mailaddr, mailfrom, alert_cmd, dosyslog);
609 }
610 st->devstate[i] = newstate;
611 st->devid[i] = makedev(disc.major, disc.minor);
612 }
613 st->active = array.active_disks;
614 st->working = array.working_disks;
615 st->spare = array.spare_disks;
616 st->failed = array.failed_disks;
617 st->utime = array.utime;
618 st->raid = array.raid_disks;
619 st->err = 0;
620 }
621
622 static int add_new_arrays(struct mdstat_ent *mdstat, struct state *statelist,
623 int test, char *mailaddr, char *mailfrom,
624 char *alert_cmd, int dosyslog)
625 {
626 struct mdstat_ent *mse;
627 int new_found = 0;
628
629 for (mse=mdstat; mse; mse=mse->next)
630 if (mse->devnum != INT_MAX &&
631 (!mse->level || /* retrieve containers */
632 (strcmp(mse->level, "raid0") != 0 &&
633 strcmp(mse->level, "linear") != 0))
634 ) {
635 struct state *st = malloc(sizeof *st);
636 mdu_array_info_t array;
637 int fd;
638 if (st == NULL)
639 continue;
640 st->devname = strdup(get_md_name(mse->devnum));
641 if ((fd = open(st->devname, O_RDONLY)) < 0 ||
642 ioctl(fd, GET_ARRAY_INFO, &array)< 0) {
643 /* no such array */
644 if (fd >=0) close(fd);
645 put_md_name(st->devname);
646 free(st->devname);
647 if (st->metadata) {
648 st->metadata->ss->free_super(st->metadata);
649 free(st->metadata);
650 }
651 free(st);
652 continue;
653 }
654 close(fd);
655 st->utime = 0;
656 st->next = statelist;
657 st->err = 1;
658 st->devnum = mse->devnum;
659 st->percent = -2;
660 st->spare_group = NULL;
661 st->expected_spares = -1;
662 if (strncmp(mse->metadata_version, "external:", 9) == 0 &&
663 is_subarray(mse->metadata_version+9))
664 st->parent_dev =
665 devname2devnum(mse->metadata_version+10);
666 else
667 st->parent_dev = NoMdDev;
668 st->metadata = NULL;
669 statelist = st;
670 if (test)
671 alert("TestMessage", st->devname, NULL, mailaddr, mailfrom, alert_cmd, dosyslog);
672 alert("NewArray", st->devname, NULL, mailaddr, mailfrom, alert_cmd, dosyslog);
673 new_found = 1;
674 }
675 return new_found;
676 }
677
678 static void try_spare_migration(struct state *statelist,
679 char *mailaddr, char *mailfrom,
680 char *alert_cmd, int dosyslog)
681 {
682 struct state *st;
683 for (st = statelist; st; st=st->next)
684 if (st->active < st->raid &&
685 st->spare == 0 &&
686 st->spare_group != NULL) {
687 struct state *st2;
688 for (st2=statelist ; st2 ; st2=st2->next)
689 if (st2 != st &&
690 st2->spare > 0 &&
691 st2->active == st2->raid &&
692 st2->spare_group != NULL &&
693 strcmp(st->spare_group, st2->spare_group) == 0) {
694 /* try to remove and add */
695 int fd1 = open(st->devname, O_RDONLY);
696 int fd2 = open(st2->devname, O_RDONLY);
697 int dev = -1;
698 int d;
699 if (fd1 < 0 || fd2 < 0) {
700 if (fd1>=0) close(fd1);
701 if (fd2>=0) close(fd2);
702 continue;
703 }
704 for (d=st2->raid; d < MaxDisks; d++) {
705 if (st2->devid[d] > 0 &&
706 st2->devstate[d] == 0) {
707 dev = st2->devid[d];
708 break;
709 }
710 }
711 if (dev > 0) {
712 struct mddev_dev devlist;
713 char devname[20];
714 devlist.next = NULL;
715 devlist.used = 0;
716 devlist.re_add = 0;
717 devlist.writemostly = 0;
718 devlist.devname = devname;
719 sprintf(devname, "%d:%d", major(dev), minor(dev));
720
721 devlist.disposition = 'r';
722 if (Manage_subdevs(st2->devname, fd2, &devlist, -1, 0) == 0) {
723 devlist.disposition = 'a';
724 if (Manage_subdevs(st->devname, fd1, &devlist, -1, 0) == 0) {
725 alert("MoveSpare", st->devname, st2->devname, mailaddr, mailfrom, alert_cmd, dosyslog);
726 close(fd1);
727 close(fd2);
728 break;
729 }
730 else Manage_subdevs(st2->devname, fd2, &devlist, -1, 0);
731 }
732 }
733 close(fd1);
734 close(fd2);
735 }
736 }
737 }
738 /* Not really Monitor but ... */
739 int Wait(char *dev)
740 {
741 struct stat stb;
742 int devnum;
743 int rv = 1;
744
745 if (stat(dev, &stb) != 0) {
746 fprintf(stderr, Name ": Cannot find %s: %s\n", dev,
747 strerror(errno));
748 return 2;
749 }
750 devnum = stat2devnum(&stb);
751
752 while(1) {
753 struct mdstat_ent *ms = mdstat_read(1, 0);
754 struct mdstat_ent *e;
755
756 for (e=ms ; e; e=e->next)
757 if (e->devnum == devnum)
758 break;
759
760 if (!e || e->percent < 0) {
761 if (e && e->metadata_version &&
762 strncmp(e->metadata_version, "external:", 9) == 0) {
763 if (is_subarray(&e->metadata_version[9]))
764 ping_monitor(&e->metadata_version[9]);
765 else
766 ping_monitor(devnum2devname(devnum));
767 }
768 free_mdstat(ms);
769 return rv;
770 }
771 free_mdstat(ms);
772 rv = 0;
773 mdstat_wait(5);
774 }
775 }