/*
* 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")) {
} 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);
+ 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);
+ if (size == 0)
+ size = array.size;
}
/* ======= set level =========== */
}
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;
}
}
}
/* 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;
}
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 */
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);
+ rv |= lseek64(destfd[i], destoffsets[i] - 4096, 0);
+ rv = rv ?: write(destfd[i], &bsb, 512);
+ if (destoffsets[i] > 4096) {
+ rv |= lseek64(destfd[i], destoffsets[i]+stripes*chunk*odata, 0);
+ 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);
+ rv |= lseek64(destfd[i], destoffsets[i]-4096, 0);
+ 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,
int rv;
int degraded = 0;
- posix_memalign((void**)&buf, 4096, disks * chunk);
+ 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");
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);
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, 4096) != 4096)
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");