Пример #1
0
/*
 * Checks that the active features in the pool are supported by
 * this software.  Adds each unsupported feature (name -> description) to
 * the supplied nvlist.
 */
boolean_t
spa_features_check(spa_t *spa, boolean_t for_write,
    nvlist_t *unsup_feat, nvlist_t *enabled_feat)
{
	objset_t *os = spa->spa_meta_objset;
	boolean_t supported;
	zap_cursor_t *zc;
	zap_attribute_t *za;
	uint64_t obj = for_write ?
	    spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
	char *buf;

	zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
	za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
	buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);

	supported = B_TRUE;
	for (zap_cursor_init(zc, os, obj);
	    zap_cursor_retrieve(zc, za) == 0;
	    zap_cursor_advance(zc)) {
		ASSERT(za->za_integer_length == sizeof (uint64_t) &&
		    za->za_num_integers == 1);

		if (NULL != enabled_feat) {
			fnvlist_add_uint64(enabled_feat, za->za_name,
			    za->za_first_integer);
		}

		if (za->za_first_integer != 0 &&
		    !zfeature_is_supported(za->za_name)) {
			supported = B_FALSE;

			if (NULL != unsup_feat) {
				char *desc = "";

				if (zap_lookup(os, spa->spa_feat_desc_obj,
				    za->za_name, 1, MAXPATHLEN, buf) == 0)
					desc = buf;

				VERIFY(nvlist_add_string(unsup_feat,
				    za->za_name, desc) == 0);
			}
		}
	}
	zap_cursor_fini(zc);

	kmem_free(buf, MAXPATHLEN);
	kmem_free(za, sizeof (zap_attribute_t));
	kmem_free(zc, sizeof (zap_cursor_t));

	return (supported);
}
Пример #2
0
/*
 * Checks that the features active in the specified object are supported by
 * this software.  Adds each unsupported feature (name -> description) to
 * the supplied nvlist.
 */
boolean_t
feature_is_supported(objset_t *os, uint64_t obj, uint64_t desc_obj,
                     nvlist_t *unsup_feat, nvlist_t *enabled_feat)
{
    boolean_t supported;
    zap_cursor_t zc;
    zap_attribute_t za;

    supported = B_TRUE;
    for (zap_cursor_init(&zc, os, obj);
            zap_cursor_retrieve(&zc, &za) == 0;
            zap_cursor_advance(&zc)) {
        ASSERT(za.za_integer_length == sizeof (uint64_t) &&
               za.za_num_integers == 1);

        if (NULL != enabled_feat) {
            fnvlist_add_uint64(enabled_feat, za.za_name,
                               za.za_first_integer);
        }

        if (za.za_first_integer != 0 &&
                !zfeature_is_supported(za.za_name)) {
            supported = B_FALSE;

            if (NULL != unsup_feat) {
                char *desc = "";
                char buf[MAXPATHLEN];

                if (zap_lookup(os, desc_obj, za.za_name,
                               1, sizeof (buf), buf) == 0)
                    desc = buf;

                VERIFY(nvlist_add_string(unsup_feat, za.za_name,
                                         desc) == 0);
            }
        }
    }
    zap_cursor_fini(&zc);

    return (supported);
}
Пример #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);
}