コード例 #1
0
ファイル: spa_config.c プロジェクト: ColinIanKing/zfs
/*
 * Generate the pool's configuration based on the current in-core state.
 *
 * We infer whether to generate a complete config or just one top-level config
 * based on whether vd is the root vdev.
 */
nvlist_t *
spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
{
	nvlist_t *config, *nvroot;
	vdev_t *rvd = spa->spa_root_vdev;
	unsigned long hostid = 0;
	boolean_t locked = B_FALSE;
	uint64_t split_guid;
	char *pool_name;
	int config_gen_flags = 0;

	if (vd == NULL) {
		vd = rvd;
		locked = B_TRUE;
		spa_config_enter(spa, SCL_CONFIG | SCL_STATE, FTAG, RW_READER);
	}

	ASSERT(spa_config_held(spa, SCL_CONFIG | SCL_STATE, RW_READER) ==
	    (SCL_CONFIG | SCL_STATE));

	/*
	 * If txg is -1, report the current value of spa->spa_config_txg.
	 */
	if (txg == -1ULL)
		txg = spa->spa_config_txg;

	/*
	 * Originally, users had to handle spa namespace collisions by either
	 * exporting the already imported pool or by specifying a new name for
	 * the pool with a conflicting name. In the case of root pools from
	 * virtual guests, neither approach to collision resolution is
	 * reasonable. This is addressed by extending the new name syntax with
	 * an option to specify that the new name is temporary. When specified,
	 * ZFS_IMPORT_TEMP_NAME will be set in spa->spa_import_flags to tell us
	 * to use the previous name, which we do below.
	 */
	if (spa->spa_import_flags & ZFS_IMPORT_TEMP_NAME) {
		VERIFY0(nvlist_lookup_string(spa->spa_config,
		    ZPOOL_CONFIG_POOL_NAME, &pool_name));
	} else
		pool_name = spa_name(spa);

	config = fnvlist_alloc();

	fnvlist_add_uint64(config, ZPOOL_CONFIG_VERSION, spa_version(spa));
	fnvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME, pool_name);
	fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE, spa_state(spa));
	fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG, txg);
	fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID, spa_guid(spa));
	fnvlist_add_uint64(config, ZPOOL_CONFIG_ERRATA, spa->spa_errata);
	if (spa->spa_comment != NULL)
		fnvlist_add_string(config, ZPOOL_CONFIG_COMMENT,
		    spa->spa_comment);

#ifdef	_KERNEL
	hostid = zone_get_hostid(NULL);
#else	/* _KERNEL */
	/*
	 * We're emulating the system's hostid in userland, so we can't use
	 * zone_get_hostid().
	 */
	(void) ddi_strtoul(hw_serial, NULL, 10, &hostid);
