/*
* mdadm - manage Linux "md" devices aka RAID arrays.
*
- * Copyright (C) 2001-2009 Neil Brown <neilb@suse.de>
+ * Copyright (C) 2001-2012 Neil Brown <neilb@suse.de>
*
*
* This program is free software; you can redistribute it and/or modify
st = super_by_fd(fd, &subarray);
if (!st) {
- pr_err("cannot handle arrays with superblock version %d\n", info.array.major_version);
+ pr_err("cannot handle arrays with superblock version %d\n",
+ info.array.major_version);
return 1;
}
free(st);
return 1;
}
- /* now check out all the devices and make sure we can read the superblock */
+ /* now check out all the devices and make sure we can read the
+ * superblock */
for (d=0 ; d < info.array.raid_disks ; d++) {
mdu_disk_info_t disk;
char *dv;
)
st->ss->write_bitmap(st, fd2);
else {
- pr_err("failed "
- "to create internal bitmap - chunksize problem.\n");
+ pr_err("failed to create internal bitmap"
+ " - chunksize problem.\n");
close(fd2);
return 1;
}
int max_devs = st->max_devs;
/* try to load a superblock */
- for (d=0; d<max_devs; d++) {
+ for (d = 0; d < max_devs; d++) {
mdu_disk_info_t disk;
char *dv;
int fd2;
(disk.state & (1<<MD_DISK_REMOVED)))
continue;
dv = map_dev(disk.major, disk.minor, 1);
- if (!dv) continue;
+ if (!dv)
+ continue;
fd2 = dev_open(dv, O_RDONLY);
if (fd2 >= 0) {
if (st->ss->load_super(st, fd2, NULL) == 0) {
{
int i;
int csum = 0;
- for (i=0; i<len; i++)
+ for (i = 0; i < len; i++)
csum = (csum<<3) + buf[0];
return __cpu_to_le32(csum);
}
close(fd);
}
-static int reshape_super(struct supertype *st, long long size, int level,
- int layout, int chunksize, int raid_disks,
+static int reshape_super(struct supertype *st, unsigned long long size,
+ int level, int layout, int chunksize, int raid_disks,
int delta_disks, char *backup_file, char *dev,
int direction, int verbose)
{
return 1;
}
+unsigned long GCD(unsigned long a, unsigned long b)
+{
+ while (a != b) {
+ if (a < b)
+ b -= a;
+ if (b < a)
+ a -= b;
+ }
+ return a;
+}
+
unsigned long compute_backup_blocks(int nchunk, int ochunk,
unsigned int ndata, unsigned int odata)
{
a = (ochunk/512) * odata;
b = (nchunk/512) * ndata;
/* Find GCD */
- while (a != b) {
- if (a < b)
- b -= a;
- if (b < a)
- a -= b;
- }
+ a = GCD(a, b);
/* LCM == product / GCD */
blocks = (ochunk/512) * (nchunk/512) * odata * ndata / a;
switch (re->level) {
case 4:
- re->after.layout = 0 ; break;
+ re->after.layout = 0;
+ break;
case 5:
- re->after.layout = ALGORITHM_PARITY_N; break;
+ re->after.layout = ALGORITHM_PARITY_N;
+ break;
}
break;
switch (re->level) {
case 4:
- re->after.layout = 0 ; break;
+ re->after.layout = 0;
+ break;
case 5:
- re->after.layout = ALGORITHM_PARITY_N; break;
+ re->after.layout = ALGORITHM_PARITY_N;
+ break;
}
break;
+ info->delta_disks
- delta_parity);
switch (re->level) {
- case 6: re->parity = 2; break;
+ case 6: re->parity = 2;
+ break;
case 4:
- case 5: re->parity = 1; break;
- default: re->parity = 0; break;
+ case 5: re->parity = 1;
+ break;
+ default: re->parity = 0;
+ break;
}
/* So we have a restripe operation, we need to calculate the number
* of blocks per reshape operation.
int Grow_reshape(char *devname, int fd,
struct mddev_dev *devlist,
+ unsigned long long data_offset,
struct context *c, struct shape *s)
{
/* Make some changes in the shape of an array.
struct mdinfo info;
struct mdinfo *sra;
+ if (data_offset != INVALID_SECTORS) {
+ fprintf(stderr, Name ": --grow --data-offset not yet supported\n");
+ return 1;
+ }
+
if (ioctl(fd, GET_ARRAY_INFO, &array) < 0) {
pr_err("%s is not an active md array - aborting\n",
devname);
}
/* ========= set size =============== */
- if (s->size > 0 && (s->size == MAX_DISKS || s->size != (unsigned)array.size)) {
+ if (s->size > 0 && (s->size == MAX_SIZE || s->size != (unsigned)array.size)) {
unsigned long long orig_size = get_component_size(fd)/2;
unsigned long long min_csize;
struct mdinfo *mdi;
/* Impose these changes on a single array. First
* check that the metadata is OK with the change. */
- if (reshape_super(st, -1, info.new_level,
+ if (reshape_super(st, 0, info.new_level,
info.new_layout, info.new_chunk,
info.array.raid_disks, info.delta_disks,
c->backup_file, devname, APPLY_METADATA_CHANGES,
char *msg;
int orig_level = UnSet;
int disks, odisks;
+ int delayed;
struct mdu_array_info_s array;
char *c;
break;
}
+ /* If another array on the same devices is busy, the
+ * reshape will wait for them. This would mean that
+ * the first section that we suspend will stay suspended
+ * for a long time. So check on that possibility
+ * by looking for "DELAYED" in /proc/mdstat, and if found,
+ * wait a while
+ */
+ do {
+ struct mdstat_ent *mds, *m;
+ delayed = 0;
+ mds = mdstat_read(0, 0);
+ for (m = mds; m; m = mds->next)
+ if (m->devnum == devname2devnum(sra->sys_name)) {
+ if (m->resync &&
+ m->percent == RESYNC_DELAYED)
+ delayed = 1;
+ if (m->resync == 0)
+ /* Haven't started the reshape thread
+ * yet, wait a bit
+ */
+ delayed = 2;
+ break;
+ }
+ free_mdstat(mds);
+ if (delayed == 1 && get_linux_version() < 3007000) {
+ pr_err("Reshape is delayed, but cannot wait carefully with this kernel.\n"
+ " You might experience problems until other reshapes complete.\n");
+ delayed = 0;
+ }
+ if (delayed)
+ sleep(30 - (delayed-1) * 25);
+ } while (delayed);
+
close(fd);
if (check_env("MDADM_GROW_VERIFY"))
fd = open(devname, O_RDONLY | O_DIRECT);
int last_devnum = -1;
/* component_size is not meaningful for a container,
- * so pass '-1' meaning 'no change'
+ * so pass '0' meaning 'no change'
*/
if (!restart &&
- reshape_super(st, -1, info->new_level,
+ reshape_super(st, 0, info->new_level,
info->new_layout, info->new_chunk,
info->array.raid_disks, info->delta_disks,
backup_file, devname, APPLY_METADATA_CHANGES,
(unsigned long)__le64_to_cpu(bsb.mtime),
(unsigned long)info->array.utime);
} else {
- if (verbose)
- pr_err("too-old timestamp on "
- "backup-metadata on %s\n", devname);
+ pr_err("too-old timestamp on backup-metadata on %s\n", devname);
+ pr_err("If you think it is should be safe, try 'export MDADM_GROW_ALLOW_OLD=1'\n");
continue; /* time stamp is too bad */
}
}
}
}
for (j=0; j<info->array.raid_disks; j++) {
- if (fdlist[j] < 0) continue;
+ if (fdlist[j] < 0)
+ continue;
if (st->ss->load_super(st, fdlist[j], NULL))
continue;
st->ss->getinfo_super(st, &dinfo, NULL);