diff options
author | Chris Williamson <[email protected]> | 2018-02-08 09:16:23 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2018-02-08 15:28:18 -0800 |
commit | d99a015343425a1c856c900aa8223016400ac2dc (patch) | |
tree | f6ab517b27b650c32127953b74567baa99951d08 /tests/zfs-tests/cmd | |
parent | 8824a7f133e4402f7176115cf8efd535c8cbdab2 (diff) |
OpenZFS 7431 - ZFS Channel Programs
Authored by: Chris Williamson <[email protected]>
Reviewed by: Matthew Ahrens <[email protected]>
Reviewed by: George Wilson <[email protected]>
Reviewed by: John Kennedy <[email protected]>
Reviewed by: Dan Kimmel <[email protected]>
Approved by: Garrett D'Amore <[email protected]>
Ported-by: Don Brady <[email protected]>
Ported-by: John Kennedy <[email protected]>
OpenZFS-issue: https://www.illumos.org/issues/7431
OpenZFS-commit: https://github.com/openzfs/openzfs/commit/dfc11533
Porting Notes:
* The CLI long option arguments for '-t' and '-m' don't parse on linux
* Switched from kmem_alloc to vmem_alloc in zcp_lua_alloc
* Lua implementation is built as its own module (zlua.ko)
* Lua headers consumed directly by zfs code moved to 'include/sys/lua/'
* There is no native setjmp/longjump available in stock Linux kernel.
Brought over implementations from illumos and FreeBSD
* The get_temporary_prop() was adapted due to VFS platform differences
* Use of inline functions in lua parser to reduce stack usage per C call
* Skip some ZFS Test Suite ZCP tests on sparc64 to avoid stack overflow
Diffstat (limited to 'tests/zfs-tests/cmd')
-rw-r--r-- | tests/zfs-tests/cmd/Makefile.am | 1 | ||||
-rw-r--r-- | tests/zfs-tests/cmd/nvlist_to_lua/.gitignore | 1 | ||||
-rw-r--r-- | tests/zfs-tests/cmd/nvlist_to_lua/Makefile.am | 14 | ||||
-rw-r--r-- | tests/zfs-tests/cmd/nvlist_to_lua/nvlist_to_lua.c | 305 |
4 files changed, 321 insertions, 0 deletions
diff --git a/tests/zfs-tests/cmd/Makefile.am b/tests/zfs-tests/cmd/Makefile.am index f55ff8ce2..123a79849 100644 --- a/tests/zfs-tests/cmd/Makefile.am +++ b/tests/zfs-tests/cmd/Makefile.am @@ -14,6 +14,7 @@ SUBDIRS = \ mktree \ mmap_exec \ mmapwrite \ + nvlist_to_lua \ randfree_file \ readmmap \ rename_dir \ diff --git a/tests/zfs-tests/cmd/nvlist_to_lua/.gitignore b/tests/zfs-tests/cmd/nvlist_to_lua/.gitignore new file mode 100644 index 000000000..b31db6454 --- /dev/null +++ b/tests/zfs-tests/cmd/nvlist_to_lua/.gitignore @@ -0,0 +1 @@ +/nvlist_to_lua diff --git a/tests/zfs-tests/cmd/nvlist_to_lua/Makefile.am b/tests/zfs-tests/cmd/nvlist_to_lua/Makefile.am new file mode 100644 index 000000000..f509a97e3 --- /dev/null +++ b/tests/zfs-tests/cmd/nvlist_to_lua/Makefile.am @@ -0,0 +1,14 @@ +include $(top_srcdir)/config/Rules.am + +pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin + +DEFAULT_INCLUDES += \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/lib/libspl/include + +pkgexec_PROGRAMS = nvlist_to_lua + +nvlist_to_lua_SOURCES = nvlist_to_lua.c +nvlist_to_lua_LDADD = \ + $(top_builddir)/lib/libnvpair/libnvpair.la \ + $(top_builddir)/lib/libzfs_core/libzfs_core.la diff --git a/tests/zfs-tests/cmd/nvlist_to_lua/nvlist_to_lua.c b/tests/zfs-tests/cmd/nvlist_to_lua/nvlist_to_lua.c new file mode 100644 index 000000000..b130d667f --- /dev/null +++ b/tests/zfs-tests/cmd/nvlist_to_lua/nvlist_to_lua.c @@ -0,0 +1,305 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2016 by Delphix. All rights reserved. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <libzfs_core.h> +#include <sys/nvpair.h> + +nvlist_t *nvl; +const char *pool; +boolean_t unexpected_failures; + +static boolean_t +nvlist_equal(nvlist_t *nvla, nvlist_t *nvlb) +{ + if (fnvlist_num_pairs(nvla) != fnvlist_num_pairs(nvlb)) + return (B_FALSE); + /* + * The nvlists have the same number of pairs and keys are unique, so + * if every key in A is also in B and assigned to the same value, the + * lists are identical. + */ + for (nvpair_t *pair = nvlist_next_nvpair(nvla, NULL); + pair != NULL; pair = nvlist_next_nvpair(nvla, pair)) { + char *key = nvpair_name(pair); + + if (!nvlist_exists(nvlb, key)) + return (B_FALSE); + + if (nvpair_type(pair) != + nvpair_type(fnvlist_lookup_nvpair(nvlb, key))) + return (B_FALSE); + + switch (nvpair_type(pair)) { + case DATA_TYPE_BOOLEAN_VALUE: + if (fnvpair_value_boolean_value(pair) != + fnvlist_lookup_boolean_value(nvlb, key)) { + return (B_FALSE); + } + break; + case DATA_TYPE_STRING: + if (strcmp(fnvpair_value_string(pair), + fnvlist_lookup_string(nvlb, key))) { + return (B_FALSE); + } + break; + case DATA_TYPE_INT64: + if (fnvpair_value_int64(pair) != + fnvlist_lookup_int64(nvlb, key)) { + return (B_FALSE); + } + break; + case DATA_TYPE_NVLIST: + if (!nvlist_equal(fnvpair_value_nvlist(pair), + fnvlist_lookup_nvlist(nvlb, key))) { + return (B_FALSE); + } + break; + default: + (void) printf("Unexpected type for nvlist_equal\n"); + return (B_FALSE); + } + } + return (B_TRUE); +} + +static void +test(const char *testname, boolean_t expect_success, boolean_t expect_match) +{ + char *progstr = "input = ...; return {output=input}"; + + nvlist_t *outnvl; + + (void) printf("\nrunning test '%s'; input:\n", testname); + dump_nvlist(nvl, 4); + + int err = lzc_channel_program(pool, progstr, + 10 * 1000 * 1000, 10 * 1024 * 1024, nvl, &outnvl); + + (void) printf("lzc_channel_program returned %u\n", err); + dump_nvlist(outnvl, 5); + + if (err == 0 && expect_match) { + /* + * Verify that outnvl is the same as input nvl, if we expect + * them to be. The input and output will never match if the + * input contains an array (since arrays are converted to lua + * tables), so this is only asserted for some test cases. + */ + nvlist_t *real_outnvl = fnvlist_lookup_nvlist(outnvl, "return"); + real_outnvl = fnvlist_lookup_nvlist(real_outnvl, "output"); + if (!nvlist_equal(nvl, real_outnvl)) { + unexpected_failures = B_TRUE; + (void) printf("unexpected input/output mismatch for " + "case: %s\n", testname); + } + } + if (err != 0 && expect_success) { + unexpected_failures = B_TRUE; + (void) printf("unexpected FAIL of case: %s\n", testname); + } + + fnvlist_free(nvl); + nvl = fnvlist_alloc(); +} + +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); +} + +int +main(int argc, const char *argv[]) +{ + (void) libzfs_core_init(); + + if (argc != 2) { + (void) printf("usage: %s <pool>\n", + argv[0]); + exit(2); + } + pool = argv[1]; + + run_tests(); + + libzfs_core_fini(); + return (unexpected_failures); +} |