External reshape (step 2): Freeze container

When growing the number of raid disks the reshape process will promote
container-spares to subarray-spares (later the kernel promotes them to
subarray-members in raid5_start_reshape()).  The automatic spare
promotion that mdmon performs upon seeing a degraded array must be
disabled until the reshape process has been initiated.  Otherwise, mdmon
may start a rebuild before the reshape parameters can be specified.

In the external case we arrange for the monitor to be blocked, and
turn off the safemode delay.
Mdmon is updated to check sync_action is not frozen before initiating
recovery.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
Dan Williams 2010-11-23 16:39:58 +11:00 committed by NeilBrown
parent 7bc7119671
commit 7f2ba464e4
1 changed files with 103 additions and 39 deletions

142
Grow.c
View File

@ -458,29 +458,80 @@ static int child_same_size(int afd, struct mdinfo *sra, unsigned long blocks,
int disks, int chunk, int level, int layout, int data,
int dests, int *destfd, unsigned long long *destoffsets);
static int freeze_array(struct mdinfo *sra)
static int freeze_container(struct supertype *st)
{
/* Try to freeze resync on this array.
* Return -1 if the array is busy,
* return 0 if this kernel doesn't support 'frozen'
* return 1 if it worked.
*/
char buf[20];
if (sysfs_get_str(sra, NULL, "sync_action", buf, 20) <= 0)
return 0;
if (strcmp(buf, "idle\n") != 0 &&
strcmp(buf, "frozen\n") != 0)
return -1;
if (sysfs_set_str(sra, NULL, "sync_action", "frozen") < 0)
return 0;
int container_dev = (st->container_dev != NoMdDev
? st->container_dev : st->devnum);
char *container = devnum2devname(container_dev);
if (!container) {
fprintf(stderr, Name
": could not determine container name, freeze aborted\n");
return -2;
}
if (block_monitor(container, 1)) {
fprintf(stderr, Name ": failed to freeze container\n");
return -2;
}
return 1;
}
static void unfreeze_array(struct mdinfo *sra, int frozen)
static void unfreeze_container(struct supertype *st)
{
int container_dev = (st->container_dev != NoMdDev
? st->container_dev : st->devnum);
char *container = devnum2devname(container_dev);
if (!container) {
fprintf(stderr, Name
": could not determine container name, unfreeze aborted\n");
return;
}
unblock_monitor(container, 1);
}
static int freeze(struct supertype *st)
{
/* Try to freeze resync/rebuild on this array/container.
* Return -1 if the array is busy,
* return -2 container cannot be frozen,
* return 0 if this kernel doesn't support 'frozen'
* return 1 if it worked.
*/
if (st->ss->external)
return freeze_container(st);
else {
struct mdinfo *sra = sysfs_read(-1, st->devnum, GET_VERSION);
int err;
if (!sra)
return -1;
err = sysfs_freeze_array(sra);
sysfs_free(sra);
return err;
}
}
static void unfreeze(struct supertype *st, int frozen)
{
/* If 'frozen' is 1, unfreeze the array */
if (frozen > 0)
sysfs_set_str(sra, NULL, "sync_action", "idle");
if (frozen <= 0)
return;
if (st->ss->external)
return unfreeze_container(st);
else {
struct mdinfo *sra = sysfs_read(-1, st->devnum, GET_VERSION);
if (sra)
sysfs_set_str(sra, NULL, "sync_action", "idle");
else
fprintf(stderr, Name ": failed to unfreeze array\n");
sysfs_free(sra);
}
}
static void wait_reshape(struct mdinfo *sra)
@ -670,38 +721,40 @@ static void revert_container_raid_disks(struct supertype *st, int fd, char *cont
return;
}
if (st->ss->load_container(st, fd, NULL)) {
fprintf(stderr, Name
": failed read metadata while aborting reshape\n");
return ;
}
for (e = ent; e; e = e->next) {
int level_fixed = 0, disks_fixed = 0;
struct mdinfo *sub, prev;
struct mdinfo *sub, *prev;
char *subarray;
if (!is_container_member(e, container))
continue;
st->ss->free_super(st);
sprintf(st->subarray, "%s", to_subarray(e, container));
if (st->ss->load_super(st, fd, NULL)) {
fprintf(stderr, Name
": failed read metadata while aborting reshape\n");
continue;
}
st->ss->getinfo_super(st, &prev);
subarray = to_subarray(e, container);
prev = st->ss->container_content(st, subarray);
/* changing level might change raid_disks so we do it
* first and then check if raid_disks still needs fixing
*/
if (map_name(pers, e->level) != prev.array.level) {
if (map_name(pers, e->level) != prev->array.level) {
sub = sysfs_read(-1, e->devnum, GET_VERSION);
if (sub &&
!sysfs_set_num(sub, NULL, "level", prev.array.level))
!sysfs_set_num(sub, NULL, "level", prev->array.level))
level_fixed = 1;
sysfs_free(sub);
} else
level_fixed = 1;
sub = sysfs_read(-1, e->devnum, GET_DISKS);
if (sub && sub->array.raid_disks != prev.array.raid_disks) {
if (sub && sub->array.raid_disks != prev->array.raid_disks) {
if (!subarray_set_num(container, sub, "raid_disks",
prev.array.raid_disks))
prev->array.raid_disks))
disks_fixed = 1;
} else if (sub)
disks_fixed = 1;
@ -710,9 +763,11 @@ static void revert_container_raid_disks(struct supertype *st, int fd, char *cont
if (!disks_fixed || !level_fixed)
fprintf(stderr, Name
": failed to restore %s to a %d-disk %s array\n",
e->dev, prev.array.raid_disks,
map_num(pers, prev.array.level));
e->dev, prev->array.raid_disks,
map_num(pers, prev->array.level));
free(prev);
}
st->ss->free_super(st);
free_mdstat(ent);
}
@ -801,6 +856,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
*/
if (st->ss->external) {
int container_dev;
int rv;
if (subarray) {
container_dev = st->container_dev;
@ -820,18 +876,25 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
if (cfd < 0) {
fprintf(stderr, Name ": Unable to open container for %s\n",
devname);
free(subarray);
return 1;
}
container = devnum2devname(st->devnum);
if (!container) {
fprintf(stderr, Name ": Could not determine container name\n");
free(subarray);
return 1;
}
if (st->ss->load_super(st, cfd, NULL)) {
if (subarray)
rv = st->ss->load_container(st, cfd, NULL);
else
rv = st->ss->load_super(st, cfd, NULL);
if (rv) {
fprintf(stderr, Name ": Cannot read superblock for %s\n",
devname);
free(subarray);
return 1;
}
@ -841,23 +904,25 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
sra = sysfs_read(fd, 0, GET_LEVEL);
if (sra) {
if (st->ss->external && st->subarray[0] == 0) {
if (st->ss->external && subarray == NULL) {
array.level = LEVEL_CONTAINER;
sra->array.level = LEVEL_CONTAINER;
}
frozen = freeze_array(sra);
} else {
fprintf(stderr, Name ": failed to read sysfs parameters for %s\n",
devname);
return 1;
}
if (frozen < 0) {
frozen = freeze(st);
if (frozen < -1) {
/* freeze() already spewed the reason */
return 1;
} else 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)) {
long long orig_size = array.size;
@ -1642,8 +1707,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
if (c && sysfs_set_str(sra, NULL, "level", c) == 0)
fprintf(stderr, Name ": aborting level change\n");
}
if (sra)
unfreeze_array(sra, frozen);
unfreeze(st, frozen);
return rv;
}