--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+
+#define CONFIG_DEBUG_MAPLE_TREE
+#define CONFIG_MAPLE_SEARCH
+#include "test.h"
+
+#define dump_stack() assert(0)
+
+#include "../shared/linux/maple_tree.h"
+#include "../../../include/linux/maple_tree.h"
+
+static int count;
+
+struct data {
+ const uint8_t *data;
+ size_t size;
+ size_t position;
+};
+
+static unsigned long get_ul(struct data *info)
+{
+ uint8_t tmp;
+ unsigned long ret = 0;
+ int i = 8;
+
+ while (i--) {
+ if (info->position >= info->size)
+ info->position = 0;
+
+ tmp = info->data[info->position++];
+ ret += tmp << i;
+ }
+ return ret * count;
+}
+
+static uint8_t get_uint(struct data *info)
+{
+ if (info->position >= info->size)
+ info->position = 0;
+
+ return info->data[info->position++];
+}
+
+#define v(x) (xa_mk_value(x & LONG_MAX))
+//#define trace(...) pr_info(__VA_ARGS__)
+#define trace(...) printv(1, __VA_ARGS__)
+#define TREE_FLAGS MT_FLAGS_ALLOC_RANGE
+
+DEFINE_MTREE(tree);
+
+static void maple_tree_tests(struct data *info)
+{
+ unsigned long l1, l2;
+ void *e, *rl;
+ int r;
+
+ while (count--) {
+ if (test_verbose) {
+ pr_info("------------------------------------------------\n");
+ mt_dump(&tree, mt_dump_hex);
+ }
+
+ l1 = get_ul(info);
+ l2 = l1 + get_ul(info);
+ e = v(l1);
+
+ trace("execute with %lx %lx (%p)\n", l1, l2, e);
+ switch (get_uint(info) % 8) {
+ case 3:
+ trace("\tmtree_load(mt, 0x%lx);", l1);
+ rl = mtree_load(&tree, l1);
+ trace("// -> %p\n", rl);
+ break;
+#if 1
+ case 1:
+ trace("\tmtree_insert(mt, 0x%lx, (void *)%p, GFP_KERNEL);",
+ l1, e);
+ r = mtree_insert(&tree, l1, e, GFP_KERNEL);
+ trace("// ret %d\n", r);
+ break;
+ case 2:
+ trace("\tmtree_insert_range(mt, 0x%lx, 0x%lx, (void *)%p, GFP_KERNEL);",
+ l1, l2, e);
+ r = mtree_insert_range(&tree, l1, l2, e, GFP_KERNEL);
+ trace("// %d\n", r);
+ break;
+#endif
+ default:
+ case 0:
+ trace("\tmtree_store_range(mt, 0x%lx, 0x%lx, (void *)%p, GFP_KERNEL);",
+ l1, l2, e);
+ r = mtree_store_range(&tree, l1, l2, e, GFP_KERNEL);
+ trace(" // %d\n", r);
+ break;
+ case 4:
+ trace("\tmtree_store(mt, 1x%lx, (void *)%p, GFP_KERNEL);",
+ l1, e);
+ r = mtree_store(&tree, l1, e, GFP_KERNEL);
+ trace(" // %d\n", r);
+ break;
+ case 5:
+ trace("\tmtree_erase(mt, 0x%lx);", l1);
+ rl = mtree_erase(&tree, l1);
+ trace(" // %p\n", rl);
+ break;
+#if 0
+ case 6:
+ mt_validate(&tree);
+ trace("mtree_destroy(mt);\n");
+ mtree_destroy(&tree);
+ trace("mt_init_flags(mt, 0x%x);\n", TREE_FLAGS);
+ mt_init_flags(&tree, TREE_FLAGS);
+ break;
+ case 7:
+ mt_validate(&tree);
+ trace("mtree_destroy(mt);\n");
+ mtree_destroy(&tree);
+ trace("mt_init_flags(mt, 0x%x);\n", 0);
+ mt_init_flags(&tree, 0);
+ break;
+#endif
+ }
+
+ mt_validate(&tree);
+ }
+
+ mt_validate(&tree);
+ trace("mtree_destroy(mt);\n");
+ mtree_destroy(&tree);
+ trace("mt_init_flags(mt, 0x%x);\n", TREE_FLAGS);
+ mt_init_flags(&tree, TREE_FLAGS);
+}
+
+extern int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+ char *v;
+
+ srand(time(NULL));
+ v = getenv("V");
+ if (v)
+ test_verbose = 1;
+
+ maple_tree_init();
+ mt_init_flags(&tree, TREE_FLAGS);
+ trace("mt_init_flags(mt, 0x%x);\n", TREE_FLAGS);
+ return 0;
+}
+
+extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ struct data info;
+
+ if (!size)
+ return 0;
+
+ info.data = data;
+ info.size = size;
+ info.position = 0;
+ count = 125 * get_uint(&info);
+
+ //printk("count %lu and size %zu\n", count, size);
+ maple_tree_tests(&info);
+ rcu_barrier();
+ return 0;
+}