return 1;
} else if (strcmp(file, "internal") == 0) {
int d;
+ if (st->ss->add_internal_bitmap == NULL) {
+ fprintf(stderr, Name ": Internal bitmaps not supported "
+ "with %s metadata\n", st->ss->name);
+ return 1;
+ }
for (d=0; d< st->max_devs; d++) {
mdu_disk_info_t disk;
char *dv;
/*
* When reshaping an array we might need to backup some data.
* This is written to all spares with a 'super_block' describing it.
- * The superblock goes 1K form the end of the used space on the
+ * The superblock goes 4K from the end of the used space on the
* device.
* It if written after the backup is complete.
* It has the following structure.
return 1;
}
+ 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")) {
return 1;
}
sra = sysfs_read(fd, 0, GET_LEVEL);
- frozen = freeze_array(sra);
+ if (sra)
+ frozen = freeze_array(sra);
+ else {
+ fprintf(stderr, Name ": failed to read sysfs parameters for %s\n",
+ devname);
+ return 1;
+ }
if (frozen < 0) {
fprintf(stderr, Name ": %s is performing resync/recovery and cannot"
" be reshaped\n", devname);
} 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(errno));
+ 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)/2;
+ if (size == 0)
+ size = array.size;
if (!quiet)
- fprintf(stderr, Name ": component size of %s has been set to %dK\n",
- devname, array.size);
+ fprintf(stderr, Name ": component size of %s has been set to %lluK\n",
+ devname, size);
changed = 1;
+ } else {
+ size = get_component_size(fd)/2;
+ if (size == 0)
+ size = array.size;
}
/* ======= set level =========== */
layout_str = "parity-last";
} else {
c = map_num(pers, level);
- if (c == NULL)
- return 1;/* not possible */
+ 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;
}
c = map_num(pers, level);
if (c) {
rv = sysfs_set_str(sra, NULL, "level", c);
- if (rv)
+ 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",
if (chunksize) {
nchunk = chunksize * 1024;
- if (array.size % chunksize) {
- fprintf(stderr, Name ": component size %dK is not"
+ if (size % chunksize) {
+ fprintf(stderr, Name ": component size %lluK is not"
" a multiple of chunksize %dK\n",
- array.size, chunksize);
+ size, chunksize);
break;
}
}
if (nlayout == UnSet) {
fprintf(stderr, Name ": layout %s not understood for raid5.\n",
layout_str);
- return 1;
+ rv = 1;
+ goto release;
}
break;
if (nlayout == UnSet) {
fprintf(stderr, Name ": layout %s not understood for raid6.\n",
layout_str);
- return 1;
+ rv = 1;
+ goto release;
}
break;
}
ndata--;
}
+ if (odata == ndata &&
+ get_linux_version() < 2006032) {
+ fprintf(stderr, Name ": in-place reshape is not safe before 2.6.32, sorry.\n");
+ break;
+ }
+
/* Check that we can hold all the data */
- size = ndata * array.size;
get_dev_size(fd, NULL, &array_size);
- if (size < (array_size/1024)) {
+ if (ndata * size < (array_size/1024)) {
fprintf(stderr, Name ": this change will reduce the size of the array.\n"
" use --grow --array-size first to truncate array.\n"
" e.g. mdadm --grow %s --array-size %llu\n",
- devname, size);
+ devname, ndata * size);
rv = 1;
break;
}
* old stripes and a whole number of new stripes.
* So LCM for (chunksize*datadisks).
*/
- a = ochunk/512 * odata;
- b = nchunk/512 * ndata;
+ a = (ochunk/512) * odata;
+ b = (nchunk/512) * ndata;
/* Find GCD */
while (a != b) {
if (a < b)
a -= b;
}
/* LCM == product / GCD */
- blocks = ochunk/512 * nchunk/512 * odata * ndata / a;
+ blocks = (ochunk/512) * (nchunk/512) * odata * ndata / a;
sysfs_free(sra);
sra = sysfs_read(fd, 0,
GET_COMPONENT|GET_DEVS|GET_OFFSET|GET_STATE|
GET_CACHE);
+ if (!sra) {
+ fprintf(stderr, Name ": %s: Cannot get array details from sysfs\n",
+ devname);
+ rv = 1;
+ break;
+ }
+
if (ndata == odata) {
/* Make 'blocks' bigger for better throughput, but
* not so big that we reject it below.
fprintf(stderr, Name ": Need to backup %luK of critical "
"section..\n", blocks/2);
- if (!sra) {
- fprintf(stderr, Name ": %s: Cannot get array details from sysfs\n",
- devname);
- rv = 1;
- break;
- }
-
if (blocks >= sra->component_size/2) {
fprintf(stderr, Name ": %s: Something wrong - reshape aborted\n",
devname);
char *dn = map_dev(sd->disk.major,
sd->disk.minor, 1);
fdlist[d] = dev_open(dn, O_RDWR);
- offsets[d] = (sra->component_size - blocks - 8)*512;
+ offsets[d] = (sd->data_offset + sra->component_size - blocks - 8)*512;
if (fdlist[d]<0) {
fprintf(stderr, Name ": %s: cannot open component %s\n",
devname, dn?dn:"-unknown");
if (ochunk == nchunk && olayout == nlayout) {
array.raid_disks = ndisks;
if (ioctl(fd, SET_ARRAY_INFO, &array) != 0) {
+ int err = errno;
rv = 1;
fprintf(stderr, Name ": Cannot set device shape for %s: %s\n",
devname, strerror(errno));
if (ndisks < odisks &&
get_linux_version() < 2006030)
fprintf(stderr, Name ": linux 2.6.30 or later required\n");
+ if (err == EBUSY &&
+ (array.state & (1<<MD_SB_BITMAP_PRESENT)))
+ fprintf(stderr, " Bitmap must be removed before shape can be changed\n");
break;
}
/* set them all just in case some old 'new_*' value
* persists from some earlier problem
*/
+ int err = err; /* only used if rv==1, and always set if
+ * rv==1, so initialisation not needed,
+ * despite gcc warning
+ */
if (sysfs_set_num(sra, NULL, "chunk_size", nchunk) < 0)
- rv = 1;
- if (sysfs_set_num(sra, NULL, "layout", nlayout) < 0)
- rv = 1;
- if (sysfs_set_num(sra, NULL, "raid_disks", ndisks) < 0)
- rv = 1;
+ rv = 1, err = errno;
+ if (!rv && sysfs_set_num(sra, NULL, "layout", nlayout) < 0)
+ rv = 1, err = errno;
+ if (!rv && sysfs_set_num(sra, NULL, "raid_disks", ndisks) < 0)
+ rv = 1, err = errno;
if (rv) {
fprintf(stderr, Name ": Cannot set device shape for %s\n",
devname);
if (get_linux_version() < 2006030)
fprintf(stderr, Name ": linux 2.6.30 or later required\n");
+ if (err == EBUSY &&
+ (array.state & (1<<MD_SB_BITMAP_PRESENT)))
+ fprintf(stderr, " Bitmap must be removed before shape can be changed\n");
break;
}
}
*
*/
+/* FIXME return status is never checked */
int grow_backup(struct mdinfo *sra,
unsigned long long offset, /* per device */
unsigned long stripes, /* per device */
odata--;
if (level == 6)
odata--;
- sysfs_set_num(sra, NULL, "suspend_hi", (offset + stripes * chunk/512) * odata);
+ sysfs_set_num(sra, NULL, "suspend_hi", (offset + stripes * (chunk/512)) * odata);
/* Check that array hasn't become degraded, else we might backup the wrong data */
sysfs_get_ll(sra, NULL, "degraded", &new_degraded);
if (new_degraded != *degraded) {
}
if (part) {
bsb.arraystart2 = __cpu_to_le64(offset * odata);
- bsb.length2 = __cpu_to_le64(stripes * chunk/512 * odata);
+ bsb.length2 = __cpu_to_le64(stripes * (chunk/512) * odata);
} else {
bsb.arraystart = __cpu_to_le64(offset * odata);
- bsb.length = __cpu_to_le64(stripes * chunk/512 * odata);
+ bsb.length = __cpu_to_le64(stripes * (chunk/512) * odata);
}
if (part)
bsb.magic[15] = '2';
bsb.sb_csum2 = bsb_csum((char*)&bsb,
((char*)&bsb.sb_csum2)-((char*)&bsb));
- lseek64(destfd[i], destoffsets[i] - 4096, 0);
- write(destfd[i], &bsb, 512);
+ if (lseek64(destfd[i], destoffsets[i] - 4096, 0) != destoffsets[i] - 4096)
+ rv = 1;
+ rv = rv ?: write(destfd[i], &bsb, 512);
+ if (destoffsets[i] > 4096) {
+ if (lseek64(destfd[i], destoffsets[i]+stripes*chunk*odata, 0) !=
+ destoffsets[i]+stripes*chunk*odata)
+ rv = 1;
+ rv = rv ?: write(destfd[i], &bsb, 512);
+ }
fsync(destfd[i]);
}
- return 0;
+ return rv;
}
/* in 2.6.30, the value reported by sync_completed can be
* The various caller give appropriate values so that
* every works.
*/
+/* FIXME return value is often ignored */
int wait_backup(struct mdinfo *sra,
unsigned long long offset, /* per device */
unsigned long long blocks, /* per device */
int fd = sysfs_get_fd(sra, NULL, "sync_completed");
unsigned long long completed;
int i;
+ int rv;
if (fd < 0)
return -1;
bsb.length = __cpu_to_le64(0);
}
bsb.mtime = __cpu_to_le64(time(0));
+ rv = 0;
for (i = 0; i < dests; i++) {
bsb.devstart = __cpu_to_le64(destoffsets[i]/512);
bsb.sb_csum = bsb_csum((char*)&bsb, ((char*)&bsb.sb_csum)-((char*)&bsb));
if (memcmp(bsb.magic, "md_backup_data-2", 16) == 0)
bsb.sb_csum2 = bsb_csum((char*)&bsb,
((char*)&bsb.sb_csum2)-((char*)&bsb));
- lseek64(destfd[i], destoffsets[i]-4096, 0);
- write(destfd[i], &bsb, 512);
+ if (lseek64(destfd[i], destoffsets[i]-4096, 0) !=
+ destoffsets[i]-4096)
+ rv = 1;
+ rv = rv ?: write(destfd[i], &bsb, 512);
fsync(destfd[i]);
}
- return 0;
+ return rv;
}
static void fail(char *msg)
{
- write(2, msg, strlen(msg));
- write(2, "\n", 1);
- exit(1);
+ int rv;
+ rv = write(2, msg, strlen(msg));
+ rv |= write(2, "\n", 1);
+ exit(rv ? 1 : 2);
}
static char *abuf, *bbuf;
free(abuf);
free(bbuf);
abuflen = len;
- posix_memalign((void**)&abuf, 4096, abuflen);
- posix_memalign((void**)&bbuf, 4096, abuflen);
+ if (posix_memalign((void**)&abuf, 4096, abuflen) ||
+ posix_memalign((void**)&bbuf, 4096, abuflen)) {
+ abuflen = 0;
+ /* just stop validating on mem-alloc failure */
+ return;
+ }
}
lseek64(bfd, offset, 0);
if (read(bfd, bbuf, len) != len) {
- printf("len %llu\n", len);
+ //printf("len %llu\n", len);
fail("read first backup failed");
}
lseek64(afd, __le64_to_cpu(bsb2.arraystart)*512, 0);
if (read(afd, abuf, len) != len)
fail("read first from array failed");
if (memcmp(bbuf, abuf, len) != 0) {
+ #if 0
int i;
printf("offset=%llu len=%llu\n",
- __le64_to_cpu(bsb2.arraystart)*512, len);
+ (unsigned long long)__le64_to_cpu(bsb2.arraystart)*512, len);
for (i=0; i<len; i++)
if (bbuf[i] != abuf[i]) {
printf("first diff byte %d\n", i);
break;
}
+ #endif
fail("data1 compare failed");
}
}
char *buf;
int degraded = 0;
- posix_memalign((void**)&buf, 4096, disks * chunk);
+ if (posix_memalign((void**)&buf, 4096, disks * chunk))
+ /* Don't start the 'reshape' */
+ return 0;
sysfs_set_num(sra, NULL, "suspend_hi", 0);
sysfs_set_num(sra, NULL, "suspend_lo", 0);
grow_backup(sra, 0, stripes,
dests, destfd, destoffsets,
0, °raded, buf);
validate(afd, destfd[0], destoffsets[0]);
- wait_backup(sra, 0, stripes * chunk / 512, stripes * chunk / 512,
+ wait_backup(sra, 0, stripes * (chunk / 512), stripes * (chunk / 512),
dests, destfd, destoffsets,
0);
- sysfs_set_num(sra, NULL, "suspend_lo", (stripes * chunk/512) * data);
+ sysfs_set_num(sra, NULL, "suspend_lo", (stripes * (chunk/512)) * data);
free(buf);
/* FIXME this should probably be numeric */
sysfs_set_str(sra, NULL, "sync_max", "max");
int rv;
int degraded = 0;
- posix_memalign((void**)&buf, 4096, disks * chunk);
- start = sra->component_size - stripes * chunk/512;
+ if (posix_memalign((void**)&buf, 4096, disks * chunk))
+ return 0;
+ start = sra->component_size - stripes * (chunk/512);
sysfs_set_num(sra, NULL, "sync_max", start);
sysfs_set_str(sra, NULL, "sync_action", "reshape");
sysfs_set_num(sra, NULL, "suspend_lo", 0);
sysfs_set_num(sra, NULL, "suspend_hi", 0);
- rv = wait_backup(sra, 0, start - stripes * chunk/512, stripes * chunk/512,
+ rv = wait_backup(sra, 0, start - stripes * (chunk/512), stripes * (chunk/512),
dests, destfd, destoffsets, 0);
if (rv < 0)
return 0;
dests, destfd, destoffsets,
0, °raded, buf);
validate(afd, destfd[0], destoffsets[0]);
- wait_backup(sra, start, stripes*chunk/512, 0,
+ wait_backup(sra, start, stripes*(chunk/512), 0,
dests, destfd, destoffsets, 0);
- sysfs_set_num(sra, NULL, "suspend_lo", (stripes * chunk/512) * data);
+ sysfs_set_num(sra, NULL, "suspend_lo", (stripes * (chunk/512)) * data);
free(buf);
/* FIXME this should probably be numeric */
sysfs_set_str(sra, NULL, "sync_max", "max");
int degraded = 0;
- posix_memalign((void**)&buf, 4096, disks * chunk);
+ if (posix_memalign((void**)&buf, 4096, disks * chunk))
+ return 0;
sysfs_set_num(sra, NULL, "suspend_lo", 0);
sysfs_set_num(sra, NULL, "suspend_hi", 0);
disks, chunk, level, layout,
dests, destfd, destoffsets,
0, °raded, buf);
- grow_backup(sra, (start + stripes) * chunk/512, stripes,
+ grow_backup(sra, (start + stripes) * (chunk/512), stripes,
fds, offsets,
disks, chunk, level, layout,
dests, destfd, destoffsets,
start += stripes * 2; /* where to read next */
size = sra->component_size / (chunk/512);
while (start < size) {
- if (wait_backup(sra, (start-stripes*2)*chunk/512,
- stripes*chunk/512, 0,
+ if (wait_backup(sra, (start-stripes*2)*(chunk/512),
+ stripes*(chunk/512), 0,
dests, destfd, destoffsets,
part) < 0)
return 0;
- sysfs_set_num(sra, NULL, "suspend_lo", start*chunk/512 * data);
+ sysfs_set_num(sra, NULL, "suspend_lo", start*(chunk/512) * data);
if (start + stripes > size)
tailstripes = (size - start);
- grow_backup(sra, start*chunk/512, tailstripes,
+ grow_backup(sra, start*(chunk/512), tailstripes,
fds, offsets,
disks, chunk, level, layout,
dests, destfd, destoffsets,
part = 1 - part;
validate(afd, destfd[0], destoffsets[0]);
}
- if (wait_backup(sra, (start-stripes*2) * chunk/512, stripes * chunk/512, 0,
+ if (wait_backup(sra, (start-stripes*2) * (chunk/512), stripes * (chunk/512), 0,
dests, destfd, destoffsets,
part) < 0)
return 0;
- sysfs_set_num(sra, NULL, "suspend_lo", ((start-stripes)*chunk/512) * data);
- wait_backup(sra, (start-stripes) * chunk/512, tailstripes * chunk/512, 0,
+ sysfs_set_num(sra, NULL, "suspend_lo", ((start-stripes)*(chunk/512)) * data);
+ wait_backup(sra, (start-stripes) * (chunk/512), tailstripes * (chunk/512), 0,
dests, destfd, destoffsets,
1-part);
- sysfs_set_num(sra, NULL, "suspend_lo", (size*chunk/512) * data);
+ sysfs_set_num(sra, NULL, "suspend_lo", (size*(chunk/512)) * data);
sysfs_set_num(sra, NULL, "sync_speed_min", speed);
free(buf);
return 1;
old_disks = cnt;
for (i=old_disks-(backup_file?1:0); i<cnt; i++) {
struct mdinfo dinfo;
- char buf[4096];
int fd;
int bsbsize;
char *devname, namebuf[20];
continue; /* Wrong uuid */
}
- if (info->array.utime > __le64_to_cpu(bsb.mtime) + 10*60 ||
+ /* array utime and backup-mtime should be updated at much the same time, but it seems that
+ * sometimes they aren't... So allow considerable flexability in matching, and allow
+ * this test to be overridden by an environment variable.
+ */
+ if (info->array.utime > __le64_to_cpu(bsb.mtime) + 2*60*60 ||
info->array.utime < __le64_to_cpu(bsb.mtime) - 10*60) {
- if (verbose)
- fprintf(stderr, Name ": too-old timestamp on backup-metadata on %s\n", devname);
- continue; /* time stamp is too bad */
+ if (check_env("MDADM_GROW_ALLOW_OLD")) {
+ fprintf(stderr, Name ": accepting backup with timestamp %lu "
+ "for array with timestamp %lu\n",
+ (unsigned long)__le64_to_cpu(bsb.mtime),
+ (unsigned long)info->array.utime);
+ } else {
+ if (verbose)
+ fprintf(stderr, Name ": too-old timestamp on "
+ "backup-metadata on %s\n", devname);
+ continue; /* time stamp is too bad */
+ }
}
if (bsb.magic[15] == '1') {
}
/* There should be a duplicate backup superblock 4k before here */
if (lseek64(fd, -4096, 1) < 0 ||
- read(fd, buf, 4096) != 4096)
+ read(fd, &bsb2, sizeof(bsb2)) != sizeof(bsb2))
goto second_fail; /* Cannot find leading superblock */
if (bsb.magic[15] == '1')
bsbsize = offsetof(struct mdp_backup_super, pad1);
else
bsbsize = offsetof(struct mdp_backup_super, pad);
- if (memcmp(buf, &bsb, bsbsize) != 0)
+ if (memcmp(&bsb2, &bsb, bsbsize) != 0)
goto second_fail; /* Cannot find leading superblock */
/* Now need the data offsets for all devices. */
continue;
st->ss->getinfo_super(st, &dinfo);
st->ss->free_super(st);
- offsets[j] = dinfo.data_offset;
+ offsets[j] = dinfo.data_offset * 512;
}
printf(Name ": restoring critical section\n");
int cache;
int done = 0;
+ sra = sysfs_read(-1, devname2devnum(info->sys_name),
+ GET_COMPONENT|GET_DEVS|GET_OFFSET|GET_STATE|
+ GET_CACHE);
+ if (!sra)
+ return 1;
+
err = sysfs_set_str(info, NULL, "array_state", "readonly");
if (err)
return err;
ochunk = info->array.chunk_size;
nchunk = info->new_chunk;
-
- a = ochunk/512 * odata;
- b = nchunk/512 * ndata;
+ a = (ochunk/512) * odata;
+ b = (nchunk/512) * ndata;
/* Find GCD */
while (a != b) {
if (a < b)
a -= b;
}
/* LCM == product / GCD */
- blocks = ochunk/512 * nchunk/512 * odata * ndata / a;
-
- sra = sysfs_read(-1, devname2devnum(info->sys_name),
- GET_COMPONENT|GET_DEVS|GET_OFFSET|GET_STATE|
- GET_CACHE);
-
+ blocks = (ochunk/512) * (nchunk/512) * odata * ndata / a;
if (ndata == odata)
while (blocks * 32 < sra->component_size &&