- newdev = a->container->ss->activate_spare(a, &updates);
- if (newdev) {
- struct mdinfo *d;
- /* Cool, we can add a device or several. */
- newa = duplicate_aa(a);
- /* suspend recovery - maybe not needed */
-
- /* 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;
- if (sysfs_add_disk(&newa->info, d) < 0)
- continue;
- newd = malloc(sizeof(*newd));
- *newd = *d;
- newd->next = newa->info.devs;
- newa->info.devs = newd;
-
- newd->state_fd = sysfs_open(a->devnum,
- newd->sys_name,
- "state");
- newd->prev_state
- = read_dev_state(newd->state_fd);
- newd->curr_state = newd->prev_state;
+ newdev = container->ss->activate_spare(a, &updates);
+ if (!newdev)
+ return;
+
+ newa = duplicate_aa(a);
+ if (!newa)
+ goto out;
+ /* prevent the kernel from activating the disk(s) before we
+ * finish adding them
+ */
+ dprintf("freezing %s\n", a->info.sys_name);
+ 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 = xmalloc(sizeof(*newd));
+ if (sysfs_add_disk(&newa->info, d, 0) < 0) {
+ free(newd);
+ continue;
+ }
+ disk_init_and_add(newd, d, newa);
+ }
+ queue_metadata_update(updates);
+ updates = NULL;
+ while (update_queue_pending || update_queue) {
+ check_update_queue(container);
+ usleep(15*1000);
+ }
+ replace_array(container, a, newa);
+ if (sysfs_set_str(&a->info, NULL,
+ "sync_action", "recover") == 0)
+ newa->prev_action = recover;
+ dprintf("recovery started on %s\n", a->info.sys_name);
+ out:
+ while (newdev) {
+ d = newdev->next;
+ free(newdev);
+ newdev = d;
+ }
+ free_updates(&updates);
+ }
+
+ if (a->check_reshape) {
+ /* mdadm might have added some devices to the array.
+ * We want to disk_init_and_add any such device to a
+ * duplicate_aa and replace a with that.
+ * mdstat doesn't have enough info so we sysfs_read
+ * and look for new stuff.
+ */
+ struct mdinfo *info, *d, *d2, *newd;
+ unsigned long long array_size;
+ struct active_array *newa = NULL;
+ a->check_reshape = 0;
+ info = sysfs_read(-1, mdstat->devnm,
+ GET_DEVS|GET_OFFSET|GET_SIZE|GET_STATE);
+ if (!info)
+ goto out2;
+ for (d = info->devs; d; d = d->next) {
+ if (d->disk.raid_disk < 0)
+ continue;
+ for (d2 = a->info.devs; d2; d2 = d2->next)
+ if (d2->disk.raid_disk ==
+ d->disk.raid_disk)
+ break;
+ if (d2)
+ /* already have this one */
+ continue;
+ if (!newa) {
+ newa = duplicate_aa(a);
+ if (!newa)
+ break;