Exemple #1
0
int unblock_subarray(struct mdinfo *sra, const int unfreeze)
{
	char buf[64];
	int rc = 0;

	if (sra) {
		sprintf(buf, "external:%s\n", sra->text_version);
		buf[9] = '/';
	} else
		buf[9] = '-';

	if (buf[9] == '-' ||
	    sysfs_set_str(sra, NULL, "metadata_version", buf) ||
	    (unfreeze &&
	     sysfs_attribute_available(sra, NULL, "sync_action") &&
	     sysfs_set_str(sra, NULL, "sync_action", "idle")))
		rc = -1;
	return rc;
}
Exemple #2
0
int sysfs_freeze_array(struct mdinfo *sra)
{
    /* Try to freeze resync/rebuild on this array/container.
     * 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_attribute_available(sra, NULL, "sync_action"))
        return 1; /* no sync_action == frozen */
    if (sysfs_get_str(sra, NULL, "sync_action", buf, 20) <= 0)
        return 0;
    if (strcmp(buf, "frozen\n") == 0)
        /* Already frozen */
        return 0;
    if (strcmp(buf, "idle\n") != 0 && strcmp(buf, "recover\n") != 0)
        return -1;
    if (sysfs_set_str(sra, NULL, "sync_action", "frozen") < 0)
        return 0;
    return 1;
}
Exemple #3
0
/**
 * block_monitor - prevent mdmon spare assignment
 * @container - container to block
 * @freeze - flag to additionally freeze sync_action
 *
 * This is used by the reshape code to freeze the container, and the
 * auto-rebuild implementation to atomically move spares.
 * In both cases we need to stop mdmon from assigning spares to replace
 * failed devices as we might have other plans for the spare.
 * For the reshape case we also need to 'freeze' sync_action so that
 * no recovery happens until we have fully prepared for the reshape.
 *
 * We tell mdmon that the array is frozen by marking the 'metadata' name
 * with a leading '-'.  The previously told mdmon "Don't make this array
 * read/write, leave it readonly".  Now it means a more general "Don't
 * reconfigure this array at all".
 * As older versions of mdmon (which might run from initrd) don't understand
 * this, we first check that the running mdmon is new enough.
 */
int block_monitor(char *container, const int freeze)
{
	int devnum = devname2devnum(container);
	struct mdstat_ent *ent, *e, *e2;
	struct mdinfo *sra = NULL;
	char *version = NULL;
	char buf[64];
	int rv = 0;

	if (!mdmon_running(devnum)) {
		/* if mdmon is not active we assume that any instance that is
		 * later started will match the current mdadm version, if this
		 * assumption is violated we may inadvertantly rebuild an array
		 * that was meant for reshape, or start rebuild on a spare that
		 * was to be moved to another container
		 */
		/* pass */;
	} else {
		int ver;

		version = ping_monitor_version(container);
		ver = version ? mdadm_version(version) : -1;
		free(version);
		if (ver < 3002000) {
			fprintf(stderr, Name
				": mdmon instance for %s cannot be disabled\n",
				container);
			return -1;
		}
	}

	ent = mdstat_read(0, 0);
	if (!ent) {
		fprintf(stderr, Name
			": failed to read /proc/mdstat while disabling mdmon\n");
		return -1;
	}

	/* freeze container contents */
	for (e = ent; e; e = e->next) {
		if (!is_container_member(e, container))
			continue;
		sysfs_free(sra);
		sra = sysfs_read(-1, e->devnum, GET_VERSION);
		if (!sra) {
			fprintf(stderr, Name
				": failed to read sysfs for subarray%s\n",
				to_subarray(e, container));
			break;
		}
		/* can't reshape an array that we can't monitor */
		if (sra->text_version[0] == '-')
			break;

		if (freeze && sysfs_freeze_array(sra) < 1)
			break;
		/* flag this array to not be modified by mdmon (close race with
		 * takeover in reshape case and spare reassignment in the
		 * auto-rebuild case)
		 */
		if (block_subarray(sra))
			break;
		ping_monitor(container);

		/* check that we did not race with recovery */
		if ((freeze &&
		     !sysfs_attribute_available(sra, NULL, "sync_action")) ||
		    (freeze &&
		     sysfs_attribute_available(sra, NULL, "sync_action") &&
		     sysfs_get_str(sra, NULL, "sync_action", buf, 20) > 0 &&
		     strcmp(buf, "frozen\n") == 0))
			/* pass */;
		else {
			unblock_subarray(sra, 0);
			break;
		}
		/* Double check against races - there should be no spares
		 * or part-spares
		 */
		sysfs_free(sra);
		sra = sysfs_read(-1, e->devnum, GET_DEVS | GET_STATE);
		if (sra && sra->array.spare_disks > 0) {
			unblock_subarray(sra, freeze);
			break;
		}
	}

	if (e) {
		fprintf(stderr, Name ": failed to freeze subarray%s\n",
			to_subarray(e, container));

		/* thaw the partially frozen container */
		for (e2 = ent; e2 && e2 != e; e2 = e2->next) {
			if (!is_container_member(e2, container))
				continue;
			sysfs_free(sra);
			sra = sysfs_read(-1, e2->devnum, GET_VERSION);
			if (unblock_subarray(sra, freeze))
				fprintf(stderr, Name ": Failed to unfreeze %s\n", e2->dev);
		}

		ping_monitor(container); /* cleared frozen */
		rv = -1;
	}

	sysfs_free(sra);
	free_mdstat(ent);

	return rv;
}