handle Manage_subdevs() for 'external' arrays
[thirdparty/mdadm.git] / Manage.c
1 /*
2  * mdadm - manage Linux "md" devices aka RAID arrays.
3  *
4  * Copyright (C) 2001-2006 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@cse.unsw.edu.au>
23  *    Paper: Neil Brown
24  *           School of Computer Science and Engineering
25  *           The University of New South Wales
26  *           Sydney, 2052
27  *           Australia
28  */
29
30 #include "mdadm.h"
31 #include "md_u.h"
32 #include "md_p.h"
33
34 #define REGISTER_DEV            _IO (MD_MAJOR, 1)
35 #define START_MD                _IO (MD_MAJOR, 2)
36 #define STOP_MD                 _IO (MD_MAJOR, 3)
37
38 int Manage_ro(char *devname, int fd, int readonly)
39 {
40         /* switch to readonly or rw
41          *
42          * requires >= 0.90.0
43          * first check that array is runing
44          * use RESTART_ARRAY_RW or STOP_ARRAY_RO
45          *
46          */
47         mdu_array_info_t array;
48
49         if (md_get_version(fd) < 9000) {
50                 fprintf(stderr, Name ": need md driver version 0.90.0 or later\n");
51                 return 1;
52         }
53         if (ioctl(fd, GET_ARRAY_INFO, &array)) {
54                 fprintf(stderr, Name ": %s does not appear to be active.\n",
55                         devname);
56                 return 1;
57         }
58
59         if (readonly>0) {
60                 if (ioctl(fd, STOP_ARRAY_RO, NULL)) {
61                         fprintf(stderr, Name ": failed to set readonly for %s: %s\n",
62                                 devname, strerror(errno));
63                         return 1;
64                 }
65         } else if (readonly < 0) {
66                 if (ioctl(fd, RESTART_ARRAY_RW, NULL)) {
67                         fprintf(stderr, Name ": failed to set writable for %s: %s\n",
68                                 devname, strerror(errno));
69                         return 1;
70                 }
71         }
72         return 0;
73 }
74
75 #ifndef MDASSEMBLE
76
77 int Manage_runstop(char *devname, int fd, int runstop, int quiet)
78 {
79         /* Run or stop the array. array must already be configured
80          * required >= 0.90.0
81          */
82         mdu_param_t param; /* unused */
83
84         if (runstop == -1 && md_get_version(fd) < 9000) {
85                 if (ioctl(fd, STOP_MD, 0)) {
86                         if (!quiet) fprintf(stderr, Name ": stopping device %s failed: %s\n",
87                                             devname, strerror(errno));
88                         return 1;
89                 }
90         }
91
92         if (md_get_version(fd) < 9000) {
93                 fprintf(stderr, Name ": need md driver version 0.90.0 or later\n");
94                 return 1;
95         }
96         /*
97         if (ioctl(fd, GET_ARRAY_INFO, &array)) {
98                 fprintf(stderr, Name ": %s does not appear to be active.\n",
99                         devname);
100                 return 1;
101         }
102         */
103         if (runstop>0) {
104                 if (ioctl(fd, RUN_ARRAY, &param)) {
105                         fprintf(stderr, Name ": failed to run array %s: %s\n",
106                                 devname, strerror(errno));
107                         return 1;
108                 }
109                 if (quiet <= 0)
110                         fprintf(stderr, Name ": started %s\n", devname);
111         } else if (runstop < 0){
112                 struct map_ent *map = NULL;
113                 struct stat stb;
114                 if (ioctl(fd, STOP_ARRAY, NULL)) {
115                         if (quiet==0)
116                                 fprintf(stderr, Name ": fail to stop array %s: %s\n",
117                                         devname, strerror(errno));
118                         return 1;
119                 }
120                 if (quiet <= 0)
121                         fprintf(stderr, Name ": stopped %s\n", devname);
122                 if (fstat(fd, &stb) == 0) {
123                         int devnum;
124                         if (major(stb.st_rdev) == MD_MAJOR)
125                                 devnum = minor(stb.st_rdev);
126                         else
127                                 devnum = -1-(minor(stb.st_rdev)>>6);
128                         map_delete(&map, devnum);
129                         map_write(map);
130                         map_free(map);
131                 }
132         }
133         return 0;
134 }
135
136 int Manage_resize(char *devname, int fd, long long size, int raid_disks)
137 {
138         mdu_array_info_t info;
139         if (ioctl(fd, GET_ARRAY_INFO, &info) != 0) {
140                 fprintf(stderr, Name ": Cannot get array information for %s: %s\n",
141                         devname, strerror(errno));
142                 return 1;
143         }
144         if (size >= 0)
145                 info.size = size;
146         if (raid_disks > 0)
147                 info.raid_disks = raid_disks;
148         if (ioctl(fd, SET_ARRAY_INFO, &info) != 0) {
149                 fprintf(stderr, Name ": Cannot set device size/shape for %s: %s\n",
150                         devname, strerror(errno));
151                 return 1;
152         }
153         return 0;
154 }
155
156 int Manage_reconfig(char *devname, int fd, int layout)
157 {
158         mdu_array_info_t info;
159         if (ioctl(fd, GET_ARRAY_INFO, &info) != 0) {
160                 fprintf(stderr, Name ": Cannot get array information for %s: %s\n",
161                         devname, strerror(errno));
162                 return 1;
163         }
164         info.layout = layout;
165         printf("layout set to %d\n", info.layout);
166         if (ioctl(fd, SET_ARRAY_INFO, &info) != 0) {
167                 fprintf(stderr, Name ": Cannot set layout for %s: %s\n",
168                         devname, strerror(errno));
169                 return 1;
170         }
171         return 0;
172 }
173
174 static int
175 add_remove_device_container(int fd, int add_remove, struct stat *stb)
176 {
177         int devnum = fd2devnum(fd);
178         char *devname = devnum2devname(devnum);
179         int sfd = devname ? connect_monitor(devname) : -1;
180         struct md_message msg;
181         int err = 0;
182
183         if (devname && sfd < 0) {
184                 fprintf(stderr, Name ": Cannot connect to monitor for %s: %s\n",
185                         devname, strerror(errno));
186                 free(devname);
187                 return 1;
188         } else if (sfd < 0) {
189                 fprintf(stderr, Name ": Cannot determine container name for"
190                         " device number %d\n", devnum);
191                 return 1;
192         }
193
194         if (add_remove)
195                 ack(sfd, 0, 0);
196         else if (send_remove_device(sfd, stb->st_rdev, 0, 0) != 0) {
197                 fprintf(stderr, Name ": Failed to send \'%s device\'"
198                         " message to the container monitor\n",
199                         add_remove ? "add" : "remove");
200                 err = 1;
201         }
202
203         /* check the reply */
204         if (!err && receive_message(sfd, &msg, 0) != 0) {
205                 fprintf(stderr, Name ": Failed to receive an acknowledgement"
206                         " from the container monitor\n");
207                 err = 1;
208         }
209
210         if (!err && msg.seq != 0) {
211                 fprintf(stderr, Name ": %s device failed error code %d\n",
212                         add_remove ? "Add" : "Remove", msg.seq);
213                 err = 1;
214         }
215
216         free(devname);
217         close(sfd);
218
219         return err;
220 }
221
222 int Manage_subdevs(char *devname, int fd,
223                    mddev_dev_t devlist, int verbose)
224 {
225         /* do something to each dev.
226          * devmode can be
227          *  'a' - add the device
228          *         try HOT_ADD_DISK
229          *         If that fails EINVAL, try ADD_NEW_DISK
230          *  'r' - remove the device HOT_REMOVE_DISK
231          *        device can be 'faulty' or 'detached' in which case all
232          *        matching devices are removed.
233          *  'f' - set the device faulty SET_DISK_FAULTY
234          *        device can be 'detached' in which case any device that
235          *        is inaccessible will be marked faulty.
236          */
237         mdu_array_info_t array;
238         mdu_disk_info_t disc;
239         unsigned long long array_size;
240         mddev_dev_t dv, next = NULL;
241         struct stat stb;
242         int j, jnext = 0;
243         int tfd;
244         struct supertype *st, *tst;
245         int duuid[4];
246         int ouuid[4];
247
248         if (ioctl(fd, GET_ARRAY_INFO, &array)) {
249                 fprintf(stderr, Name ": cannot get array info for %s\n",
250                         devname);
251                 return 1;
252         }
253
254         /* array.size is only 32 bit and may be truncated.
255          * So read from sysfs if possible, and record number of sectors
256          */
257
258         array_size = get_component_size(fd);
259         if (array_size <= 0)
260                 array_size = array.size * 2;
261
262         tst = super_by_fd(fd);
263         if (!tst) {
264                 fprintf(stderr, Name ": unsupport array - version %d.%d\n",
265                         array.major_version, array.minor_version);
266                 return 1;
267         }
268
269         for (dv = devlist, j=0 ; dv; dv = next, j = jnext) {
270                 unsigned long long ldsize;
271                 char dvname[20];
272                 char *dnprintable = dv->devname;
273
274                 next = dv->next;
275                 jnext = 0;
276
277                 if (strcmp(dv->devname, "failed")==0 ||
278                     strcmp(dv->devname, "faulty")==0) {
279                         if (dv->disposition != 'r') {
280                                 fprintf(stderr, Name ": %s only meaningful "
281                                         "with -r, not -%c\n",
282                                         dv->devname, dv->disposition);
283                                 return 1;
284                         }
285                         for (; j < array.raid_disks + array.nr_disks ; j++) {
286                                 disc.number = j;
287                                 if (ioctl(fd, GET_DISK_INFO, &disc))
288                                         continue;
289                                 if (disc.major == 0 && disc.minor == 0)
290                                         continue;
291                                 if ((disc.state & 1) == 0) /* faulty */
292                                         continue;
293                                 stb.st_rdev = makedev(disc.major, disc.minor);
294                                 next = dv;
295                                 jnext = j+1;
296                                 sprintf(dvname,"%d:%d", disc.major, disc.minor);
297                                 dnprintable = dvname;
298                                 break;
299                         }
300                         if (jnext == 0)
301                                 continue;
302                 } else if (strcmp(dv->devname, "detached") == 0) {
303                         if (dv->disposition != 'r' && dv->disposition != 'f') {
304                                 fprintf(stderr, Name ": %s only meaningful "
305                                         "with -r of -f, not -%c\n",
306                                         dv->devname, dv->disposition);
307                                 return 1;
308                         }
309                         for (; j < array.raid_disks + array.nr_disks; j++) {
310                                 int sfd;
311                                 disc.number = j;
312                                 if (ioctl(fd, GET_DISK_INFO, &disc))
313                                         continue;
314                                 if (disc.major == 0 && disc.minor == 0)
315                                         continue;
316                                 sprintf(dvname,"%d:%d", disc.major, disc.minor);
317                                 sfd = dev_open(dvname, O_RDONLY);
318                                 if (sfd >= 0) {
319                                         close(sfd);
320                                         continue;
321                                 }
322                                 if (dv->disposition == 'f' &&
323                                     (disc.state & 1) == 1) /* already faulty */
324                                         continue;
325                                 if (errno != ENXIO)
326                                         continue;
327                                 stb.st_rdev = makedev(disc.major, disc.minor);
328                                 next = dv;
329                                 jnext = j+1;
330                                 dnprintable = dvname;
331                                 break;
332                         }
333                         if (jnext == 0)
334                                 continue;
335                 } else {
336                         j = 0;
337
338                         if (stat(dv->devname, &stb)) {
339                                 fprintf(stderr, Name ": cannot find %s: %s\n",
340                                         dv->devname, strerror(errno));
341                                 return 1;
342                         }
343                         if ((stb.st_mode & S_IFMT) != S_IFBLK) {
344                                 fprintf(stderr, Name ": %s is not a "
345                                         "block device.\n",
346                                         dv->devname);
347                                 return 1;
348                         }
349                 }
350                 switch(dv->disposition){
351                 default:
352                         fprintf(stderr, Name ": internal error - devmode[%s]=%d\n",
353                                 dv->devname, dv->disposition);
354                         return 1;
355                 case 'a':
356                         /* add the device */
357                         if (tst == &supertype_container_member) {
358                                 fprintf(stderr, Name ": Cannot add disks to a"
359                                         " \'member\' array, perform this"
360                                         " operation on the parent container\n");
361                                 return 1;
362                         } else if (tst->ss->external)
363                                 return add_remove_device_container(fd, 1, &stb);
364                         /* Make sure it isn't in use (in 2.6 or later) */
365                         tfd = open(dv->devname, O_RDONLY|O_EXCL);
366                         if (tfd < 0) {
367                                 fprintf(stderr, Name ": Cannot open %s: %s\n",
368                                         dv->devname, strerror(errno));
369                                 return 1;
370                         }
371                         remove_partitions(tfd);
372
373                         st = dup_super(tst);
374
375                         if (array.not_persistent==0)
376                                 st->ss->load_super(st, tfd, NULL);
377
378                         if (!get_dev_size(tfd, dv->devname, &ldsize)) {
379                                 close(tfd);
380                                 return 1;
381                         }
382                         close(tfd);
383
384                         if (array.major_version == 0 &&
385                             md_get_version(fd)%100 < 2) {
386                                 if (ioctl(fd, HOT_ADD_DISK,
387                                           (unsigned long)stb.st_rdev)==0) {
388                                         if (verbose >= 0)
389                                                 fprintf(stderr, Name ": hot added %s\n",
390                                                         dv->devname);
391                                         continue;
392                                 }
393
394                                 fprintf(stderr, Name ": hot add failed for %s: %s\n",
395                                         dv->devname, strerror(errno));
396                                 return 1;
397                         }
398
399                         if (array.not_persistent == 0) {
400
401                                 /* Make sure device is large enough */
402                                 if (tst->ss->avail_size(tst, ldsize/512) <
403                                     array_size) {
404                                         fprintf(stderr, Name ": %s not large enough to join array\n",
405                                                 dv->devname);
406                                         return 1;
407                                 }
408
409                                 /* need to find a sample superblock to copy, and
410                                  * a spare slot to use
411                                  */
412                                 for (j = 0; j < tst->max_devs; j++) {
413                                         char *dev;
414                                         int dfd;
415                                         disc.number = j;
416                                         if (ioctl(fd, GET_DISK_INFO, &disc))
417                                                 continue;
418                                         if (disc.major==0 && disc.minor==0)
419                                                 continue;
420                                         if ((disc.state & 4)==0) continue; /* sync */
421                                         /* Looks like a good device to try */
422                                         dev = map_dev(disc.major, disc.minor, 1);
423                                         if (!dev) continue;
424                                         dfd = dev_open(dev, O_RDONLY);
425                                         if (dfd < 0) continue;
426                                         if (tst->ss->load_super(tst, dfd,
427                                                                 NULL)) {
428                                                 close(dfd);
429                                                 continue;
430                                         }
431                                         close(dfd);
432                                         break;
433                                 }
434                                 if (!tst->sb) {
435                                         fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n");
436                                         return 1;
437                                 }
438                                 /* Possibly this device was recently part of the array
439                                  * and was temporarily removed, and is now being re-added.
440                                  * If so, we can simply re-add it.
441                                  */
442                                 tst->ss->uuid_from_super(tst, duuid);
443
444                                 /* re-add doesn't work for version-1 superblocks
445                                  * before 2.6.18 :-(
446                                  */
447                                 if (array.major_version == 1 &&
448                                     get_linux_version() <= 2006018)
449                                         ;
450                                 else if (st->sb) {
451                                         st->ss->uuid_from_super(st, ouuid);
452                                         if (memcmp(duuid, ouuid, sizeof(ouuid))==0) {
453                                                 /* looks close enough for now.  Kernel
454                                                  * will worry about whether a bitmap
455                                                  * based reconstruction is possible.
456                                                  */
457                                                 struct mdinfo mdi;
458                                                 st->ss->getinfo_super(st, &mdi);
459                                                 disc.major = major(stb.st_rdev);
460                                                 disc.minor = minor(stb.st_rdev);
461                                                 disc.number = mdi.disk.number;
462                                                 disc.raid_disk = mdi.disk.raid_disk;
463                                                 disc.state = mdi.disk.state;
464                                                 if (dv->writemostly)
465                                                         disc.state |= 1 << MD_DISK_WRITEMOSTLY;
466                                                 if (ioctl(fd, ADD_NEW_DISK, &disc) == 0) {
467                                                         if (verbose >= 0)
468                                                                 fprintf(stderr, Name ": re-added %s\n", dv->devname);
469                                                         continue;
470                                                 }
471                                                 /* fall back on normal-add */
472                                         }
473                                 }
474                         } else {
475                                 /* non-persistent. Must ensure that new drive
476                                  * is at least array.size big.
477                                  */
478                                 if (ldsize/512 < array_size) {
479                                         fprintf(stderr, Name ": %s not large enough to join array\n",
480                                                 dv->devname);
481                                         return 1;
482                                 }
483                         }
484                         /* in 2.6.17 and earlier, version-1 superblocks won't
485                          * use the number we write, but will choose a free number.
486                          * we must choose the same free number, which requires
487                          * starting at 'raid_disks' and counting up
488                          */
489                         for (j = array.raid_disks; j< tst->max_devs; j++) {
490                                 disc.number = j;
491                                 if (ioctl(fd, GET_DISK_INFO, &disc))
492                                         break;
493                                 if (disc.major==0 && disc.minor==0)
494                                         break;
495                                 if (disc.state & 8) /* removed */
496                                         break;
497                         }
498                         disc.major = major(stb.st_rdev);
499                         disc.minor = minor(stb.st_rdev);
500                         disc.number =j;
501                         disc.state = 0;
502                         if (array.not_persistent==0) {
503                                 int dfd;
504                                 if (dv->writemostly)
505                                         disc.state |= 1 << MD_DISK_WRITEMOSTLY;
506                                 dfd = open(dv->devname, O_RDWR | O_EXCL);
507                                 tst->ss->add_to_super(tst, &disc, dfd,
508                                                       dv->devname);
509                                 /* write_init_super will close 'dfd' */
510                                 if (tst->ss->write_init_super(tst))
511                                         return 1;
512                         } else if (dv->re_add) {
513                                 /*  this had better be raid1.
514                                  * As we are "--re-add"ing we must find a spare slot
515                                  * to fill.
516                                  */
517                                 char *used = malloc(array.raid_disks);
518                                 memset(used, 0, array.raid_disks);
519                                 for (j=0; j< tst->max_devs; j++) {
520                                         mdu_disk_info_t disc2;
521                                         disc2.number = j;
522                                         if (ioctl(fd, GET_DISK_INFO, &disc2))
523                                                 continue;
524                                         if (disc2.major==0 && disc2.minor==0)
525                                                 continue;
526                                         if (disc2.state & 8) /* removed */
527                                                 continue;
528                                         if (disc2.raid_disk < 0)
529                                                 continue;
530                                         if (disc2.raid_disk > array.raid_disks)
531                                                 continue;
532                                         used[disc2.raid_disk] = 1;
533                                 }
534                                 for (j=0 ; j<array.raid_disks; j++)
535                                         if (!used[j]) {
536                                                 disc.raid_disk = j;
537                                                 disc.state |= (1<<MD_DISK_SYNC);
538                                                 break;
539                                         }
540                         }
541                         if (dv->writemostly)
542                                 disc.state |= (1 << MD_DISK_WRITEMOSTLY);
543                         if (ioctl(fd,ADD_NEW_DISK, &disc)) {
544                                 fprintf(stderr, Name ": add new device failed for %s as %d: %s\n",
545                                         dv->devname, j, strerror(errno));
546                                 return 1;
547                         }
548                         if (verbose >= 0)
549                                 fprintf(stderr, Name ": added %s\n", dv->devname);
550                         break;
551
552                 case 'r':
553                         /* hot remove */
554                         if (tst == &supertype_container_member) {
555                                 fprintf(stderr, Name ": Cannot remove disks from a"
556                                         " \'member\' array, perform this"
557                                         " operation on the parent container\n");
558                                 return 1;
559                         } else if (tst->ss->external)
560                                 return add_remove_device_container(fd, 0, &stb);
561                         /* FIXME check that it is a current member */
562                         if (ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev)) {
563                                 fprintf(stderr, Name ": hot remove failed "
564                                         "for %s: %s\n", dnprintable,
565                                         strerror(errno));
566                                 return 1;
567                         }
568                         if (verbose >= 0)
569                                 fprintf(stderr, Name ": hot removed %s\n",
570                                         dnprintable);
571                         break;
572
573                 case 'f': /* set faulty */
574                         /* FIXME check current member */
575                         if (ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev)) {
576                                 fprintf(stderr, Name ": set device faulty failed for %s:  %s\n",
577                                         dnprintable, strerror(errno));
578                                 return 1;
579                         }
580                         if (verbose >= 0)
581                                 fprintf(stderr, Name ": set %s faulty in %s\n",
582                                         dnprintable, devname);
583                         break;
584                 }
585         }
586         return 0;
587
588 }
589
590 int autodetect(void)
591 {
592         /* Open any md device, and issue the RAID_AUTORUN ioctl */
593         int rv = 1;
594         int fd = dev_open("9:0", O_RDONLY);
595         if (fd >= 0) {
596                 if (ioctl(fd, RAID_AUTORUN, 0) == 0)
597                         rv = 0;
598                 close(fd);
599         }
600         return rv;
601 }
602 #endif