+
+ if (size >= 0 &&
+ (chunksize || level!= UnSet || layout_str || raid_disks)) {
+ fprintf(stderr, Name ": cannot change component size at the same time "
+ "as other changes.\n"
+ " Change size first, then check data is intact before "
+ "making other changes.\n");
+ return 1;
+ }
+
+ if (raid_disks && raid_disks < array.raid_disks && array.level > 1 &&
+ get_linux_version() < 2006032 &&
+ !check_env("MDADM_FORCE_FEWER")) {
+ fprintf(stderr, Name ": reducing the number of devices is not safe before Linux 2.6.32\n"
+ " Please use a newer kernel\n");
+ return 1;
+ }
+ sra = sysfs_read(fd, 0, GET_LEVEL);
+ frozen = freeze_array(sra);
+ if (frozen < 0) {
+ fprintf(stderr, Name ": %s is performing resync/recovery and cannot"
+ " be reshaped\n", devname);
+ return 1;
+ }
+
+ /* ========= set size =============== */
+ if (size >= 0 && (size == 0 || size != array.size)) {
+ array.size = size;
+ if (array.size != size) {
+ /* got truncated to 32bit, write to
+ * component_size instead
+ */
+ if (sra)
+ rv = sysfs_set_num(sra, NULL,
+ "component_size", size);
+ else
+ rv = -1;
+ } else
+ rv = ioctl(fd, SET_ARRAY_INFO, &array);
+ if (rv != 0) {
+ int err = errno;
+ fprintf(stderr, Name ": Cannot set device size for %s: %s\n",
+ devname, strerror(err));
+ if (err == EBUSY &&
+ (array.state & (1<<MD_SB_BITMAP_PRESENT)))
+ fprintf(stderr, " Bitmap must be removed before size can be changed\n");
+ rv = 1;
+ goto release;
+ }
+ ioctl(fd, GET_ARRAY_INFO, &array);
+ size = get_component_size(fd);
+ if (size == 0)
+ size = array.size;
+ if (!quiet)
+ fprintf(stderr, Name ": component size of %s has been set to %lluK\n",
+ devname, size);
+ changed = 1;
+ } else {
+ size = get_component_size(fd);
+ if (size == 0)
+ size = array.size;
+ }
+
+ /* ======= set level =========== */
+ if (level != UnSet && level != array.level) {
+ /* Trying to change the level.
+ * We might need to change layout first and schedule a
+ * level change for later.
+ * Level changes that can happen immediately are:
+ * 0->4,5,6 1->5 4->5,6 5->1,6
+ * Level changes that need a layout change first are:
+ * 6->5,4,0 : need a -6 layout, or parity-last
+ * 5->4,0 : need parity-last
+ */
+ if ((array.level == 6 || array.level == 5) &&
+ (level == 5 || level == 4 || level == 0)) {
+ /* Don't change level yet, but choose intermediate
+ * layout
+ */
+ if (level == 5) {
+ if (layout_str == NULL)
+ switch (array.layout) {
+ case ALGORITHM_LEFT_ASYMMETRIC:
+ case ALGORITHM_LEFT_ASYMMETRIC_6:
+ case ALGORITHM_ROTATING_N_RESTART:
+ layout_str = "left-asymmetric-6";
+ break;
+ case ALGORITHM_LEFT_SYMMETRIC:
+ case ALGORITHM_LEFT_SYMMETRIC_6:
+ case ALGORITHM_ROTATING_N_CONTINUE:
+ layout_str = "left-symmetric-6";
+ break;
+ case ALGORITHM_RIGHT_ASYMMETRIC:
+ case ALGORITHM_RIGHT_ASYMMETRIC_6:
+ case ALGORITHM_ROTATING_ZERO_RESTART:
+ layout_str = "right-asymmetric-6";
+ break;
+ case ALGORITHM_RIGHT_SYMMETRIC:
+ case ALGORITHM_RIGHT_SYMMETRIC_6:
+ layout_str = "right-symmetric-6";
+ break;
+ case ALGORITHM_PARITY_0:
+ case ALGORITHM_PARITY_0_6:
+ layout_str = "parity-first-6";
+ break;
+ case ALGORITHM_PARITY_N:
+ layout_str = "parity-last";
+ break;
+ default:
+ fprintf(stderr, Name ": %s: cannot"
+ "convert layout to RAID5 equivalent\n",
+ devname);
+ rv = 1;
+ goto release;
+ }
+ else {
+ int l = map_name(r5layout, layout_str);
+ if (l == UnSet) {
+ fprintf(stderr, Name ": %s: layout '%s' not recognised\n",
+ devname, layout_str);
+ rv = 1;
+ goto release;
+ }
+ if (l != ALGORITHM_PARITY_N) {
+ /* need the -6 version */
+ char *ls = map_num(r5layout, l);
+ strcat(strcpy(alt_layout, ls),
+ "-6");
+ layout_str = alt_layout;
+ }
+ }
+ if (raid_disks)
+ /* The final raid6->raid5 conversion
+ * will reduce the number of disks,
+ * so now we need to aim higher
+ */
+ raid_disks++;
+ } else
+ layout_str = "parity-last";
+ } else {
+ c = map_num(pers, level);
+ if (c == NULL) {
+ rv = 1;/* not possible */
+ goto release;
+ }
+ err = sysfs_set_str(sra, NULL, "level", c);
+ if (err) {
+ err = errno;
+ fprintf(stderr, Name ": %s: could not set level to %s\n",
+ devname, c);
+ if (err == EBUSY &&
+ (array.state & (1<<MD_SB_BITMAP_PRESENT)))
+ fprintf(stderr, " Bitmap must be removed before level can be changed\n");
+ rv = 1;
+ goto release;
+ }
+ orig = array;
+ orig_level = orig.level;
+ ioctl(fd, GET_ARRAY_INFO, &array);
+ if (layout_str == NULL &&
+ orig.level == 5 && level == 6 &&
+ array.layout != orig.layout)
+ layout_str = map_num(r5layout, orig.layout);
+ if (!quiet)
+ fprintf(stderr, Name " level of %s changed to %s\n",
+ devname, c);
+ changed = 1;
+ }
+ }
+
+ /* ========= set shape (chunk_size / layout / ndisks) ============== */
+ /* Check if layout change is a no-op */
+ if (layout_str) switch(array.level) {
+ case 5:
+ if (array.layout == map_name(r5layout, layout_str))
+ layout_str = NULL;
+ break;
+ case 6:
+ if (layout_str == NULL &&
+ ((chunksize && chunksize * 1024 != array.chunk_size) ||
+ (raid_disks && raid_disks != array.raid_disks)) &&
+ array.layout >= 16) {
+ fprintf(stderr, Name
+ ": %s has a non-standard layout. If you wish to preserve this\n"
+ " during the reshape, please specify --layout=preserve\n"
+ " If you want to change it, specify a layout or use --layout=normalise\n",
+ devname);
+ rv = 1;
+ goto release;
+ }
+ if (strcmp(layout_str, "normalise") == 0 ||
+ strcmp(layout_str, "normalize") == 0) {
+ char *hyphen;
+ strcpy(alt_layout, map_num(r6layout, array.layout));
+ hyphen = strrchr(alt_layout, '-');
+ if (hyphen && strcmp(hyphen, "-6") == 0) {
+ *hyphen = 0;
+ layout_str = alt_layout;
+ }
+ }
+
+ if (array.layout == map_name(r6layout, layout_str))
+ layout_str = NULL;
+ if (layout_str && strcmp(layout_str, "preserve") == 0)
+ layout_str = NULL;
+ break;
+ }
+ if (layout_str == NULL
+ && (chunksize == 0 || chunksize*1024 == array.chunk_size)
+ && (raid_disks == 0 || raid_disks == array.raid_disks)) {
+ rv = 0;
+ if (level != UnSet && level != array.level) {
+ /* Looks like this level change doesn't need
+ * a reshape after all.
+ */
+ c = map_num(pers, level);
+ if (c) {
+ rv = sysfs_set_str(sra, NULL, "level", c);
+ if (rv) {
+ int err = errno;
+ fprintf(stderr, Name ": %s: could not set level to %s\n",
+ devname, c);
+ if (err == EBUSY &&
+ (array.state & (1<<MD_SB_BITMAP_PRESENT)))
+ fprintf(stderr, " Bitmap must be removed before level can be changed\n");
+ }
+ }
+ } else if (!changed && !quiet)
+ fprintf(stderr, Name ": %s: no change requested\n",
+ devname);
+ goto release;
+ }
+