#endif	/* _KERNEL */
	if (hostid != 0)
		fnvlist_add_uint64(config, ZPOOL_CONFIG_HOSTID, hostid);
	fnvlist_add_string(config, ZPOOL_CONFIG_HOSTNAME, utsname()->nodename);

	if (vd != rvd) {
		fnvlist_add_uint64(config, ZPOOL_CONFIG_TOP_GUID,
		    vd->vdev_top->vdev_guid);
		fnvlist_add_uint64(config, ZPOOL_CONFIG_GUID,
		    vd->vdev_guid);
		if (vd->vdev_isspare)
			fnvlist_add_uint64(config,
			    ZPOOL_CONFIG_IS_SPARE, 1ULL);
		if (vd->vdev_islog)
			fnvlist_add_uint64(config,
			    ZPOOL_CONFIG_IS_LOG, 1ULL);
		vd = vd->vdev_top;		/* label contains top config */
	} else {
		/*
		 * Only add the (potentially large) split information
		 * in the mos config, and not in the vdev labels
		 */
		if (spa->spa_config_splitting != NULL)
			fnvlist_add_nvlist(config, ZPOOL_CONFIG_SPLIT,
			    spa->spa_config_splitting);

		fnvlist_add_boolean(config, ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS);

		config_gen_flags |= VDEV_CONFIG_MOS;
	}

	/*
	 * Add the top-level config.  We even add this on pools which
	 * don't support holes in the namespace.
	 */
	vdev_top_config_generate(spa, config);

	/*
	 * If we're splitting, record the original pool's guid.
	 */
	if (spa->spa_config_splitting != NULL &&
	    nvlist_lookup_uint64(spa->spa_config_splitting,
	    ZPOOL_CONFIG_SPLIT_GUID, &split_guid) == 0) {
		fnvlist_add_uint64(config, ZPOOL_CONFIG_SPLIT_GUID, split_guid);
	}

	nvroot = vdev_config_generate(spa, vd, getstats, config_gen_flags);
	fnvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, nvroot);
	nvlist_free(nvroot);

	/*
	 * Store what's necessary for reading the MOS in the label.
	 */
	fnvlist_add_nvlist(config, ZPOOL_CONFIG_FEATURES_FOR_READ,
	    spa->spa_label_features);

	if (getstats && spa_load_state(spa) == SPA_LOAD_NONE) {
		ddt_histogram_t *ddh;
		ddt_stat_t *dds;
		ddt_object_t *ddo;

		ddh = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP);
		ddt_get_dedup_histogram(spa, ddh);
		fnvlist_add_uint64_array(config,
		    ZPOOL_CONFIG_DDT_HISTOGRAM,
		    (uint64_t *)ddh, sizeof (*ddh) / sizeof (uint64_t));
		kmem_free(ddh, sizeof (ddt_histogram_t));

		ddo = kmem_zalloc(sizeof (ddt_object_t), KM_SLEEP);
		ddt_get_dedup_object_stats(spa, ddo);
		fnvlist_add_uint64_array(config,
		    ZPOOL_CONFIG_DDT_OBJ_STATS,
		    (uint64_t *)ddo, sizeof (*ddo) / sizeof (uint64_t));
		kmem_free(ddo, sizeof (ddt_object_t));

		dds = kmem_zalloc(sizeof (ddt_stat_t), KM_SLEEP);
		ddt_get_dedup_stats(spa, dds);
		fnvlist_add_uint64_array(config,
		    ZPOOL_CONFIG_DDT_STATS,
		    (uint64_t *)dds, sizeof (*dds) / sizeof (uint64_t));
		kmem_free(dds, sizeof (ddt_stat_t));
	}

	if (locked)
		spa_config_exit(spa, SCL_CONFIG | SCL_STATE, FTAG);

	return (config);
}
コード例 #2
0
ファイル: nvlist_to_lua.c プロジェクト: DeHackEd/zfs
static void
run_tests(void)
{
	const char *key = "key";

	/* Note: maximum nvlist key length is 32KB */
	int len = 1024 * 31;
	char *bigstring = malloc(len);
	for (int i = 0; i < len; i++)
		bigstring[i] = 'a' + i % 26;
	bigstring[len - 1] = '\0';

	nvl = fnvlist_alloc();

	fnvlist_add_boolean(nvl, key);
	test("boolean", B_TRUE, B_FALSE);

	fnvlist_add_boolean_value(nvl, key, B_TRUE);
	test("boolean_value", B_FALSE, B_FALSE);

	fnvlist_add_byte(nvl, key, 1);
	test("byte", B_FALSE, B_FALSE);

	fnvlist_add_int8(nvl, key, 1);
	test("int8", B_FALSE, B_FALSE);

	fnvlist_add_uint8(nvl, key, 1);
	test("uint8", B_FALSE, B_FALSE);

	fnvlist_add_int16(nvl, key, 1);
	test("int16", B_FALSE, B_FALSE);

	fnvlist_add_uint16(nvl, key, 1);
	test("uint16", B_FALSE, B_FALSE);

	fnvlist_add_int32(nvl, key, 1);
	test("int32", B_FALSE, B_FALSE);

	fnvlist_add_uint32(nvl, key, 1);
	test("uint32", B_FALSE, B_FALSE);

	fnvlist_add_int64(nvl, key, 1);
	test("int64", B_TRUE, B_TRUE);

	fnvlist_add_uint64(nvl, key, 1);
	test("uint64", B_FALSE, B_FALSE);

	fnvlist_add_string(nvl, key, "1");
	test("string", B_TRUE, B_TRUE);


	{
		nvlist_t *val = fnvlist_alloc();
		fnvlist_add_string(val, "subkey", "subvalue");
		fnvlist_add_nvlist(nvl, key, val);
		fnvlist_free(val);
		test("nvlist", B_TRUE, B_TRUE);
	}
	{
		boolean_t val[2] = { B_FALSE, B_TRUE };
		fnvlist_add_boolean_array(nvl, key, val, 2);
		test("boolean_array", B_FALSE, B_FALSE);
	}
	{
		uchar_t val[2] = { 0, 1 };
		fnvlist_add_byte_array(nvl, key, val, 2);
		test("byte_array", B_FALSE, B_FALSE);
	}
	{
		int8_t val[2] = { 0, 1 };
		fnvlist_add_int8_array(nvl, key, val, 2);
		test("int8_array", B_FALSE, B_FALSE);
	}
	{
		uint8_t val[2] = { 0, 1 };
		fnvlist_add_uint8_array(nvl, key, val, 2);
		test("uint8_array", B_FALSE, B_FALSE);
	}
	{
		int16_t val[2] = { 0, 1 };
		fnvlist_add_int16_array(nvl, key, val, 2);
		test("int16_array", B_FALSE, B_FALSE);
	}
	{
		uint16_t val[2] = { 0, 1 };
		fnvlist_add_uint16_array(nvl, key, val, 2);
		test("uint16_array", B_FALSE, B_FALSE);
	}
	{
		int32_t val[2] = { 0, 1 };
		fnvlist_add_int32_array(nvl, key, val, 2);
		test("int32_array", B_FALSE, B_FALSE);
	}
	{
		uint32_t val[2] = { 0, 1 };
		fnvlist_add_uint32_array(nvl, key, val, 2);
		test("uint32_array", B_FALSE, B_FALSE);
	}
	{
		int64_t val[2] = { 0, 1 };
		fnvlist_add_int64_array(nvl, key, val, 2);
		test("int64_array", B_TRUE, B_FALSE);
	}
	{
		uint64_t val[2] = { 0, 1 };
		fnvlist_add_uint64_array(nvl, key, val, 2);
		test("uint64_array", B_FALSE, B_FALSE);
	}
	{
		char *const val[2] = { "0", "1" };
		fnvlist_add_string_array(nvl, key, val, 2);
		test("string_array", B_TRUE, B_FALSE);
	}
	{
		nvlist_t *val[2];
		val[0] = fnvlist_alloc();
		fnvlist_add_string(val[0], "subkey", "subvalue");
		val[1] = fnvlist_alloc();
		fnvlist_add_string(val[1], "subkey2", "subvalue2");
		fnvlist_add_nvlist_array(nvl, key, val, 2);
		fnvlist_free(val[0]);
		fnvlist_free(val[1]);
		test("nvlist_array", B_FALSE, B_FALSE);
	}
	{
		fnvlist_add_string(nvl, bigstring, "1");
		test("large_key", B_TRUE, B_TRUE);
	}
	{
		fnvlist_add_string(nvl, key, bigstring);
		test("large_value", B_TRUE, B_TRUE);
	}
	{
		for (int i = 0; i < 1024; i++) {
			char buf[32];
			(void) snprintf(buf, sizeof (buf), "key-%u", i);
			fnvlist_add_int64(nvl, buf, i);
		}
		test("many_keys", B_TRUE, B_TRUE);
	}
#ifndef __sparc__
	{
		for (int i = 0; i < 10; i++) {
			nvlist_t *newval = fnvlist_alloc();
			fnvlist_add_nvlist(newval, "key", nvl);
			fnvlist_free(nvl);
			nvl = newval;
		}
		test("deeply_nested_pos", B_TRUE, B_TRUE);
	}
	{
		for (int i = 0; i < 90; i++) {
			nvlist_t *newval = fnvlist_alloc();
			fnvlist_add_nvlist(newval, "key", nvl);
			fnvlist_free(nvl);
			nvl = newval;
		}
		test("deeply_nested_neg", B_FALSE, B_FALSE);
	}
#endif
	free(bigstring);
	fnvlist_free(nvl);
}