X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=Manage.c;h=660580b9c4ed247a75534b8758f25e8ba5770bf3;hb=280a927d3d8da258a70df13df4f780d823fc1da2;hp=eda275a9ee24a2f7fad4e1753931a40ba857dde0;hpb=82b27616de634964db1a71bd5d9813db71e391a1;p=thirdparty%2Fmdadm.git diff --git a/Manage.c b/Manage.c index eda275a9..660580b9 100644 --- a/Manage.c +++ b/Manage.c @@ -1,7 +1,7 @@ /* - * mdctl - manage Linux "md" devices aka RAID arrays. + * mdadm - manage Linux "md" devices aka RAID arrays. * - * Copyright (C) 2001 Neil Brown + * Copyright (C) 2001-2006 Neil Brown * * * This program is free software; you can redistribute it and/or modify @@ -27,7 +27,7 @@ * Australia */ -#include "mdctl.h" +#include "mdadm.h" #include "md_u.h" #include "md_p.h" @@ -72,18 +72,17 @@ int Manage_ro(char *devname, int fd, int readonly) return 0; } -int Manage_runstop(char *devname, int fd, int runstop) +int Manage_runstop(char *devname, int fd, int runstop, int quiet) { /* Run or stop the array. array must already be configured * required >= 0.90.0 */ - mdu_array_info_t array; mdu_param_t param; /* unused */ if (runstop == -1 && md_get_version(fd) < 9000) { if (ioctl(fd, STOP_MD, 0)) { - fprintf(stderr, Name ": stopping device %s failed: %s\n", - devname, strerror(errno)); + if (!quiet) fprintf(stderr, Name ": stopping device %s failed: %s\n", + devname, strerror(errno)); return 1; } } @@ -107,17 +106,56 @@ int Manage_runstop(char *devname, int fd, int runstop) } } else if (runstop < 0){ if (ioctl(fd, STOP_ARRAY, NULL)) { - fprintf(stderr, Name ": fail to re writable for %s: %s\n", - devname, strerror(errno)); + if (!quiet) + fprintf(stderr, Name ": fail to stop array %s: %s\n", + devname, strerror(errno)); return 1; } } return 0; } +int Manage_resize(char *devname, int fd, long long size, int raid_disks) +{ + mdu_array_info_t info; + if (ioctl(fd, GET_ARRAY_INFO, &info) != 0) { + fprintf(stderr, Name ": Cannot get array information for %s: %s\n", + devname, strerror(errno)); + return 1; + } + if (size >= 0) + info.size = size; + if (raid_disks > 0) + info.raid_disks = raid_disks; + if (ioctl(fd, SET_ARRAY_INFO, &info) != 0) { + fprintf(stderr, Name ": Cannot set device size/shape for %s: %s\n", + devname, strerror(errno)); + return 1; + } + return 0; +} + +int Manage_reconfig(char *devname, int fd, int layout) +{ + mdu_array_info_t info; + if (ioctl(fd, GET_ARRAY_INFO, &info) != 0) { + fprintf(stderr, Name ": Cannot get array information for %s: %s\n", + devname, strerror(errno)); + return 1; + } + info.layout = layout; + printf("layout set to %d\n", info.layout); + if (ioctl(fd, SET_ARRAY_INFO, &info) != 0) { + fprintf(stderr, Name ": Cannot set layout for %s: %s\n", + devname, strerror(errno)); + return 1; + } + return 0; +} + int Manage_subdevs(char *devname, int fd, - int devcnt, char *devnames[], int devmodes[]) - { + mddev_dev_t devlist, int verbose) +{ /* do something to each dev. * devmode can be * 'a' - add the device @@ -128,44 +166,135 @@ int Manage_subdevs(char *devname, int fd, */ mdu_array_info_t array; mdu_disk_info_t disc; + mddev_dev_t dv; struct stat stb; - int i,j; + int j; + int tfd; + struct supertype *st; + void *dsuper = NULL; + void *osuper = NULL; /* original super */ + int duuid[4]; + int ouuid[4]; if (ioctl(fd, GET_ARRAY_INFO, &array)) { fprintf(stderr, Name ": cannot get array info for %s\n", devname); return 1; } - for (i=0 ; inext) { + if (stat(dv->devname, &stb)) { fprintf(stderr, Name ": cannot find %s: %s\n", - devnames[i], strerror(errno)); + dv->devname, strerror(errno)); return 1; } if ((stb.st_mode & S_IFMT) != S_IFBLK) { fprintf(stderr, Name ": %s is not a block device.\n", - devnames[i]); + dv->devname); return 1; } - switch(devmodes[i]){ + switch(dv->disposition){ default: - fprintf(stderr, Name ": internal error - devmode[%d]=%d\n", - i, devmodes[i]); + fprintf(stderr, Name ": internal error - devmode[%s]=%d\n", + dv->devname, dv->disposition); return 1; case 'a': /* add the device - hot or cold */ - if (ioctl(fd, HOT_ADD_DISK, stb.st_rdev)==0) { - fprintf(stderr, Name ": hot added %s\n", - devnames[i]); - continue; + st = super_by_version(array.major_version, + array.minor_version); + if (!st) { + fprintf(stderr, Name ": unsupport array - version %d.%d\n", + array.major_version, array.minor_version); + return 1; + } + + /* Make sure it isn't in use (in 2.6 or later) */ + tfd = open(dv->devname, O_RDONLY|O_EXCL); + if (tfd < 0) { + fprintf(stderr, Name ": Cannot open %s: %s\n", + dv->devname, strerror(errno)); + return 1; + } + if (array.not_persistent==0) + st->ss->load_super(st, tfd, &osuper, NULL); + /* will use osuper later */ + close(tfd); + + if (array.major_version == 0 && + md_get_version(fd)%100 < 2) { + if (ioctl(fd, HOT_ADD_DISK, + (unsigned long)stb.st_rdev)==0) { + if (verbose >= 0) + fprintf(stderr, Name ": hot added %s\n", + dv->devname); + continue; + } + + fprintf(stderr, Name ": hot add failed for %s: %s\n", + dv->devname, strerror(errno)); + return 1; + } + + if (array.not_persistent == 0) { + + /* need to find a sample superblock to copy, and + * a spare slot to use + */ + for (j=0; jmax_devs; j++) { + char *dev; + int dfd; + disc.number = j; + if (ioctl(fd, GET_DISK_INFO, &disc)) + continue; + if (disc.major==0 && disc.minor==0) + continue; + if ((disc.state & 4)==0) continue; /* sync */ + /* Looks like a good device to try */ + dev = map_dev(disc.major, disc.minor, 1); + if (!dev) continue; + dfd = dev_open(dev, O_RDONLY); + if (dfd < 0) continue; + if (st->ss->load_super(st, dfd, &dsuper, NULL)) { + close(dfd); + continue; + } + close(dfd); + break; + } + if (!dsuper) { + fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n"); + return 1; + } + /* Possibly this device was recently part of the array + * and was temporarily removed, and is now being re-added. + * If so, we can simply re-add it. + */ + st->ss->uuid_from_super(duuid, dsuper); + + if (osuper) { + st->ss->uuid_from_super(ouuid, osuper); + if (memcmp(duuid, ouuid, sizeof(ouuid))==0) { + /* look close enough for now. Kernel + * will worry about where a bitmap + * based reconstruct is possible + */ + struct mdinfo mdi; + st->ss->getinfo_super(&mdi, osuper); + disc.major = major(stb.st_rdev); + disc.minor = minor(stb.st_rdev); + disc.number = mdi.disk.number; + disc.raid_disk = mdi.disk.raid_disk; + disc.state = mdi.disk.state; + if (ioctl(fd, ADD_NEW_DISK, &disc) == 0) { + if (verbose >= 0) + fprintf(stderr, Name ": re-added %s\n", dv->devname); + continue; + } + /* fall back on normal-add */ + } + } } - /* try ADD_NEW_DISK. - * we might be creating, we might be assembling, - * it is hard to tell. - * set up number/raid_disk/state just - * in case - */ - for (j=0; jmax_devs; j++) { + disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) break; if (disc.major==0 && disc.minor==0) @@ -173,39 +302,78 @@ int Manage_subdevs(char *devname, int fd, if (disc.state & 8) /* removed */ break; } + disc.major = major(stb.st_rdev); + disc.minor = minor(stb.st_rdev); disc.number =j; - disc.raid_disk = j; disc.state = 0; - disc.major = MAJOR(stb.st_rdev); - disc.minor = MINOR(stb.st_rdev); + if (array.not_persistent==0) { + if (dv->writemostly) + disc.state |= 1 << MD_DISK_WRITEMOSTLY; + st->ss->add_to_super(dsuper, &disc); + if (st->ss->write_init_super(st, dsuper, &disc, dv->devname)) + return 1; + } else if (dv->re_add) { + /* this had better be raid1. + * As we are "--re-add"ing we must find a spare slot + * to fill. + */ + char *used = malloc(array.raid_disks); + memset(used, 0, array.raid_disks); + for (j=0; j< st->max_devs; j++) { + mdu_disk_info_t disc2; + disc2.number = j; + if (ioctl(fd, GET_DISK_INFO, &disc2)) + continue; + if (disc2.major==0 && disc2.minor==0) + continue; + if (disc2.state & 8) /* removed */ + continue; + if (disc2.raid_disk < 0) + continue; + if (disc2.raid_disk > array.raid_disks) + continue; + used[disc2.raid_disk] = 1; + } + for (j=0 ; jwritemostly) + disc.state |= (1 << MD_DISK_WRITEMOSTLY); if (ioctl(fd,ADD_NEW_DISK, &disc)) { - fprintf(stderr, Name ": add new disk failed for %s: %s\n", - devnames[i], strerror(errno)); + fprintf(stderr, Name ": add new device failed for %s as %d: %s\n", + dv->devname, j, strerror(errno)); return 1; } - fprintf(stderr, Name ": added %s\n", devnames[i]); + if (verbose >= 0) + fprintf(stderr, Name ": added %s\n", dv->devname); break; case 'r': /* hot remove */ /* FIXME check that it is a current member */ - if (ioctl(fd, HOT_REMOVE_DISK, stb.st_rdev)) { + if (ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev)) { fprintf(stderr, Name ": hot remove failed for %s: %s\n", - devnames[i], strerror(errno)); + dv->devname, strerror(errno)); return 1; } - fprintf(stderr, Name ": hot removed %s\n", devnames[i]); + if (verbose >= 0) + fprintf(stderr, Name ": hot removed %s\n", dv->devname); break; case 'f': /* set faulty */ /* FIXME check current member */ - if (ioctl(fd, SET_DISK_FAULTY, stb.st_rdev)) { - fprintf(stderr, Name ": set disk faulty failed for %s: %s\n", - devnames[i], strerror(errno)); + if (ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev)) { + fprintf(stderr, Name ": set device faulty failed for %s: %s\n", + dv->devname, strerror(errno)); return 1; } - fprintf(stderr, Name ": set %s faulty in %s\n", - devnames[i], devname); + if (verbose >= 0) + fprintf(stderr, Name ": set %s faulty in %s\n", + dv->devname, devname); break; } }