Пример #1
0
static void
zfeature_register(spa_feature_t fid, const char *guid, const char *name,
    const char *desc, boolean_t readonly, boolean_t mos,
    boolean_t activate_on_enable, const spa_feature_t *deps)
{
	zfeature_info_t *feature = &spa_feature_table[fid];
	static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };

	ASSERT(name != NULL);
	ASSERT(desc != NULL);
	ASSERT(!readonly || !mos);
	ASSERT3U(fid, <, SPA_FEATURES);
	ASSERT(zfeature_is_valid_guid(guid));

	if (deps == NULL)
		deps = nodeps;

	feature->fi_feature = fid;
	feature->fi_guid = guid;
	feature->fi_uname = name;
	feature->fi_desc = desc;
	feature->fi_can_readonly = readonly;
	feature->fi_mos = mos;
	feature->fi_activate_on_enable = activate_on_enable;
	feature->fi_depends = deps;
}
Пример #2
0
static void
zfeature_register(spa_feature_t fid, const char *guid, const char *name,
    const char *desc, zfeature_flags_t flags, const spa_feature_t *deps)
{
	zfeature_info_t *feature = &spa_feature_table[fid];
	static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };

	ASSERT(name != NULL);
	ASSERT(desc != NULL);
	ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 ||
	    (flags & ZFEATURE_FLAG_MOS) == 0);
	ASSERT3U(fid, <, SPA_FEATURES);
	ASSERT(zfeature_is_valid_guid(guid));

	if (deps == NULL)
		deps = nodeps;

	VERIFY(((flags & ZFEATURE_FLAG_PER_DATASET) == 0) ||
	    (deps_contains_feature(deps, SPA_FEATURE_EXTENSIBLE_DATASET)));

	feature->fi_feature = fid;
	feature->fi_guid = guid;
	feature->fi_uname = name;
	feature->fi_desc = desc;
	feature->fi_flags = flags;
	feature->fi_depends = deps;
}
Пример #3
0
static void
zhack_do_feature_ref(int argc, char **argv)
{
	char c;
	char *target;
	boolean_t decr = B_FALSE;
	spa_t *spa;
	objset_t *mos;
	zfeature_info_t feature;
	spa_feature_t nodeps[] = { SPA_FEATURE_NONE };

	/*
	 * fi_desc does not matter here because it was written to disk
	 * when the feature was enabled, but we need to properly set the
	 * feature for read or write based on the information we read off
	 * disk later.
	 */
	feature.fi_uname = "zhack";
	feature.fi_flags = 0;
	feature.fi_desc = NULL;
	feature.fi_depends = nodeps;
	feature.fi_feature = SPA_FEATURE_NONE;

	optind = 1;
	while ((c = getopt(argc, argv, "md")) != -1) {
		switch (c) {
		case 'm':
			feature.fi_flags |= ZFEATURE_FLAG_MOS;
			break;
		case 'd':
			decr = B_TRUE;
			break;
		default:
			usage();
			break;
		}
	}
	argc -= optind;
	argv += optind;

	if (argc < 2) {
		(void) fprintf(stderr, "error: missing feature or pool name\n");
		usage();
	}
	target = argv[0];
	feature.fi_guid = argv[1];

	if (!zfeature_is_valid_guid(feature.fi_guid))
		fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);

	zhack_spa_open(target, B_FALSE, FTAG, &spa);
	mos = spa->spa_meta_objset;

	if (zfeature_is_supported(feature.fi_guid)) {
		fatal(spa, FTAG,
		    "'%s' is a real feature, will not change refcount");
	}

	if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
	    feature.fi_guid)) {
		feature.fi_flags &= ~ZFEATURE_FLAG_READONLY_COMPAT;
	} else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
	    feature.fi_guid)) {
		feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
	} else {
		fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
	}

	if (decr) {
		uint64_t count;
		if (feature_get_refcount_from_disk(spa, &feature,
		    &count) == 0 && count == 0) {
			fatal(spa, FTAG, "feature refcount already 0: %s",
			    feature.fi_guid);
		}
	}

	VERIFY0(dsl_sync_task(spa_name(spa), NULL,
	    decr ? feature_decr_sync : feature_incr_sync, &feature,
	    5, ZFS_SPACE_CHECK_NORMAL));

	spa_close(spa, FTAG);
}
Пример #4
0
static void
zhack_do_feature_enable(int argc, char **argv)
{
	char c;
	char *desc, *target;
	spa_t *spa;
	objset_t *mos;
	zfeature_info_t feature;
	spa_feature_t nodeps[] = { SPA_FEATURE_NONE };

	/*
	 * Features are not added to the pool's label until their refcounts
	 * are incremented, so fi_mos can just be left as false for now.
	 */
	desc = NULL;
	feature.fi_uname = "zhack";
	feature.fi_flags = 0;
	feature.fi_depends = nodeps;
	feature.fi_feature = SPA_FEATURE_NONE;

	optind = 1;
	while ((c = getopt(argc, argv, "rmd:")) != -1) {
		switch (c) {
		case 'r':
			feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
			break;
		case 'd':
			desc = strdup(optarg);
			break;
		default:
			usage();
			break;
		}
	}

	if (desc == NULL)
		desc = strdup("zhack injected");
	feature.fi_desc = desc;

	argc -= optind;
	argv += optind;

	if (argc < 2) {
		(void) fprintf(stderr, "error: missing feature or pool name\n");
		usage();
	}
	target = argv[0];
	feature.fi_guid = argv[1];

	if (!zfeature_is_valid_guid(feature.fi_guid))
		fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);

	zhack_spa_open(target, B_FALSE, FTAG, &spa);
	mos = spa->spa_meta_objset;

	if (zfeature_is_supported(feature.fi_guid))
		fatal(spa, FTAG, "'%s' is a real feature, will not enable");
	if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
		fatal(spa, FTAG, "feature already enabled: %s",
		    feature.fi_guid);

	VERIFY0(dsl_sync_task(spa_name(spa), NULL,
	    zhack_feature_enable_sync, &feature, 5, ZFS_SPACE_CHECK_NORMAL));

	spa_close(spa, FTAG);

	free(desc);
}
Пример #5
0
static int
feature_do_action(objset_t *os, uint64_t read_obj, uint64_t write_obj,
                  uint64_t desc_obj, zfeature_info_t *feature, feature_action_t action,
                  dmu_tx_t *tx)
{
    int error;
    uint64_t refcount;
    uint64_t zapobj = feature->fi_can_readonly ? write_obj : read_obj;

    ASSERT(0 != zapobj);
    ASSERT(zfeature_is_valid_guid(feature->fi_guid));

    error = zap_lookup(os, zapobj, feature->fi_guid,
                       sizeof (uint64_t), 1, &refcount);

    /*
     * If we can't ascertain the status of the specified feature, an I/O
     * error occurred.
     */
    if (error != 0 && error != ENOENT)
        return (error);

    switch (action) {
    case FEATURE_ACTION_ENABLE:
        /*
         * If the feature is already enabled, ignore the request.
         */
        if (error == 0)
            return (0);
        refcount = 0;
        break;
    case FEATURE_ACTION_INCR:
        if (error == ENOENT)
            return (ENOTSUP);
        if (refcount == UINT64_MAX)
            return (EOVERFLOW);
        refcount++;
        break;
    case FEATURE_ACTION_DECR:
        if (error == ENOENT)
            return (ENOTSUP);
        if (refcount == 0)
            return (EOVERFLOW);
        refcount--;
        break;
    default:
        ASSERT(0);
        break;
    }

    if (action == FEATURE_ACTION_ENABLE) {
        int i;

        for (i = 0; feature->fi_depends[i] != NULL; i++) {
            zfeature_info_t *dep = feature->fi_depends[i];

            error = feature_do_action(os, read_obj, write_obj,
                                      desc_obj, dep, FEATURE_ACTION_ENABLE, tx);
            if (error != 0)
                return (error);
        }
    }

    error = zap_update(os, zapobj, feature->fi_guid,
                       sizeof (uint64_t), 1, &refcount, tx);
    if (error != 0)
        return (error);

    if (action == FEATURE_ACTION_ENABLE) {
        error = zap_update(os, desc_obj,
                           feature->fi_guid, 1, strlen(feature->fi_desc) + 1,
                           feature->fi_desc, tx);
        if (error != 0)
            return (error);
    }

    if (action == FEATURE_ACTION_INCR && refcount == 1 && feature->fi_mos) {
        spa_activate_mos_feature(dmu_objset_spa(os), feature->fi_guid);
    }

    if (action == FEATURE_ACTION_DECR && refcount == 0) {
        spa_deactivate_mos_feature(dmu_objset_spa(os),
                                   feature->fi_guid);
    }

    return (0);
}
Пример #6
0
static void
zhack_do_feature_ref(int argc, char **argv)
{
	char c;
	char *target;
	boolean_t decr = B_FALSE;
	spa_t *spa;
	objset_t *mos;
	zfeature_info_t feature;
	zfeature_info_t *nodeps[] = { NULL };

	/*
	 * fi_desc does not matter here because it was written to disk
	 * when the feature was enabled, but we need to properly set the
	 * feature for read or write based on the information we read off
	 * disk later.
	 */
	feature.fi_uname = "zhack";
	feature.fi_mos = B_FALSE;
	feature.fi_desc = NULL;
	feature.fi_depends = nodeps;

	optind = 1;
	while ((c = getopt(argc, argv, "md")) != -1) {
		switch (c) {
		case 'm':
			feature.fi_mos = B_TRUE;
			break;
		case 'd':
			decr = B_TRUE;
			break;
		default:
			usage();
			break;
		}
	}
	argc -= optind;
	argv += optind;

	if (argc < 2) {
		(void) fprintf(stderr, "error: missing feature or pool name\n");
		usage();
	}
	target = argv[0];
	feature.fi_guid = argv[1];

	if (!zfeature_is_valid_guid(feature.fi_guid))
		fatal("invalid feature guid: %s", feature.fi_guid);

	zhack_spa_open(target, B_FALSE, FTAG, &spa);
	mos = spa->spa_meta_objset;

	if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
		fatal("'%s' is a real feature, will not change refcount");

	if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
	    feature.fi_guid)) {
		feature.fi_can_readonly = B_FALSE;
	} else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
	    feature.fi_guid)) {
		feature.fi_can_readonly = B_TRUE;
	} else {
		fatal("feature is not enabled: %s", feature.fi_guid);
	}

	if (decr && !spa_feature_is_active(spa, &feature))
		fatal("feature refcount already 0: %s", feature.fi_guid);

	VERIFY0(dsl_sync_task(spa_name(spa), NULL,
	    decr ? feature_decr_sync : feature_incr_sync, &feature, 5));

	spa_close(spa, FTAG);
}