close(d->state_fd);
}
- close(aa->action_fd);
- close(aa->info.state_fd);
- close(aa->resync_start_fd);
- close(aa->metadata_fd);
- close(aa->sync_completed_fd);
+ if (aa->action_fd >= 0)
+ close(aa->action_fd);
+ if (aa->info.state_fd >= 0)
+ close(aa->info.state_fd);
+ if (aa->resync_start_fd >= 0)
+ close(aa->resync_start_fd);
+ if (aa->metadata_fd >= 0)
+ close(aa->metadata_fd);
+ if (aa->sync_completed_fd >= 0)
+ close(aa->sync_completed_fd);
}
static void free_aa(struct active_array *aa)
static struct active_array *duplicate_aa(struct active_array *aa)
{
- struct active_array *newa = malloc(sizeof(*newa));
+ struct active_array *newa = xmalloc(sizeof(*newa));
struct mdinfo **dp1, **dp2;
*newa = *aa;
if ((*dp1)->state_fd < 0)
continue;
- d = malloc(sizeof(*d));
+ d = xmalloc(sizeof(*d));
*d = **dp1;
*dp2 = d;
dp2 = & d->next;
.raid_disk = -1,
.state = 0,
};
- /* nothing to do if super type handler does not support
- * remove disk primitive
- */
- if (!st->ss->remove_from_super)
- return;
dprintf("%s: remove %d:%d from container\n",
__func__, sd->disk.major, sd->disk.minor);
st->update_tail = &update;
st->ss->remove_from_super(st, &dk);
+ /* FIXME this write_init_super shouldn't be here.
+ * We have it after add_to_super to write to new device,
+ * but with 'remove' we don't ant to write to that device!
+ */
st->ss->write_init_super(st);
queue_metadata_update(update);
st->update_tail = NULL;
di->disk.minor == cd->disk.minor)
break;
if (!cd) {
- struct mdinfo *newd = malloc(sizeof(*newd));
+ struct mdinfo *newd = xmalloc(sizeof(*newd));
- if (!newd) {
- container->devcnt = -1;
- continue;
- }
*newd = *di;
add_disk_to_container(container, newd);
}
*disk = *clone;
disk->recovery_fd = sysfs_open(aa->devnum, disk->sys_name, "recovery_start");
+ if (disk->recovery_fd < 0)
+ return -1;
disk->state_fd = sysfs_open(aa->devnum, disk->sys_name, "state");
+ if (disk->state_fd < 0) {
+ close(disk->recovery_fd);
+ return -1;
+ }
disk->prev_state = read_dev_state(disk->state_fd);
disk->curr_state = disk->prev_state;
disk->next = aa->info.devs;
*/
char buf[64];
int frozen;
+ struct supertype *container = a->container;
+
+ if (container == NULL)
+ /* Raced with something */
+ return;
// FIXME
a->info.array.raid_disks = mdstat->raid_disks;
if (mdstat->level) {
int level = map_name(pers, mdstat->level);
- if (a->info.array.level != level && level >= 0) {
+ if (level == 0 || level == LEVEL_LINEAR) {
+ a->to_remove = 1;
+ wakeup_monitor();
+ return;
+ }
+ else if (a->info.array.level != level && level > 0) {
struct active_array *newa = duplicate_aa(a);
if (newa) {
newa->info.array.level = level;
- replace_array(a->container, a, newa);
+ replace_array(container, a, newa);
a = newa;
}
}
}
- if (a->check_degraded && !frozen) {
+ /* we are after monitor kick,
+ * so container field can be cleared - check it again
+ */
+ if (a->container == NULL)
+ return;
+
+ /* We don't check the array while any update is pending, as it
+ * might container a change (such as a spare assignment) which
+ * could affect our decisions.
+ */
+ if (a->check_degraded && !frozen &&
+ update_queue == NULL && update_queue_pending == NULL) {
struct metadata_update *updates = NULL;
struct mdinfo *newdev = NULL;
struct active_array *newa;
/* The array may not be degraded, this is just a good time
* to check.
*/
- newdev = a->container->ss->activate_spare(a, &updates);
+ newdev = container->ss->activate_spare(a, &updates);
if (!newdev)
return;
newa = duplicate_aa(a);
if (!newa)
goto out;
- /* Cool, we can add a device or several. */
+ /* prevent the kernel from activating the disk(s) before we
+ * finish adding them
+ */
+ sysfs_set_str(&a->info, NULL, "sync_action", "frozen");
/* Add device to array and set offset/size/slot.
* and open files for each newdev */
for (d = newdev; d ; d = d->next) {
struct mdinfo *newd;
- newd = malloc(sizeof(*newd));
- if (!newd)
- continue;
+ newd = xmalloc(sizeof(*newd));
if (sysfs_add_disk(&newa->info, d, 0) < 0) {
free(newd);
continue;
}
queue_metadata_update(updates);
updates = NULL;
- replace_array(a->container, a, newa);
+ replace_array(container, a, newa);
sysfs_set_str(&a->info, NULL, "sync_action", "recover");
out:
while (newdev) {
if (!newa)
break;
}
- newd = malloc(sizeof(*newd));
- if (!newd)
- continue;
+ newd = xmalloc(sizeof(*newd));
disk_init_and_add(newd, d, newa);
}
if (sysfs_get_ll(info, NULL, "array_size", &array_size) == 0
out2:
sysfs_free(info);
if (newa)
- replace_array(a->container, a, newa);
+ replace_array(container, a, newa);
}
}
char buf[40];
/* check if array is ready to be monitored */
- if (!mdstat->active)
+ if (!mdstat->active || !mdstat->level)
+ return;
+ if (strcmp(mdstat->level, "raid0") == 0 ||
+ strcmp(mdstat->level, "linear") == 0)
return;
mdi = sysfs_read(-1, mdstat->devnum,
GET_LEVEL|GET_CHUNK|GET_DISKS|GET_COMPONENT|
GET_DEGRADED|GET_DEVS|GET_OFFSET|GET_SIZE|GET_STATE);
- new = malloc(sizeof(*new));
- if (!new || !mdi) {
- if (mdi)
- sysfs_free(mdi);
- if (new)
- free(new);
+ if (!mdi)
return;
- }
- memset(new, 0, sizeof(*new));
+ new = xcalloc(1, sizeof(*new));
new->devnum = mdstat->devnum;
strcpy(new->info.sys_name, devnum2devname(new->devnum));
new->info.component_size = mdi->component_size;
for (i = 0; i < new->info.array.raid_disks; i++) {
- struct mdinfo *newd = malloc(sizeof(*newd));
+ struct mdinfo *newd = xmalloc(sizeof(*newd));
for (di = mdi->devs; di; di = di->next)
if (i == di->disk.raid_disk)
/* Looks like a member of this container */
for (a = container->arrays; a; a = a->next) {
if (mdstat->devnum == a->devnum) {
- if (a->container)
+ if (a->container && a->to_remove == 0)
manage_member(mdstat, a);
break;
}
manage(mdstat, container);
free_mdstat(mdstat);
} else if (!sigterm) {
- mu = malloc(sizeof(*mu));
+ mu = xmalloc(sizeof(*mu));
mu->len = msg->len;
mu->buf = msg->buf;
msg->buf = NULL;