diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-14 20:25:18 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-14 20:25:18 -0500 |
commit | a57cb1c1d7974c62a5c80f7869e35b492ace12cd (patch) | |
tree | 5a42ee9a668f171143464bc86013954c1bbe94ad /tools | |
parent | cf1b3341afab9d3ad02a76b3a619ea027dcf4e28 (diff) | |
parent | e1e14ab8411df344a17687821f8f78f0a1e73cbb (diff) |
Merge branch 'akpm' (patches from Andrew)
Merge more updates from Andrew Morton:
- a few misc things
- kexec updates
- DMA-mapping updates to better support networking DMA operations
- IPC updates
- various MM changes to improve DAX fault handling
- lots of radix-tree changes, mainly to the test suite. All leading up
to reimplementing the IDA/IDR code to be a wrapper layer over the
radix-tree. However the final trigger-pulling patch is held off for
4.11.
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (114 commits)
radix tree test suite: delete unused rcupdate.c
radix tree test suite: add new tag check
radix-tree: ensure counts are initialised
radix tree test suite: cache recently freed objects
radix tree test suite: add some more functionality
idr: reduce the number of bits per level from 8 to 6
rxrpc: abstract away knowledge of IDR internals
tpm: use idr_find(), not idr_find_slowpath()
idr: add ida_is_empty
radix tree test suite: check multiorder iteration
radix-tree: fix replacement for multiorder entries
radix-tree: add radix_tree_split_preload()
radix-tree: add radix_tree_split
radix-tree: add radix_tree_join
radix-tree: delete radix_tree_range_tag_if_tagged()
radix-tree: delete radix_tree_locate_item()
radix-tree: improve multiorder iterators
btrfs: fix race in btrfs_free_dummy_fs_info()
radix-tree: improve dump output
radix-tree: make radix_tree_find_next_bit more useful
...
Diffstat (limited to 'tools')
24 files changed, 842 insertions, 302 deletions
diff --git a/tools/include/asm/bug.h b/tools/include/asm/bug.h index 9e5f4846967f..beda1a884b50 100644 --- a/tools/include/asm/bug.h +++ b/tools/include/asm/bug.h | |||
@@ -12,6 +12,17 @@ | |||
12 | unlikely(__ret_warn_on); \ | 12 | unlikely(__ret_warn_on); \ |
13 | }) | 13 | }) |
14 | 14 | ||
15 | #define WARN_ON_ONCE(condition) ({ \ | ||
16 | static int __warned; \ | ||
17 | int __ret_warn_once = !!(condition); \ | ||
18 | \ | ||
19 | if (unlikely(__ret_warn_once && !__warned)) { \ | ||
20 | __warned = true; \ | ||
21 | WARN_ON(1); \ | ||
22 | } \ | ||
23 | unlikely(__ret_warn_once); \ | ||
24 | }) | ||
25 | |||
15 | #define WARN_ONCE(condition, format...) ({ \ | 26 | #define WARN_ONCE(condition, format...) ({ \ |
16 | static int __warned; \ | 27 | static int __warned; \ |
17 | int __ret_warn_once = !!(condition); \ | 28 | int __ret_warn_once = !!(condition); \ |
diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h index 43c1c5021e4b..eef41d500e9e 100644 --- a/tools/include/linux/bitmap.h +++ b/tools/include/linux/bitmap.h | |||
@@ -35,6 +35,32 @@ static inline void bitmap_zero(unsigned long *dst, int nbits) | |||
35 | } | 35 | } |
36 | } | 36 | } |
37 | 37 | ||
38 | static inline void bitmap_fill(unsigned long *dst, unsigned int nbits) | ||
39 | { | ||
40 | unsigned int nlongs = BITS_TO_LONGS(nbits); | ||
41 | if (!small_const_nbits(nbits)) { | ||
42 | unsigned int len = (nlongs - 1) * sizeof(unsigned long); | ||
43 | memset(dst, 0xff, len); | ||
44 | } | ||
45 | dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits); | ||
46 | } | ||
47 | |||
48 | static inline int bitmap_empty(const unsigned long *src, unsigned nbits) | ||
49 | { | ||
50 | if (small_const_nbits(nbits)) | ||
51 | return ! (*src & BITMAP_LAST_WORD_MASK(nbits)); | ||
52 | |||
53 | return find_first_bit(src, nbits) == nbits; | ||
54 | } | ||
55 | |||
56 | static inline int bitmap_full(const unsigned long *src, unsigned int nbits) | ||
57 | { | ||
58 | if (small_const_nbits(nbits)) | ||
59 | return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits)); | ||
60 | |||
61 | return find_first_zero_bit(src, nbits) == nbits; | ||
62 | } | ||
63 | |||
38 | static inline int bitmap_weight(const unsigned long *src, int nbits) | 64 | static inline int bitmap_weight(const unsigned long *src, int nbits) |
39 | { | 65 | { |
40 | if (small_const_nbits(nbits)) | 66 | if (small_const_nbits(nbits)) |
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index d08e214ec6e7..be93ab02b490 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl | |||
@@ -719,14 +719,14 @@ sub set_value { | |||
719 | 719 | ||
720 | if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $prvalue ne "build") { | 720 | if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $prvalue ne "build") { |
721 | # Note if a test is something other than build, then we | 721 | # Note if a test is something other than build, then we |
722 | # will need other manditory options. | 722 | # will need other mandatory options. |
723 | if ($prvalue ne "install") { | 723 | if ($prvalue ne "install") { |
724 | # for bisect, we need to check BISECT_TYPE | 724 | # for bisect, we need to check BISECT_TYPE |
725 | if ($prvalue ne "bisect") { | 725 | if ($prvalue ne "bisect") { |
726 | $buildonly = 0; | 726 | $buildonly = 0; |
727 | } | 727 | } |
728 | } else { | 728 | } else { |
729 | # install still limits some manditory options. | 729 | # install still limits some mandatory options. |
730 | $buildonly = 2; | 730 | $buildonly = 2; |
731 | } | 731 | } |
732 | } | 732 | } |
@@ -735,7 +735,7 @@ sub set_value { | |||
735 | if ($prvalue ne "install") { | 735 | if ($prvalue ne "install") { |
736 | $buildonly = 0; | 736 | $buildonly = 0; |
737 | } else { | 737 | } else { |
738 | # install still limits some manditory options. | 738 | # install still limits some mandatory options. |
739 | $buildonly = 2; | 739 | $buildonly = 2; |
740 | } | 740 | } |
741 | } | 741 | } |
@@ -3989,7 +3989,7 @@ sub make_min_config { | |||
3989 | } | 3989 | } |
3990 | } | 3990 | } |
3991 | 3991 | ||
3992 | # Save off all the current mandidory configs | 3992 | # Save off all the current mandatory configs |
3993 | open (OUT, ">$temp_config") | 3993 | open (OUT, ">$temp_config") |
3994 | or die "Can't write to $temp_config"; | 3994 | or die "Can't write to $temp_config"; |
3995 | foreach my $config (keys %keep_configs) { | 3995 | foreach my $config (keys %keep_configs) { |
diff --git a/tools/testing/radix-tree/Makefile b/tools/testing/radix-tree/Makefile index f2e07f2fd4b4..3635e4d3eca7 100644 --- a/tools/testing/radix-tree/Makefile +++ b/tools/testing/radix-tree/Makefile | |||
@@ -1,10 +1,14 @@ | |||
1 | 1 | ||
2 | CFLAGS += -I. -g -O2 -Wall -D_LGPL_SOURCE | 2 | CFLAGS += -I. -I../../include -g -O2 -Wall -D_LGPL_SOURCE |
3 | LDFLAGS += -lpthread -lurcu | 3 | LDFLAGS += -lpthread -lurcu |
4 | TARGETS = main | 4 | TARGETS = main |
5 | OFILES = main.o radix-tree.o linux.o test.o tag_check.o find_next_bit.o \ | 5 | OFILES = main.o radix-tree.o linux.o test.o tag_check.o find_next_bit.o \ |
6 | regression1.o regression2.o regression3.o multiorder.o \ | 6 | regression1.o regression2.o regression3.o multiorder.o \ |
7 | iteration_check.o | 7 | iteration_check.o benchmark.o |
8 | |||
9 | ifdef BENCHMARK | ||
10 | CFLAGS += -DBENCHMARK=1 | ||
11 | endif | ||
8 | 12 | ||
9 | targets: $(TARGETS) | 13 | targets: $(TARGETS) |
10 | 14 | ||
@@ -14,7 +18,12 @@ main: $(OFILES) | |||
14 | clean: | 18 | clean: |
15 | $(RM) -f $(TARGETS) *.o radix-tree.c | 19 | $(RM) -f $(TARGETS) *.o radix-tree.c |
16 | 20 | ||
17 | $(OFILES): *.h */*.h ../../../include/linux/radix-tree.h ../../include/linux/*.h | 21 | find_next_bit.o: ../../lib/find_bit.c |
22 | $(CC) $(CFLAGS) -c -o $@ $< | ||
23 | |||
24 | $(OFILES): *.h */*.h \ | ||
25 | ../../include/linux/*.h \ | ||
26 | ../../../include/linux/radix-tree.h | ||
18 | 27 | ||
19 | radix-tree.c: ../../../lib/radix-tree.c | 28 | radix-tree.c: ../../../lib/radix-tree.c |
20 | sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@ | 29 | sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@ |
diff --git a/tools/testing/radix-tree/benchmark.c b/tools/testing/radix-tree/benchmark.c new file mode 100644 index 000000000000..215ca86c7605 --- /dev/null +++ b/tools/testing/radix-tree/benchmark.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * benchmark.c: | ||
3 | * Author: Konstantin Khlebnikov <koct9i@gmail.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | #include <linux/radix-tree.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <time.h> | ||
18 | #include "test.h" | ||
19 | |||
20 | #define NSEC_PER_SEC 1000000000L | ||
21 | |||
22 | static long long benchmark_iter(struct radix_tree_root *root, bool tagged) | ||
23 | { | ||
24 | volatile unsigned long sink = 0; | ||
25 | struct radix_tree_iter iter; | ||
26 | struct timespec start, finish; | ||
27 | long long nsec; | ||
28 | int l, loops = 1; | ||
29 | void **slot; | ||
30 | |||
31 | #ifdef BENCHMARK | ||
32 | again: | ||
33 | #endif | ||
34 | clock_gettime(CLOCK_MONOTONIC, &start); | ||
35 | for (l = 0; l < loops; l++) { | ||
36 | if (tagged) { | ||
37 | radix_tree_for_each_tagged(slot, root, &iter, 0, 0) | ||
38 | sink ^= (unsigned long)slot; | ||
39 | } else { | ||
40 | radix_tree_for_each_slot(slot, root, &iter, 0) | ||
41 | sink ^= (unsigned long)slot; | ||
42 | } | ||
43 | } | ||
44 | clock_gettime(CLOCK_MONOTONIC, &finish); | ||
45 | |||
46 | nsec = (finish.tv_sec - start.tv_sec) * NSEC_PER_SEC + | ||
47 | (finish.tv_nsec - start.tv_nsec); | ||
48 | |||
49 | #ifdef BENCHMARK | ||
50 | if (loops == 1 && nsec * 5 < NSEC_PER_SEC) { | ||
51 | loops = NSEC_PER_SEC / nsec / 4 + 1; | ||
52 | goto again; | ||
53 | } | ||
54 | #endif | ||
55 | |||
56 | nsec /= loops; | ||
57 | return nsec; | ||
58 | } | ||
59 | |||
60 | static void benchmark_size(unsigned long size, unsigned long step, int order) | ||
61 | { | ||
62 | RADIX_TREE(tree, GFP_KERNEL); | ||
63 | long long normal, tagged; | ||
64 | unsigned long index; | ||
65 | |||
66 | for (index = 0 ; index < size ; index += step) { | ||
67 | item_insert_order(&tree, index, order); | ||
68 | radix_tree_tag_set(&tree, index, 0); | ||
69 | } | ||
70 | |||
71 | tagged = benchmark_iter(&tree, true); | ||
72 | normal = benchmark_iter(&tree, false); | ||
73 | |||
74 | printf("Size %ld, step %6ld, order %d tagged %10lld ns, normal %10lld ns\n", | ||
75 | size, step, order, tagged, normal); | ||
76 | |||
77 | item_kill_tree(&tree); | ||
78 | rcu_barrier(); | ||
79 | } | ||
80 | |||
81 | void benchmark(void) | ||
82 | { | ||
83 | unsigned long size[] = {1 << 10, 1 << 20, 0}; | ||
84 | unsigned long step[] = {1, 2, 7, 15, 63, 64, 65, | ||
85 | 128, 256, 512, 12345, 0}; | ||
86 | int c, s; | ||
87 | |||
88 | printf("starting benchmarks\n"); | ||
89 | printf("RADIX_TREE_MAP_SHIFT = %d\n", RADIX_TREE_MAP_SHIFT); | ||
90 | |||
91 | for (c = 0; size[c]; c++) | ||
92 | for (s = 0; step[s]; s++) | ||
93 | benchmark_size(size[c], step[s], 0); | ||
94 | |||
95 | for (c = 0; size[c]; c++) | ||
96 | for (s = 0; step[s]; s++) | ||
97 | benchmark_size(size[c], step[s] << 9, 9); | ||
98 | } | ||
diff --git a/tools/testing/radix-tree/find_next_bit.c b/tools/testing/radix-tree/find_next_bit.c deleted file mode 100644 index d1c2178bb2d4..000000000000 --- a/tools/testing/radix-tree/find_next_bit.c +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
1 | /* find_next_bit.c: fallback find next bit implementation | ||
2 | * | ||
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | #include <linux/bitops.h> | ||
14 | |||
15 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) | ||
16 | |||
17 | /* | ||
18 | * Find the next set bit in a memory region. | ||
19 | */ | ||
20 | unsigned long find_next_bit(const unsigned long *addr, unsigned long size, | ||
21 | unsigned long offset) | ||
22 | { | ||
23 | const unsigned long *p = addr + BITOP_WORD(offset); | ||
24 | unsigned long result = offset & ~(BITS_PER_LONG-1); | ||
25 | unsigned long tmp; | ||
26 | |||
27 | if (offset >= size) | ||
28 | return size; | ||
29 | size -= result; | ||
30 | offset %= BITS_PER_LONG; | ||
31 | if (offset) { | ||
32 | tmp = *(p++); | ||
33 | tmp &= (~0UL << offset); | ||
34 | if (size < BITS_PER_LONG) | ||
35 | goto found_first; | ||
36 | if (tmp) | ||
37 | goto found_middle; | ||
38 | size -= BITS_PER_LONG; | ||
39 | result += BITS_PER_LONG; | ||
40 | } | ||
41 | while (size & ~(BITS_PER_LONG-1)) { | ||
42 | if ((tmp = *(p++))) | ||
43 | goto found_middle; | ||
44 | result += BITS_PER_LONG; | ||
45 | size -= BITS_PER_LONG; | ||
46 | } | ||
47 | if (!size) | ||
48 | return result; | ||
49 | tmp = *p; | ||
50 | |||
51 | found_first: | ||
52 | tmp &= (~0UL >> (BITS_PER_LONG - size)); | ||
53 | if (tmp == 0UL) /* Are any bits set? */ | ||
54 | return result + size; /* Nope. */ | ||
55 | found_middle: | ||
56 | return result + __ffs(tmp); | ||
57 | } | ||
diff --git a/tools/testing/radix-tree/iteration_check.c b/tools/testing/radix-tree/iteration_check.c index 9adb8e7415a6..7572b7ed930e 100644 --- a/tools/testing/radix-tree/iteration_check.c +++ b/tools/testing/radix-tree/iteration_check.c | |||
@@ -16,35 +16,50 @@ | |||
16 | #include <pthread.h> | 16 | #include <pthread.h> |
17 | #include "test.h" | 17 | #include "test.h" |
18 | 18 | ||
19 | #define NUM_THREADS 4 | 19 | #define NUM_THREADS 5 |
20 | #define TAG 0 | 20 | #define MAX_IDX 100 |
21 | #define TAG 0 | ||
22 | #define NEW_TAG 1 | ||
23 | |||
21 | static pthread_mutex_t tree_lock = PTHREAD_MUTEX_INITIALIZER; | 24 | static pthread_mutex_t tree_lock = PTHREAD_MUTEX_INITIALIZER; |
22 | static pthread_t threads[NUM_THREADS]; | 25 | static pthread_t threads[NUM_THREADS]; |
23 | RADIX_TREE(tree, GFP_KERNEL); | 26 | static unsigned int seeds[3]; |
24 | bool test_complete; | 27 | static RADIX_TREE(tree, GFP_KERNEL); |
28 | static bool test_complete; | ||
29 | static int max_order; | ||
25 | 30 | ||
26 | /* relentlessly fill the tree with tagged entries */ | 31 | /* relentlessly fill the tree with tagged entries */ |
27 | static void *add_entries_fn(void *arg) | 32 | static void *add_entries_fn(void *arg) |
28 | { | 33 | { |
29 | int pgoff; | 34 | rcu_register_thread(); |
30 | 35 | ||
31 | while (!test_complete) { | 36 | while (!test_complete) { |
32 | for (pgoff = 0; pgoff < 100; pgoff++) { | 37 | unsigned long pgoff; |
38 | int order; | ||
39 | |||
40 | for (pgoff = 0; pgoff < MAX_IDX; pgoff++) { | ||
33 | pthread_mutex_lock(&tree_lock); | 41 | pthread_mutex_lock(&tree_lock); |
34 | if (item_insert(&tree, pgoff) == 0) | 42 | for (order = max_order; order >= 0; order--) { |
35 | item_tag_set(&tree, pgoff, TAG); | 43 | if (item_insert_order(&tree, pgoff, order) |
44 | == 0) { | ||
45 | item_tag_set(&tree, pgoff, TAG); | ||
46 | break; | ||
47 | } | ||
48 | } | ||
36 | pthread_mutex_unlock(&tree_lock); | 49 | pthread_mutex_unlock(&tree_lock); |
37 | } | 50 | } |
38 | } | 51 | } |
39 | 52 | ||
53 | rcu_unregister_thread(); | ||
54 | |||
40 | return NULL; | 55 | return NULL; |
41 | } | 56 | } |
42 | 57 | ||
43 | /* | 58 | /* |
44 | * Iterate over the tagged entries, doing a radix_tree_iter_retry() as we find | 59 | * Iterate over the tagged entries, doing a radix_tree_iter_retry() as we find |
45 | * things that have been removed and randomly resetting our iteration to the | 60 | * things that have been removed and randomly resetting our iteration to the |
46 | * next chunk with radix_tree_iter_next(). Both radix_tree_iter_retry() and | 61 | * next chunk with radix_tree_iter_resume(). Both radix_tree_iter_retry() and |
47 | * radix_tree_iter_next() cause radix_tree_next_slot() to be called with a | 62 | * radix_tree_iter_resume() cause radix_tree_next_slot() to be called with a |
48 | * NULL 'slot' variable. | 63 | * NULL 'slot' variable. |
49 | */ | 64 | */ |
50 | static void *tagged_iteration_fn(void *arg) | 65 | static void *tagged_iteration_fn(void *arg) |
@@ -52,17 +67,12 @@ static void *tagged_iteration_fn(void *arg) | |||
52 | struct radix_tree_iter iter; | 67 | struct radix_tree_iter iter; |
53 | void **slot; | 68 | void **slot; |
54 | 69 | ||
70 | rcu_register_thread(); | ||
71 | |||
55 | while (!test_complete) { | 72 | while (!test_complete) { |
56 | rcu_read_lock(); | 73 | rcu_read_lock(); |
57 | radix_tree_for_each_tagged(slot, &tree, &iter, 0, TAG) { | 74 | radix_tree_for_each_tagged(slot, &tree, &iter, 0, TAG) { |
58 | void *entry; | 75 | void *entry = radix_tree_deref_slot(slot); |
59 | int i; | ||
60 | |||
61 | /* busy wait to let removals happen */ | ||
62 | for (i = 0; i < 1000000; i++) | ||
63 | ; | ||
64 | |||
65 | entry = radix_tree_deref_slot(slot); | ||
66 | if (unlikely(!entry)) | 76 | if (unlikely(!entry)) |
67 | continue; | 77 | continue; |
68 | 78 | ||
@@ -71,20 +81,26 @@ static void *tagged_iteration_fn(void *arg) | |||
71 | continue; | 81 | continue; |
72 | } | 82 | } |
73 | 83 | ||
74 | if (rand() % 50 == 0) | 84 | if (rand_r(&seeds[0]) % 50 == 0) { |
75 | slot = radix_tree_iter_next(&iter); | 85 | slot = radix_tree_iter_resume(slot, &iter); |
86 | rcu_read_unlock(); | ||
87 | rcu_barrier(); | ||
88 | rcu_read_lock(); | ||
89 | } | ||
76 | } | 90 | } |
77 | rcu_read_unlock(); | 91 | rcu_read_unlock(); |
78 | } | 92 | } |
79 | 93 | ||
94 | rcu_unregister_thread(); | ||
95 | |||
80 | return NULL; | 96 | return NULL; |
81 | } | 97 | } |
82 | 98 | ||
83 | /* | 99 | /* |
84 | * Iterate over the entries, doing a radix_tree_iter_retry() as we find things | 100 | * Iterate over the entries, doing a radix_tree_iter_retry() as we find things |
85 | * that have been removed and randomly resetting our iteration to the next | 101 | * that have been removed and randomly resetting our iteration to the next |
86 | * chunk with radix_tree_iter_next(). Both radix_tree_iter_retry() and | 102 | * chunk with radix_tree_iter_resume(). Both radix_tree_iter_retry() and |
87 | * radix_tree_iter_next() cause radix_tree_next_slot() to be called with a | 103 | * radix_tree_iter_resume() cause radix_tree_next_slot() to be called with a |
88 | * NULL 'slot' variable. | 104 | * NULL 'slot' variable. |
89 | */ | 105 | */ |
90 | static void *untagged_iteration_fn(void *arg) | 106 | static void *untagged_iteration_fn(void *arg) |
@@ -92,17 +108,12 @@ static void *untagged_iteration_fn(void *arg) | |||
92 | struct radix_tree_iter iter; | 108 | struct radix_tree_iter iter; |
93 | void **slot; | 109 | void **slot; |
94 | 110 | ||
111 | rcu_register_thread(); | ||
112 | |||
95 | while (!test_complete) { | 113 | while (!test_complete) { |
96 | rcu_read_lock(); | 114 | rcu_read_lock(); |
97 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | 115 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { |
98 | void *entry; | 116 | void *entry = radix_tree_deref_slot(slot); |
99 | int i; | ||
100 | |||
101 | /* busy wait to let removals happen */ | ||
102 | for (i = 0; i < 1000000; i++) | ||
103 | ; | ||
104 | |||
105 | entry = radix_tree_deref_slot(slot); | ||
106 | if (unlikely(!entry)) | 117 | if (unlikely(!entry)) |
107 | continue; | 118 | continue; |
108 | 119 | ||
@@ -111,12 +122,18 @@ static void *untagged_iteration_fn(void *arg) | |||
111 | continue; | 122 | continue; |
112 | } | 123 | } |
113 | 124 | ||
114 | if (rand() % 50 == 0) | 125 | if (rand_r(&seeds[1]) % 50 == 0) { |
115 | slot = radix_tree_iter_next(&iter); | 126 | slot = radix_tree_iter_resume(slot, &iter); |
127 | rcu_read_unlock(); | ||
128 | rcu_barrier(); | ||
129 | rcu_read_lock(); | ||
130 | } | ||
116 | } | 131 | } |
117 | rcu_read_unlock(); | 132 | rcu_read_unlock(); |
118 | } | 133 | } |
119 | 134 | ||
135 | rcu_unregister_thread(); | ||
136 | |||
120 | return NULL; | 137 | return NULL; |
121 | } | 138 | } |
122 | 139 | ||
@@ -126,47 +143,71 @@ static void *untagged_iteration_fn(void *arg) | |||
126 | */ | 143 | */ |
127 | static void *remove_entries_fn(void *arg) | 144 | static void *remove_entries_fn(void *arg) |
128 | { | 145 | { |
146 | rcu_register_thread(); | ||
147 | |||
129 | while (!test_complete) { | 148 | while (!test_complete) { |
130 | int pgoff; | 149 | int pgoff; |
131 | 150 | ||
132 | pgoff = rand() % 100; | 151 | pgoff = rand_r(&seeds[2]) % MAX_IDX; |
133 | 152 | ||
134 | pthread_mutex_lock(&tree_lock); | 153 | pthread_mutex_lock(&tree_lock); |
135 | item_delete(&tree, pgoff); | 154 | item_delete(&tree, pgoff); |
136 | pthread_mutex_unlock(&tree_lock); | 155 | pthread_mutex_unlock(&tree_lock); |
137 | } | 156 | } |
138 | 157 | ||
158 | rcu_unregister_thread(); | ||
159 | |||
160 | return NULL; | ||
161 | } | ||
162 | |||
163 | static void *tag_entries_fn(void *arg) | ||
164 | { | ||
165 | rcu_register_thread(); | ||
166 | |||
167 | while (!test_complete) { | ||
168 | tag_tagged_items(&tree, &tree_lock, 0, MAX_IDX, 10, TAG, | ||
169 | NEW_TAG); | ||
170 | } | ||
171 | rcu_unregister_thread(); | ||
139 | return NULL; | 172 | return NULL; |
140 | } | 173 | } |
141 | 174 | ||
142 | /* This is a unit test for a bug found by the syzkaller tester */ | 175 | /* This is a unit test for a bug found by the syzkaller tester */ |
143 | void iteration_test(void) | 176 | void iteration_test(unsigned order, unsigned test_duration) |
144 | { | 177 | { |
145 | int i; | 178 | int i; |
146 | 179 | ||
147 | printf("Running iteration tests for 10 seconds\n"); | 180 | printf("Running %siteration tests for %d seconds\n", |
181 | order > 0 ? "multiorder " : "", test_duration); | ||
148 | 182 | ||
149 | srand(time(0)); | 183 | max_order = order; |
150 | test_complete = false; | 184 | test_complete = false; |
151 | 185 | ||
186 | for (i = 0; i < 3; i++) | ||
187 | seeds[i] = rand(); | ||
188 | |||
152 | if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) { | 189 | if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) { |
153 | perror("pthread_create"); | 190 | perror("create tagged iteration thread"); |
154 | exit(1); | 191 | exit(1); |
155 | } | 192 | } |
156 | if (pthread_create(&threads[1], NULL, untagged_iteration_fn, NULL)) { | 193 | if (pthread_create(&threads[1], NULL, untagged_iteration_fn, NULL)) { |
157 | perror("pthread_create"); | 194 | perror("create untagged iteration thread"); |
158 | exit(1); | 195 | exit(1); |
159 | } | 196 | } |
160 | if (pthread_create(&threads[2], NULL, add_entries_fn, NULL)) { | 197 | if (pthread_create(&threads[2], NULL, add_entries_fn, NULL)) { |
161 | perror("pthread_create"); | 198 | perror("create add entry thread"); |
162 | exit(1); | 199 | exit(1); |
163 | } | 200 | } |
164 | if (pthread_create(&threads[3], NULL, remove_entries_fn, NULL)) { | 201 | if (pthread_create(&threads[3], NULL, remove_entries_fn, NULL)) { |
165 | perror("pthread_create"); | 202 | perror("create remove entry thread"); |
203 | exit(1); | ||
204 | } | ||
205 | if (pthread_create(&threads[4], NULL, tag_entries_fn, NULL)) { | ||
206 | perror("create tag entry thread"); | ||
166 | exit(1); | 207 | exit(1); |
167 | } | 208 | } |
168 | 209 | ||
169 | sleep(10); | 210 | sleep(test_duration); |
170 | test_complete = true; | 211 | test_complete = true; |
171 | 212 | ||
172 | for (i = 0; i < NUM_THREADS; i++) { | 213 | for (i = 0; i < NUM_THREADS; i++) { |
diff --git a/tools/testing/radix-tree/linux.c b/tools/testing/radix-tree/linux.c index 154823737b20..d31ea7c9abec 100644 --- a/tools/testing/radix-tree/linux.c +++ b/tools/testing/radix-tree/linux.c | |||
@@ -1,14 +1,26 @@ | |||
1 | #include <stdlib.h> | 1 | #include <stdlib.h> |
2 | #include <string.h> | 2 | #include <string.h> |
3 | #include <malloc.h> | 3 | #include <malloc.h> |
4 | #include <pthread.h> | ||
4 | #include <unistd.h> | 5 | #include <unistd.h> |
5 | #include <assert.h> | 6 | #include <assert.h> |
6 | 7 | ||
7 | #include <linux/mempool.h> | 8 | #include <linux/mempool.h> |
9 | #include <linux/poison.h> | ||
8 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
11 | #include <linux/radix-tree.h> | ||
9 | #include <urcu/uatomic.h> | 12 | #include <urcu/uatomic.h> |
10 | 13 | ||
11 | int nr_allocated; | 14 | int nr_allocated; |
15 | int preempt_count; | ||
16 | |||
17 | struct kmem_cache { | ||
18 | pthread_mutex_t lock; | ||
19 | int size; | ||
20 | int nr_objs; | ||
21 | void *objs; | ||
22 | void (*ctor)(void *); | ||
23 | }; | ||
12 | 24 | ||
13 | void *mempool_alloc(mempool_t *pool, int gfp_mask) | 25 | void *mempool_alloc(mempool_t *pool, int gfp_mask) |
14 | { | 26 | { |
@@ -33,19 +45,59 @@ mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, | |||
33 | 45 | ||
34 | void *kmem_cache_alloc(struct kmem_cache *cachep, int flags) | 46 | void *kmem_cache_alloc(struct kmem_cache *cachep, int flags) |
35 | { | 47 | { |
36 | void *ret = malloc(cachep->size); | 48 | struct radix_tree_node *node; |
37 | if (cachep->ctor) | 49 | |
38 | cachep->ctor(ret); | 50 | if (flags & __GFP_NOWARN) |
51 | return NULL; | ||
52 | |||
53 | pthread_mutex_lock(&cachep->lock); | ||
54 | if (cachep->nr_objs) { | ||
55 | cachep->nr_objs--; | ||
56 | node = cachep->objs; | ||
57 | cachep->objs = node->private_data; | ||
58 | pthread_mutex_unlock(&cachep->lock); | ||
59 | node->private_data = NULL; | ||
60 | } else { | ||
61 | pthread_mutex_unlock(&cachep->lock); | ||
62 | node = malloc(cachep->size); | ||
63 | if (cachep->ctor) | ||
64 | cachep->ctor(node); | ||
65 | } | ||
66 | |||
39 | uatomic_inc(&nr_allocated); | 67 | uatomic_inc(&nr_allocated); |
40 | return ret; | 68 | return node; |
41 | } | 69 | } |
42 | 70 | ||
43 | void kmem_cache_free(struct kmem_cache *cachep, void *objp) | 71 | void kmem_cache_free(struct kmem_cache *cachep, void *objp) |
44 | { | 72 | { |
45 | assert(objp); | 73 | assert(objp); |
46 | uatomic_dec(&nr_allocated); | 74 | uatomic_dec(&nr_allocated); |
47 | memset(objp, 0, cachep->size); | 75 | pthread_mutex_lock(&cachep->lock); |
48 | free(objp); | 76 | if (cachep->nr_objs > 10) { |
77 | memset(objp, POISON_FREE, cachep->size); | ||
78 | free(objp); | ||
79 | } else { | ||
80 | struct radix_tree_node *node = objp; | ||
81 | cachep->nr_objs++; | ||
82 | node->private_data = cachep->objs; | ||
83 | cachep->objs = node; | ||
84 | } | ||
85 | pthread_mutex_unlock(&cachep->lock); | ||
86 | } | ||
87 | |||
88 | void *kmalloc(size_t size, gfp_t gfp) | ||
89 | { | ||
90 | void *ret = malloc(size); | ||
91 | uatomic_inc(&nr_allocated); | ||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | void kfree(void *p) | ||
96 | { | ||
97 | if (!p) | ||
98 | return; | ||
99 | uatomic_dec(&nr_allocated); | ||
100 | free(p); | ||
49 | } | 101 | } |
50 | 102 | ||
51 | struct kmem_cache * | 103 | struct kmem_cache * |
@@ -54,7 +106,10 @@ kmem_cache_create(const char *name, size_t size, size_t offset, | |||
54 | { | 106 | { |
55 | struct kmem_cache *ret = malloc(sizeof(*ret)); | 107 | struct kmem_cache *ret = malloc(sizeof(*ret)); |
56 | 108 | ||
109 | pthread_mutex_init(&ret->lock, NULL); | ||
57 | ret->size = size; | 110 | ret->size = size; |
111 | ret->nr_objs = 0; | ||
112 | ret->objs = NULL; | ||
58 | ret->ctor = ctor; | 113 | ret->ctor = ctor; |
59 | return ret; | 114 | return ret; |
60 | } | 115 | } |
diff --git a/tools/testing/radix-tree/linux/bitops.h b/tools/testing/radix-tree/linux/bitops.h index 71d58427ab60..a13e9bc76eec 100644 --- a/tools/testing/radix-tree/linux/bitops.h +++ b/tools/testing/radix-tree/linux/bitops.h | |||
@@ -2,9 +2,14 @@ | |||
2 | #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ | 2 | #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ |
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <linux/bitops/find.h> | ||
6 | #include <linux/bitops/hweight.h> | ||
7 | #include <linux/kernel.h> | ||
5 | 8 | ||
6 | #define BITOP_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) | 9 | #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) |
7 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) | 10 | #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) |
11 | #define BITS_PER_BYTE 8 | ||
12 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) | ||
8 | 13 | ||
9 | /** | 14 | /** |
10 | * __set_bit - Set a bit in memory | 15 | * __set_bit - Set a bit in memory |
@@ -17,16 +22,16 @@ | |||
17 | */ | 22 | */ |
18 | static inline void __set_bit(int nr, volatile unsigned long *addr) | 23 | static inline void __set_bit(int nr, volatile unsigned long *addr) |
19 | { | 24 | { |
20 | unsigned long mask = BITOP_MASK(nr); | 25 | unsigned long mask = BIT_MASK(nr); |
21 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 26 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); |
22 | 27 | ||
23 | *p |= mask; | 28 | *p |= mask; |
24 | } | 29 | } |
25 | 30 | ||
26 | static inline void __clear_bit(int nr, volatile unsigned long *addr) | 31 | static inline void __clear_bit(int nr, volatile unsigned long *addr) |
27 | { | 32 | { |
28 | unsigned long mask = BITOP_MASK(nr); | 33 | unsigned long mask = BIT_MASK(nr); |
29 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 34 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); |
30 | 35 | ||
31 | *p &= ~mask; | 36 | *p &= ~mask; |
32 | } | 37 | } |
@@ -42,8 +47,8 @@ static inline void __clear_bit(int nr, volatile unsigned long *addr) | |||
42 | */ | 47 | */ |
43 | static inline void __change_bit(int nr, volatile unsigned long *addr) | 48 | static inline void __change_bit(int nr, volatile unsigned long *addr) |
44 | { | 49 | { |
45 | unsigned long mask = BITOP_MASK(nr); | 50 | unsigned long mask = BIT_MASK(nr); |
46 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 51 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); |
47 | 52 | ||
48 | *p ^= mask; | 53 | *p ^= mask; |
49 | } | 54 | } |
@@ -59,8 +64,8 @@ static inline void __change_bit(int nr, volatile unsigned long *addr) | |||
59 | */ | 64 | */ |
60 | static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) | 65 | static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) |
61 | { | 66 | { |
62 | unsigned long mask = BITOP_MASK(nr); | 67 | unsigned long mask = BIT_MASK(nr); |
63 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 68 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); |
64 | unsigned long old = *p; | 69 | unsigned long old = *p; |
65 | 70 | ||
66 | *p = old | mask; | 71 | *p = old | mask; |
@@ -78,8 +83,8 @@ static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) | |||
78 | */ | 83 | */ |
79 | static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) | 84 | static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) |
80 | { | 85 | { |
81 | unsigned long mask = BITOP_MASK(nr); | 86 | unsigned long mask = BIT_MASK(nr); |
82 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 87 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); |
83 | unsigned long old = *p; | 88 | unsigned long old = *p; |
84 | 89 | ||
85 | *p = old & ~mask; | 90 | *p = old & ~mask; |
@@ -90,8 +95,8 @@ static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) | |||
90 | static inline int __test_and_change_bit(int nr, | 95 | static inline int __test_and_change_bit(int nr, |
91 | volatile unsigned long *addr) | 96 | volatile unsigned long *addr) |
92 | { | 97 | { |
93 | unsigned long mask = BITOP_MASK(nr); | 98 | unsigned long mask = BIT_MASK(nr); |
94 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 99 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); |
95 | unsigned long old = *p; | 100 | unsigned long old = *p; |
96 | 101 | ||
97 | *p = old ^ mask; | 102 | *p = old ^ mask; |
@@ -105,7 +110,7 @@ static inline int __test_and_change_bit(int nr, | |||
105 | */ | 110 | */ |
106 | static inline int test_bit(int nr, const volatile unsigned long *addr) | 111 | static inline int test_bit(int nr, const volatile unsigned long *addr) |
107 | { | 112 | { |
108 | return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); | 113 | return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); |
109 | } | 114 | } |
110 | 115 | ||
111 | /** | 116 | /** |
@@ -147,4 +152,9 @@ unsigned long find_next_bit(const unsigned long *addr, | |||
147 | unsigned long size, | 152 | unsigned long size, |
148 | unsigned long offset); | 153 | unsigned long offset); |
149 | 154 | ||
155 | static inline unsigned long hweight_long(unsigned long w) | ||
156 | { | ||
157 | return sizeof(w) == 4 ? hweight32(w) : hweight64(w); | ||
158 | } | ||
159 | |||
150 | #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ | 160 | #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ |
diff --git a/tools/testing/radix-tree/linux/bitops/non-atomic.h b/tools/testing/radix-tree/linux/bitops/non-atomic.h index 46a825cf2ae1..6a1bcb9d2c4a 100644 --- a/tools/testing/radix-tree/linux/bitops/non-atomic.h +++ b/tools/testing/radix-tree/linux/bitops/non-atomic.h | |||
@@ -3,7 +3,6 @@ | |||
3 | 3 | ||
4 | #include <asm/types.h> | 4 | #include <asm/types.h> |
5 | 5 | ||
6 | #define BITOP_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) | ||
7 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) | 6 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) |
8 | 7 | ||
9 | /** | 8 | /** |
@@ -17,7 +16,7 @@ | |||
17 | */ | 16 | */ |
18 | static inline void __set_bit(int nr, volatile unsigned long *addr) | 17 | static inline void __set_bit(int nr, volatile unsigned long *addr) |
19 | { | 18 | { |
20 | unsigned long mask = BITOP_MASK(nr); | 19 | unsigned long mask = BIT_MASK(nr); |
21 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 20 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
22 | 21 | ||
23 | *p |= mask; | 22 | *p |= mask; |
@@ -25,7 +24,7 @@ static inline void __set_bit(int nr, volatile unsigned long *addr) | |||
25 | 24 | ||
26 | static inline void __clear_bit(int nr, volatile unsigned long *addr) | 25 | static inline void __clear_bit(int nr, volatile unsigned long *addr) |
27 | { | 26 | { |
28 | unsigned long mask = BITOP_MASK(nr); | 27 | unsigned long mask = BIT_MASK(nr); |
29 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 28 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
30 | 29 | ||
31 | *p &= ~mask; | 30 | *p &= ~mask; |
@@ -42,7 +41,7 @@ static inline void __clear_bit(int nr, volatile unsigned long *addr) | |||
42 | */ | 41 | */ |
43 | static inline void __change_bit(int nr, volatile unsigned long *addr) | 42 | static inline void __change_bit(int nr, volatile unsigned long *addr) |
44 | { | 43 | { |
45 | unsigned long mask = BITOP_MASK(nr); | 44 | unsigned long mask = BIT_MASK(nr); |
46 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 45 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
47 | 46 | ||
48 | *p ^= mask; | 47 | *p ^= mask; |
@@ -59,7 +58,7 @@ static inline void __change_bit(int nr, volatile unsigned long *addr) | |||
59 | */ | 58 | */ |
60 | static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) | 59 | static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) |
61 | { | 60 | { |
62 | unsigned long mask = BITOP_MASK(nr); | 61 | unsigned long mask = BIT_MASK(nr); |
63 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 62 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
64 | unsigned long old = *p; | 63 | unsigned long old = *p; |
65 | 64 | ||
@@ -78,7 +77,7 @@ static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) | |||
78 | */ | 77 | */ |
79 | static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) | 78 | static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) |
80 | { | 79 | { |
81 | unsigned long mask = BITOP_MASK(nr); | 80 | unsigned long mask = BIT_MASK(nr); |
82 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 81 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
83 | unsigned long old = *p; | 82 | unsigned long old = *p; |
84 | 83 | ||
@@ -90,7 +89,7 @@ static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) | |||
90 | static inline int __test_and_change_bit(int nr, | 89 | static inline int __test_and_change_bit(int nr, |
91 | volatile unsigned long *addr) | 90 | volatile unsigned long *addr) |
92 | { | 91 | { |
93 | unsigned long mask = BITOP_MASK(nr); | 92 | unsigned long mask = BIT_MASK(nr); |
94 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); | 93 | unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); |
95 | unsigned long old = *p; | 94 | unsigned long old = *p; |
96 | 95 | ||
diff --git a/tools/testing/radix-tree/linux/bug.h b/tools/testing/radix-tree/linux/bug.h index ccbe444977df..23b8ed52f8c8 100644 --- a/tools/testing/radix-tree/linux/bug.h +++ b/tools/testing/radix-tree/linux/bug.h | |||
@@ -1 +1 @@ | |||
#define WARN_ON_ONCE(x) assert(x) | #include "asm/bug.h" | ||
diff --git a/tools/testing/radix-tree/linux/gfp.h b/tools/testing/radix-tree/linux/gfp.h index 5201b915f631..5b09b2ce6c33 100644 --- a/tools/testing/radix-tree/linux/gfp.h +++ b/tools/testing/radix-tree/linux/gfp.h | |||
@@ -3,8 +3,24 @@ | |||
3 | 3 | ||
4 | #define __GFP_BITS_SHIFT 26 | 4 | #define __GFP_BITS_SHIFT 26 |
5 | #define __GFP_BITS_MASK ((gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) | 5 | #define __GFP_BITS_MASK ((gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) |
6 | #define __GFP_WAIT 1 | 6 | |
7 | #define __GFP_ACCOUNT 0 | 7 | #define __GFP_HIGH 0x20u |
8 | #define __GFP_NOWARN 0 | 8 | #define __GFP_IO 0x40u |
9 | #define __GFP_FS 0x80u | ||
10 | #define __GFP_NOWARN 0x200u | ||
11 | #define __GFP_ATOMIC 0x80000u | ||
12 | #define __GFP_ACCOUNT 0x100000u | ||
13 | #define __GFP_DIRECT_RECLAIM 0x400000u | ||
14 | #define __GFP_KSWAPD_RECLAIM 0x2000000u | ||
15 | |||
16 | #define __GFP_RECLAIM (__GFP_DIRECT_RECLAIM|__GFP_KSWAPD_RECLAIM) | ||
17 | |||
18 | #define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM) | ||
19 | #define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS) | ||
20 | |||
21 | static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags) | ||
22 | { | ||
23 | return !!(gfp_flags & __GFP_DIRECT_RECLAIM); | ||
24 | } | ||
9 | 25 | ||
10 | #endif | 26 | #endif |
diff --git a/tools/testing/radix-tree/linux/kernel.h b/tools/testing/radix-tree/linux/kernel.h index be98a47b4e1b..9b43b4975d83 100644 --- a/tools/testing/radix-tree/linux/kernel.h +++ b/tools/testing/radix-tree/linux/kernel.h | |||
@@ -8,9 +8,14 @@ | |||
8 | #include <limits.h> | 8 | #include <limits.h> |
9 | 9 | ||
10 | #include "../../include/linux/compiler.h" | 10 | #include "../../include/linux/compiler.h" |
11 | #include "../../include/linux/err.h" | ||
11 | #include "../../../include/linux/kconfig.h" | 12 | #include "../../../include/linux/kconfig.h" |
12 | 13 | ||
14 | #ifdef BENCHMARK | ||
15 | #define RADIX_TREE_MAP_SHIFT 6 | ||
16 | #else | ||
13 | #define RADIX_TREE_MAP_SHIFT 3 | 17 | #define RADIX_TREE_MAP_SHIFT 3 |
18 | #endif | ||
14 | 19 | ||
15 | #ifndef NULL | 20 | #ifndef NULL |
16 | #define NULL 0 | 21 | #define NULL 0 |
@@ -43,4 +48,17 @@ static inline int in_interrupt(void) | |||
43 | { | 48 | { |
44 | return 0; | 49 | return 0; |
45 | } | 50 | } |
51 | |||
52 | /* | ||
53 | * This looks more complex than it should be. But we need to | ||
54 | * get the type for the ~ right in round_down (it needs to be | ||
55 | * as wide as the result!), and we want to evaluate the macro | ||
56 | * arguments just once each. | ||
57 | */ | ||
58 | #define __round_mask(x, y) ((__typeof__(x))((y)-1)) | ||
59 | #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) | ||
60 | #define round_down(x, y) ((x) & ~__round_mask(x, y)) | ||
61 | |||
62 | #define xchg(ptr, x) uatomic_xchg(ptr, x) | ||
63 | |||
46 | #endif /* _KERNEL_H */ | 64 | #endif /* _KERNEL_H */ |
diff --git a/tools/testing/radix-tree/linux/preempt.h b/tools/testing/radix-tree/linux/preempt.h index 6210672e3baa..65c04c226965 100644 --- a/tools/testing/radix-tree/linux/preempt.h +++ b/tools/testing/radix-tree/linux/preempt.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* */ | 1 | extern int preempt_count; |
2 | 2 | ||
3 | #define preempt_disable() do { } while (0) | 3 | #define preempt_disable() uatomic_inc(&preempt_count) |
4 | #define preempt_enable() do { } while (0) | 4 | #define preempt_enable() uatomic_dec(&preempt_count) |
diff --git a/tools/testing/radix-tree/linux/slab.h b/tools/testing/radix-tree/linux/slab.h index 6d5a34770fd4..e40337f41a38 100644 --- a/tools/testing/radix-tree/linux/slab.h +++ b/tools/testing/radix-tree/linux/slab.h | |||
@@ -7,15 +7,8 @@ | |||
7 | #define SLAB_PANIC 2 | 7 | #define SLAB_PANIC 2 |
8 | #define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ | 8 | #define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ |
9 | 9 | ||
10 | static inline int gfpflags_allow_blocking(gfp_t mask) | 10 | void *kmalloc(size_t size, gfp_t); |
11 | { | 11 | void kfree(void *); |
12 | return 1; | ||
13 | } | ||
14 | |||
15 | struct kmem_cache { | ||
16 | int size; | ||
17 | void (*ctor)(void *); | ||
18 | }; | ||
19 | 12 | ||
20 | void *kmem_cache_alloc(struct kmem_cache *cachep, int flags); | 13 | void *kmem_cache_alloc(struct kmem_cache *cachep, int flags); |
21 | void kmem_cache_free(struct kmem_cache *cachep, void *objp); | 14 | void kmem_cache_free(struct kmem_cache *cachep, void *objp); |
diff --git a/tools/testing/radix-tree/linux/types.h b/tools/testing/radix-tree/linux/types.h index faa0b6ff9ca8..8491d89873bb 100644 --- a/tools/testing/radix-tree/linux/types.h +++ b/tools/testing/radix-tree/linux/types.h | |||
@@ -6,8 +6,6 @@ | |||
6 | #define __rcu | 6 | #define __rcu |
7 | #define __read_mostly | 7 | #define __read_mostly |
8 | 8 | ||
9 | #define BITS_PER_LONG (sizeof(long) * 8) | ||
10 | |||
11 | static inline void INIT_LIST_HEAD(struct list_head *list) | 9 | static inline void INIT_LIST_HEAD(struct list_head *list) |
12 | { | 10 | { |
13 | list->next = list; | 11 | list->next = list; |
diff --git a/tools/testing/radix-tree/main.c b/tools/testing/radix-tree/main.c index daa9010693e8..f7e9801a6754 100644 --- a/tools/testing/radix-tree/main.c +++ b/tools/testing/radix-tree/main.c | |||
@@ -67,7 +67,6 @@ void big_gang_check(bool long_run) | |||
67 | 67 | ||
68 | for (i = 0; i < (long_run ? 1000 : 3); i++) { | 68 | for (i = 0; i < (long_run ? 1000 : 3); i++) { |
69 | __big_gang_check(); | 69 | __big_gang_check(); |
70 | srand(time(0)); | ||
71 | printf("%d ", i); | 70 | printf("%d ", i); |
72 | fflush(stdout); | 71 | fflush(stdout); |
73 | } | 72 | } |
@@ -206,8 +205,7 @@ void copy_tag_check(void) | |||
206 | } | 205 | } |
207 | 206 | ||
208 | // printf("\ncopying tags...\n"); | 207 | // printf("\ncopying tags...\n"); |
209 | cur = start; | 208 | tagged = tag_tagged_items(&tree, NULL, start, end, ITEMS, 0, 1); |
210 | tagged = radix_tree_range_tag_if_tagged(&tree, &cur, end, ITEMS, 0, 1); | ||
211 | 209 | ||
212 | // printf("checking copied tags\n"); | 210 | // printf("checking copied tags\n"); |
213 | assert(tagged == count); | 211 | assert(tagged == count); |
@@ -215,16 +213,13 @@ void copy_tag_check(void) | |||
215 | 213 | ||
216 | /* Copy tags in several rounds */ | 214 | /* Copy tags in several rounds */ |
217 | // printf("\ncopying tags...\n"); | 215 | // printf("\ncopying tags...\n"); |
218 | cur = start; | 216 | tmp = rand() % (count / 10 + 2); |
219 | do { | 217 | tagged = tag_tagged_items(&tree, NULL, start, end, tmp, 0, 2); |
220 | tmp = rand() % (count/10+2); | 218 | assert(tagged == count); |
221 | tagged = radix_tree_range_tag_if_tagged(&tree, &cur, end, tmp, 0, 2); | ||
222 | } while (tmp == tagged); | ||
223 | 219 | ||
224 | // printf("%lu %lu %lu\n", tagged, tmp, count); | 220 | // printf("%lu %lu %lu\n", tagged, tmp, count); |
225 | // printf("checking copied tags\n"); | 221 | // printf("checking copied tags\n"); |
226 | check_copied_tags(&tree, start, end, idx, ITEMS, 0, 2); | 222 | check_copied_tags(&tree, start, end, idx, ITEMS, 0, 2); |
227 | assert(tagged < tmp); | ||
228 | verify_tag_consistency(&tree, 0); | 223 | verify_tag_consistency(&tree, 0); |
229 | verify_tag_consistency(&tree, 1); | 224 | verify_tag_consistency(&tree, 1); |
230 | verify_tag_consistency(&tree, 2); | 225 | verify_tag_consistency(&tree, 2); |
@@ -240,7 +235,7 @@ static void __locate_check(struct radix_tree_root *tree, unsigned long index, | |||
240 | 235 | ||
241 | item_insert_order(tree, index, order); | 236 | item_insert_order(tree, index, order); |
242 | item = item_lookup(tree, index); | 237 | item = item_lookup(tree, index); |
243 | index2 = radix_tree_locate_item(tree, item); | 238 | index2 = find_item(tree, item); |
244 | if (index != index2) { | 239 | if (index != index2) { |
245 | printf("index %ld order %d inserted; found %ld\n", | 240 | printf("index %ld order %d inserted; found %ld\n", |
246 | index, order, index2); | 241 | index, order, index2); |
@@ -274,17 +269,17 @@ static void locate_check(void) | |||
274 | index += (1UL << order)) { | 269 | index += (1UL << order)) { |
275 | __locate_check(&tree, index + offset, order); | 270 | __locate_check(&tree, index + offset, order); |
276 | } | 271 | } |
277 | if (radix_tree_locate_item(&tree, &tree) != -1) | 272 | if (find_item(&tree, &tree) != -1) |
278 | abort(); | 273 | abort(); |
279 | 274 | ||
280 | item_kill_tree(&tree); | 275 | item_kill_tree(&tree); |
281 | } | 276 | } |
282 | } | 277 | } |
283 | 278 | ||
284 | if (radix_tree_locate_item(&tree, &tree) != -1) | 279 | if (find_item(&tree, &tree) != -1) |
285 | abort(); | 280 | abort(); |
286 | __locate_check(&tree, -1, 0); | 281 | __locate_check(&tree, -1, 0); |
287 | if (radix_tree_locate_item(&tree, &tree) != -1) | 282 | if (find_item(&tree, &tree) != -1) |
288 | abort(); | 283 | abort(); |
289 | item_kill_tree(&tree); | 284 | item_kill_tree(&tree); |
290 | } | 285 | } |
@@ -293,50 +288,80 @@ static void single_thread_tests(bool long_run) | |||
293 | { | 288 | { |
294 | int i; | 289 | int i; |
295 | 290 | ||
296 | printf("starting single_thread_tests: %d allocated\n", nr_allocated); | 291 | printf("starting single_thread_tests: %d allocated, preempt %d\n", |
292 | nr_allocated, preempt_count); | ||
297 | multiorder_checks(); | 293 | multiorder_checks(); |
298 | printf("after multiorder_check: %d allocated\n", nr_allocated); | 294 | rcu_barrier(); |
295 | printf("after multiorder_check: %d allocated, preempt %d\n", | ||
296 | nr_allocated, preempt_count); | ||
299 | locate_check(); | 297 | locate_check(); |
300 | printf("after locate_check: %d allocated\n", nr_allocated); | 298 | rcu_barrier(); |
299 | printf("after locate_check: %d allocated, preempt %d\n", | ||
300 | nr_allocated, preempt_count); | ||
301 | tag_check(); | 301 | tag_check(); |
302 | printf("after tag_check: %d allocated\n", nr_allocated); | 302 | rcu_barrier(); |
303 | printf("after tag_check: %d allocated, preempt %d\n", | ||
304 | nr_allocated, preempt_count); | ||
303 | gang_check(); | 305 | gang_check(); |
304 | printf("after gang_check: %d allocated\n", nr_allocated); | 306 | rcu_barrier(); |
307 | printf("after gang_check: %d allocated, preempt %d\n", | ||
308 | nr_allocated, preempt_count); | ||
305 | add_and_check(); | 309 | add_and_check(); |
306 | printf("after add_and_check: %d allocated\n", nr_allocated); | 310 | rcu_barrier(); |
311 | printf("after add_and_check: %d allocated, preempt %d\n", | ||
312 | nr_allocated, preempt_count); | ||
307 | dynamic_height_check(); | 313 | dynamic_height_check(); |
308 | printf("after dynamic_height_check: %d allocated\n", nr_allocated); | 314 | rcu_barrier(); |
315 | printf("after dynamic_height_check: %d allocated, preempt %d\n", | ||
316 | nr_allocated, preempt_count); | ||
309 | big_gang_check(long_run); | 317 | big_gang_check(long_run); |
310 | printf("after big_gang_check: %d allocated\n", nr_allocated); | 318 | rcu_barrier(); |
319 | printf("after big_gang_check: %d allocated, preempt %d\n", | ||
320 | nr_allocated, preempt_count); | ||
311 | for (i = 0; i < (long_run ? 2000 : 3); i++) { | 321 | for (i = 0; i < (long_run ? 2000 : 3); i++) { |
312 | copy_tag_check(); | 322 | copy_tag_check(); |
313 | printf("%d ", i); | 323 | printf("%d ", i); |
314 | fflush(stdout); | 324 | fflush(stdout); |
315 | } | 325 | } |
316 | printf("after copy_tag_check: %d allocated\n", nr_allocated); | 326 | rcu_barrier(); |
327 | printf("after copy_tag_check: %d allocated, preempt %d\n", | ||
328 | nr_allocated, preempt_count); | ||
317 | } | 329 | } |
318 | 330 | ||
319 | int main(int argc, char **argv) | 331 | int main(int argc, char **argv) |
320 | { | 332 | { |
321 | bool long_run = false; | 333 | bool long_run = false; |
322 | int opt; | 334 | int opt; |
335 | unsigned int seed = time(NULL); | ||
323 | 336 | ||
324 | while ((opt = getopt(argc, argv, "l")) != -1) { | 337 | while ((opt = getopt(argc, argv, "ls:")) != -1) { |
325 | if (opt == 'l') | 338 | if (opt == 'l') |
326 | long_run = true; | 339 | long_run = true; |
340 | else if (opt == 's') | ||
341 | seed = strtoul(optarg, NULL, 0); | ||
327 | } | 342 | } |
328 | 343 | ||
344 | printf("random seed %u\n", seed); | ||
345 | srand(seed); | ||
346 | |||
329 | rcu_register_thread(); | 347 | rcu_register_thread(); |
330 | radix_tree_init(); | 348 | radix_tree_init(); |
331 | 349 | ||
332 | regression1_test(); | 350 | regression1_test(); |
333 | regression2_test(); | 351 | regression2_test(); |
334 | regression3_test(); | 352 | regression3_test(); |
335 | iteration_test(); | 353 | iteration_test(0, 10); |
354 | iteration_test(7, 20); | ||
336 | single_thread_tests(long_run); | 355 | single_thread_tests(long_run); |
337 | 356 | ||
338 | sleep(1); | 357 | /* Free any remaining preallocated nodes */ |
339 | printf("after sleep(1): %d allocated\n", nr_allocated); | 358 | radix_tree_cpu_dead(0); |
359 | |||
360 | benchmark(); | ||
361 | |||
362 | rcu_barrier(); | ||
363 | printf("after rcu_barrier: %d allocated, preempt %d\n", | ||
364 | nr_allocated, preempt_count); | ||
340 | rcu_unregister_thread(); | 365 | rcu_unregister_thread(); |
341 | 366 | ||
342 | exit(0); | 367 | exit(0); |
diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c index d1be94667a30..f79812a5e070 100644 --- a/tools/testing/radix-tree/multiorder.c +++ b/tools/testing/radix-tree/multiorder.c | |||
@@ -26,7 +26,6 @@ static void __multiorder_tag_test(int index, int order) | |||
26 | { | 26 | { |
27 | RADIX_TREE(tree, GFP_KERNEL); | 27 | RADIX_TREE(tree, GFP_KERNEL); |
28 | int base, err, i; | 28 | int base, err, i; |
29 | unsigned long first = 0; | ||
30 | 29 | ||
31 | /* our canonical entry */ | 30 | /* our canonical entry */ |
32 | base = index & ~((1 << order) - 1); | 31 | base = index & ~((1 << order) - 1); |
@@ -60,7 +59,7 @@ static void __multiorder_tag_test(int index, int order) | |||
60 | assert(!radix_tree_tag_get(&tree, i, 1)); | 59 | assert(!radix_tree_tag_get(&tree, i, 1)); |
61 | } | 60 | } |
62 | 61 | ||
63 | assert(radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, 10, 0, 1) == 1); | 62 | assert(tag_tagged_items(&tree, NULL, 0, ~0UL, 10, 0, 1) == 1); |
64 | assert(radix_tree_tag_clear(&tree, index, 0)); | 63 | assert(radix_tree_tag_clear(&tree, index, 0)); |
65 | 64 | ||
66 | for_each_index(i, base, order) { | 65 | for_each_index(i, base, order) { |
@@ -76,8 +75,27 @@ static void __multiorder_tag_test(int index, int order) | |||
76 | item_kill_tree(&tree); | 75 | item_kill_tree(&tree); |
77 | } | 76 | } |
78 | 77 | ||
78 | static void __multiorder_tag_test2(unsigned order, unsigned long index2) | ||
79 | { | ||
80 | RADIX_TREE(tree, GFP_KERNEL); | ||
81 | unsigned long index = (1 << order); | ||
82 | index2 += index; | ||
83 | |||
84 | assert(item_insert_order(&tree, 0, order) == 0); | ||
85 | assert(item_insert(&tree, index2) == 0); | ||
86 | |||
87 | assert(radix_tree_tag_set(&tree, 0, 0)); | ||
88 | assert(radix_tree_tag_set(&tree, index2, 0)); | ||
89 | |||
90 | assert(tag_tagged_items(&tree, NULL, 0, ~0UL, 10, 0, 1) == 2); | ||
91 | |||
92 | item_kill_tree(&tree); | ||
93 | } | ||
94 | |||
79 | static void multiorder_tag_tests(void) | 95 | static void multiorder_tag_tests(void) |
80 | { | 96 | { |
97 | int i, j; | ||
98 | |||
81 | /* test multi-order entry for indices 0-7 with no sibling pointers */ | 99 | /* test multi-order entry for indices 0-7 with no sibling pointers */ |
82 | __multiorder_tag_test(0, 3); | 100 | __multiorder_tag_test(0, 3); |
83 | __multiorder_tag_test(5, 3); | 101 | __multiorder_tag_test(5, 3); |
@@ -117,6 +135,10 @@ static void multiorder_tag_tests(void) | |||
117 | __multiorder_tag_test(300, 8); | 135 | __multiorder_tag_test(300, 8); |
118 | 136 | ||
119 | __multiorder_tag_test(0x12345678UL, 8); | 137 | __multiorder_tag_test(0x12345678UL, 8); |
138 | |||
139 | for (i = 1; i < 10; i++) | ||
140 | for (j = 0; j < (10 << i); j++) | ||
141 | __multiorder_tag_test2(i, j); | ||
120 | } | 142 | } |
121 | 143 | ||
122 | static void multiorder_check(unsigned long index, int order) | 144 | static void multiorder_check(unsigned long index, int order) |
@@ -125,7 +147,7 @@ static void multiorder_check(unsigned long index, int order) | |||
125 | unsigned long min = index & ~((1UL << order) - 1); | 147 | unsigned long min = index & ~((1UL << order) - 1); |
126 | unsigned long max = min + (1UL << order); | 148 | unsigned long max = min + (1UL << order); |
127 | void **slot; | 149 | void **slot; |
128 | struct item *item2 = item_create(min); | 150 | struct item *item2 = item_create(min, order); |
129 | RADIX_TREE(tree, GFP_KERNEL); | 151 | RADIX_TREE(tree, GFP_KERNEL); |
130 | 152 | ||
131 | printf("Multiorder index %ld, order %d\n", index, order); | 153 | printf("Multiorder index %ld, order %d\n", index, order); |
@@ -231,11 +253,14 @@ void multiorder_iteration(void) | |||
231 | radix_tree_for_each_slot(slot, &tree, &iter, j) { | 253 | radix_tree_for_each_slot(slot, &tree, &iter, j) { |
232 | int height = order[i] / RADIX_TREE_MAP_SHIFT; | 254 | int height = order[i] / RADIX_TREE_MAP_SHIFT; |
233 | int shift = height * RADIX_TREE_MAP_SHIFT; | 255 | int shift = height * RADIX_TREE_MAP_SHIFT; |
234 | int mask = (1 << order[i]) - 1; | 256 | unsigned long mask = (1UL << order[i]) - 1; |
257 | struct item *item = *slot; | ||
235 | 258 | ||
236 | assert(iter.index >= (index[i] &~ mask)); | 259 | assert((iter.index | mask) == (index[i] | mask)); |
237 | assert(iter.index <= (index[i] | mask)); | ||
238 | assert(iter.shift == shift); | 260 | assert(iter.shift == shift); |
261 | assert(!radix_tree_is_internal_node(item)); | ||
262 | assert((item->index | mask) == (index[i] | mask)); | ||
263 | assert(item->order == order[i]); | ||
239 | i++; | 264 | i++; |
240 | } | 265 | } |
241 | } | 266 | } |
@@ -248,7 +273,6 @@ void multiorder_tagged_iteration(void) | |||
248 | RADIX_TREE(tree, GFP_KERNEL); | 273 | RADIX_TREE(tree, GFP_KERNEL); |
249 | struct radix_tree_iter iter; | 274 | struct radix_tree_iter iter; |
250 | void **slot; | 275 | void **slot; |
251 | unsigned long first = 0; | ||
252 | int i, j; | 276 | int i, j; |
253 | 277 | ||
254 | printf("Multiorder tagged iteration test\n"); | 278 | printf("Multiorder tagged iteration test\n"); |
@@ -269,7 +293,7 @@ void multiorder_tagged_iteration(void) | |||
269 | assert(radix_tree_tag_set(&tree, tag_index[i], 1)); | 293 | assert(radix_tree_tag_set(&tree, tag_index[i], 1)); |
270 | 294 | ||
271 | for (j = 0; j < 256; j++) { | 295 | for (j = 0; j < 256; j++) { |
272 | int mask, k; | 296 | int k; |
273 | 297 | ||
274 | for (i = 0; i < TAG_ENTRIES; i++) { | 298 | for (i = 0; i < TAG_ENTRIES; i++) { |
275 | for (k = i; index[k] < tag_index[i]; k++) | 299 | for (k = i; index[k] < tag_index[i]; k++) |
@@ -279,18 +303,22 @@ void multiorder_tagged_iteration(void) | |||
279 | } | 303 | } |
280 | 304 | ||
281 | radix_tree_for_each_tagged(slot, &tree, &iter, j, 1) { | 305 | radix_tree_for_each_tagged(slot, &tree, &iter, j, 1) { |
306 | unsigned long mask; | ||
307 | struct item *item = *slot; | ||
282 | for (k = i; index[k] < tag_index[i]; k++) | 308 | for (k = i; index[k] < tag_index[i]; k++) |
283 | ; | 309 | ; |
284 | mask = (1 << order[k]) - 1; | 310 | mask = (1UL << order[k]) - 1; |
285 | 311 | ||
286 | assert(iter.index >= (tag_index[i] &~ mask)); | 312 | assert((iter.index | mask) == (tag_index[i] | mask)); |
287 | assert(iter.index <= (tag_index[i] | mask)); | 313 | assert(!radix_tree_is_internal_node(item)); |
314 | assert((item->index | mask) == (tag_index[i] | mask)); | ||
315 | assert(item->order == order[k]); | ||
288 | i++; | 316 | i++; |
289 | } | 317 | } |
290 | } | 318 | } |
291 | 319 | ||
292 | radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, | 320 | assert(tag_tagged_items(&tree, NULL, 0, ~0UL, TAG_ENTRIES, 1, 2) == |
293 | MT_NUM_ENTRIES, 1, 2); | 321 | TAG_ENTRIES); |
294 | 322 | ||
295 | for (j = 0; j < 256; j++) { | 323 | for (j = 0; j < 256; j++) { |
296 | int mask, k; | 324 | int mask, k; |
@@ -303,19 +331,21 @@ void multiorder_tagged_iteration(void) | |||
303 | } | 331 | } |
304 | 332 | ||
305 | radix_tree_for_each_tagged(slot, &tree, &iter, j, 2) { | 333 | radix_tree_for_each_tagged(slot, &tree, &iter, j, 2) { |
334 | struct item *item = *slot; | ||
306 | for (k = i; index[k] < tag_index[i]; k++) | 335 | for (k = i; index[k] < tag_index[i]; k++) |
307 | ; | 336 | ; |
308 | mask = (1 << order[k]) - 1; | 337 | mask = (1 << order[k]) - 1; |
309 | 338 | ||
310 | assert(iter.index >= (tag_index[i] &~ mask)); | 339 | assert((iter.index | mask) == (tag_index[i] | mask)); |
311 | assert(iter.index <= (tag_index[i] | mask)); | 340 | assert(!radix_tree_is_internal_node(item)); |
341 | assert((item->index | mask) == (tag_index[i] | mask)); | ||
342 | assert(item->order == order[k]); | ||
312 | i++; | 343 | i++; |
313 | } | 344 | } |
314 | } | 345 | } |
315 | 346 | ||
316 | first = 1; | 347 | assert(tag_tagged_items(&tree, NULL, 1, ~0UL, MT_NUM_ENTRIES * 2, 1, 0) |
317 | radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, | 348 | == TAG_ENTRIES); |
318 | MT_NUM_ENTRIES, 1, 0); | ||
319 | i = 0; | 349 | i = 0; |
320 | radix_tree_for_each_tagged(slot, &tree, &iter, 0, 0) { | 350 | radix_tree_for_each_tagged(slot, &tree, &iter, 0, 0) { |
321 | assert(iter.index == tag_index[i]); | 351 | assert(iter.index == tag_index[i]); |
@@ -325,6 +355,261 @@ void multiorder_tagged_iteration(void) | |||
325 | item_kill_tree(&tree); | 355 | item_kill_tree(&tree); |
326 | } | 356 | } |
327 | 357 | ||
358 | static void multiorder_join1(unsigned long index, | ||
359 | unsigned order1, unsigned order2) | ||
360 | { | ||
361 | unsigned long loc; | ||
362 | void *item, *item2 = item_create(index + 1, order1); | ||
363 | RADIX_TREE(tree, GFP_KERNEL); | ||
364 | |||
365 | item_insert_order(&tree, index, order2); | ||
366 | item = radix_tree_lookup(&tree, index); | ||
367 | radix_tree_join(&tree, index + 1, order1, item2); | ||
368 | loc = find_item(&tree, item); | ||
369 | if (loc == -1) | ||
370 | free(item); | ||
371 | item = radix_tree_lookup(&tree, index + 1); | ||
372 | assert(item == item2); | ||
373 | item_kill_tree(&tree); | ||
374 | } | ||
375 | |||
376 | static void multiorder_join2(unsigned order1, unsigned order2) | ||
377 | { | ||
378 | RADIX_TREE(tree, GFP_KERNEL); | ||
379 | struct radix_tree_node *node; | ||
380 | void *item1 = item_create(0, order1); | ||
381 | void *item2; | ||
382 | |||
383 | item_insert_order(&tree, 0, order2); | ||
384 | radix_tree_insert(&tree, 1 << order2, (void *)0x12UL); | ||
385 | item2 = __radix_tree_lookup(&tree, 1 << order2, &node, NULL); | ||
386 | assert(item2 == (void *)0x12UL); | ||
387 | assert(node->exceptional == 1); | ||
388 | |||
389 | radix_tree_join(&tree, 0, order1, item1); | ||
390 | item2 = __radix_tree_lookup(&tree, 1 << order2, &node, NULL); | ||
391 | assert(item2 == item1); | ||
392 | assert(node->exceptional == 0); | ||
393 | item_kill_tree(&tree); | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * This test revealed an accounting bug for exceptional entries at one point. | ||
398 | * Nodes were being freed back into the pool with an elevated exception count | ||
399 | * by radix_tree_join() and then radix_tree_split() was failing to zero the | ||
400 | * count of exceptional entries. | ||
401 | */ | ||
402 | static void multiorder_join3(unsigned int order) | ||
403 | { | ||
404 | RADIX_TREE(tree, GFP_KERNEL); | ||
405 | struct radix_tree_node *node; | ||
406 | void **slot; | ||
407 | struct radix_tree_iter iter; | ||
408 | unsigned long i; | ||
409 | |||
410 | for (i = 0; i < (1 << order); i++) { | ||
411 | radix_tree_insert(&tree, i, (void *)0x12UL); | ||
412 | } | ||
413 | |||
414 | radix_tree_join(&tree, 0, order, (void *)0x16UL); | ||
415 | rcu_barrier(); | ||
416 | |||
417 | radix_tree_split(&tree, 0, 0); | ||
418 | |||
419 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | ||
420 | radix_tree_iter_replace(&tree, &iter, slot, (void *)0x12UL); | ||
421 | } | ||
422 | |||
423 | __radix_tree_lookup(&tree, 0, &node, NULL); | ||
424 | assert(node->exceptional == node->count); | ||
425 | |||
426 | item_kill_tree(&tree); | ||
427 | } | ||
428 | |||
429 | static void multiorder_join(void) | ||
430 | { | ||
431 | int i, j, idx; | ||
432 | |||
433 | for (idx = 0; idx < 1024; idx = idx * 2 + 3) { | ||
434 | for (i = 1; i < 15; i++) { | ||
435 | for (j = 0; j < i; j++) { | ||
436 | multiorder_join1(idx, i, j); | ||
437 | } | ||
438 | } | ||
439 | } | ||
440 | |||
441 | for (i = 1; i < 15; i++) { | ||
442 | for (j = 0; j < i; j++) { | ||
443 | multiorder_join2(i, j); | ||
444 | } | ||
445 | } | ||
446 | |||
447 | for (i = 3; i < 10; i++) { | ||
448 | multiorder_join3(i); | ||
449 | } | ||
450 | } | ||
451 | |||
452 | static void check_mem(unsigned old_order, unsigned new_order, unsigned alloc) | ||
453 | { | ||
454 | struct radix_tree_preload *rtp = &radix_tree_preloads; | ||
455 | if (rtp->nr != 0) | ||
456 | printf("split(%u %u) remaining %u\n", old_order, new_order, | ||
457 | rtp->nr); | ||
458 | /* | ||
459 | * Can't check for equality here as some nodes may have been | ||
460 | * RCU-freed while we ran. But we should never finish with more | ||
461 | * nodes allocated since they should have all been preloaded. | ||
462 | */ | ||
463 | if (nr_allocated > alloc) | ||
464 | printf("split(%u %u) allocated %u %u\n", old_order, new_order, | ||
465 | alloc, nr_allocated); | ||
466 | } | ||
467 | |||
468 | static void __multiorder_split(int old_order, int new_order) | ||
469 | { | ||
470 | RADIX_TREE(tree, GFP_ATOMIC); | ||
471 | void **slot; | ||
472 | struct radix_tree_iter iter; | ||
473 | unsigned alloc; | ||
474 | |||
475 | radix_tree_preload(GFP_KERNEL); | ||
476 | assert(item_insert_order(&tree, 0, old_order) == 0); | ||
477 | radix_tree_preload_end(); | ||
478 | |||
479 | /* Wipe out the preloaded cache or it'll confuse check_mem() */ | ||
480 | radix_tree_cpu_dead(0); | ||
481 | |||
482 | radix_tree_tag_set(&tree, 0, 2); | ||
483 | |||
484 | radix_tree_split_preload(old_order, new_order, GFP_KERNEL); | ||
485 | alloc = nr_allocated; | ||
486 | radix_tree_split(&tree, 0, new_order); | ||
487 | check_mem(old_order, new_order, alloc); | ||
488 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | ||
489 | radix_tree_iter_replace(&tree, &iter, slot, | ||
490 | item_create(iter.index, new_order)); | ||
491 | } | ||
492 | radix_tree_preload_end(); | ||
493 | |||
494 | item_kill_tree(&tree); | ||
495 | } | ||
496 | |||
497 | static void __multiorder_split2(int old_order, int new_order) | ||
498 | { | ||
499 | RADIX_TREE(tree, GFP_KERNEL); | ||
500 | void **slot; | ||
501 | struct radix_tree_iter iter; | ||
502 | struct radix_tree_node *node; | ||
503 | void *item; | ||
504 | |||
505 | __radix_tree_insert(&tree, 0, old_order, (void *)0x12); | ||
506 | |||
507 | item = __radix_tree_lookup(&tree, 0, &node, NULL); | ||
508 | assert(item == (void *)0x12); | ||
509 | assert(node->exceptional > 0); | ||
510 | |||
511 | radix_tree_split(&tree, 0, new_order); | ||
512 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | ||
513 | radix_tree_iter_replace(&tree, &iter, slot, | ||
514 | item_create(iter.index, new_order)); | ||
515 | } | ||
516 | |||
517 | item = __radix_tree_lookup(&tree, 0, &node, NULL); | ||
518 | assert(item != (void *)0x12); | ||
519 | assert(node->exceptional == 0); | ||
520 | |||
521 | item_kill_tree(&tree); | ||
522 | } | ||
523 | |||
524 | static void __multiorder_split3(int old_order, int new_order) | ||
525 | { | ||
526 | RADIX_TREE(tree, GFP_KERNEL); | ||
527 | void **slot; | ||
528 | struct radix_tree_iter iter; | ||
529 | struct radix_tree_node *node; | ||
530 | void *item; | ||
531 | |||
532 | __radix_tree_insert(&tree, 0, old_order, (void *)0x12); | ||
533 | |||
534 | item = __radix_tree_lookup(&tree, 0, &node, NULL); | ||
535 | assert(item == (void *)0x12); | ||
536 | assert(node->exceptional > 0); | ||
537 | |||
538 | radix_tree_split(&tree, 0, new_order); | ||
539 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | ||
540 | radix_tree_iter_replace(&tree, &iter, slot, (void *)0x16); | ||
541 | } | ||
542 | |||
543 | item = __radix_tree_lookup(&tree, 0, &node, NULL); | ||
544 | assert(item == (void *)0x16); | ||
545 | assert(node->exceptional > 0); | ||
546 | |||
547 | item_kill_tree(&tree); | ||
548 | |||
549 | __radix_tree_insert(&tree, 0, old_order, (void *)0x12); | ||
550 | |||
551 | item = __radix_tree_lookup(&tree, 0, &node, NULL); | ||
552 | assert(item == (void *)0x12); | ||
553 | assert(node->exceptional > 0); | ||
554 | |||
555 | radix_tree_split(&tree, 0, new_order); | ||
556 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | ||
557 | if (iter.index == (1 << new_order)) | ||
558 | radix_tree_iter_replace(&tree, &iter, slot, | ||
559 | (void *)0x16); | ||
560 | else | ||
561 | radix_tree_iter_replace(&tree, &iter, slot, NULL); | ||
562 | } | ||
563 | |||
564 | item = __radix_tree_lookup(&tree, 1 << new_order, &node, NULL); | ||
565 | assert(item == (void *)0x16); | ||
566 | assert(node->count == node->exceptional); | ||
567 | do { | ||
568 | node = node->parent; | ||
569 | if (!node) | ||
570 | break; | ||
571 | assert(node->count == 1); | ||
572 | assert(node->exceptional == 0); | ||
573 | } while (1); | ||
574 | |||
575 | item_kill_tree(&tree); | ||
576 | } | ||
577 | |||
578 | static void multiorder_split(void) | ||
579 | { | ||
580 | int i, j; | ||
581 | |||
582 | for (i = 3; i < 11; i++) | ||
583 | for (j = 0; j < i; j++) { | ||
584 | __multiorder_split(i, j); | ||
585 | __multiorder_split2(i, j); | ||
586 | __multiorder_split3(i, j); | ||
587 | } | ||
588 | } | ||
589 | |||
590 | static void multiorder_account(void) | ||
591 | { | ||
592 | RADIX_TREE(tree, GFP_KERNEL); | ||
593 | struct radix_tree_node *node; | ||
594 | void **slot; | ||
595 | |||
596 | item_insert_order(&tree, 0, 5); | ||
597 | |||
598 | __radix_tree_insert(&tree, 1 << 5, 5, (void *)0x12); | ||
599 | __radix_tree_lookup(&tree, 0, &node, NULL); | ||
600 | assert(node->count == node->exceptional * 2); | ||
601 | radix_tree_delete(&tree, 1 << 5); | ||
602 | assert(node->exceptional == 0); | ||
603 | |||
604 | __radix_tree_insert(&tree, 1 << 5, 5, (void *)0x12); | ||
605 | __radix_tree_lookup(&tree, 1 << 5, &node, &slot); | ||
606 | assert(node->count == node->exceptional * 2); | ||
607 | __radix_tree_replace(&tree, node, slot, NULL, NULL, NULL); | ||
608 | assert(node->exceptional == 0); | ||
609 | |||
610 | item_kill_tree(&tree); | ||
611 | } | ||
612 | |||
328 | void multiorder_checks(void) | 613 | void multiorder_checks(void) |
329 | { | 614 | { |
330 | int i; | 615 | int i; |
@@ -342,4 +627,9 @@ void multiorder_checks(void) | |||
342 | multiorder_tag_tests(); | 627 | multiorder_tag_tests(); |
343 | multiorder_iteration(); | 628 | multiorder_iteration(); |
344 | multiorder_tagged_iteration(); | 629 | multiorder_tagged_iteration(); |
630 | multiorder_join(); | ||
631 | multiorder_split(); | ||
632 | multiorder_account(); | ||
633 | |||
634 | radix_tree_cpu_dead(0); | ||
345 | } | 635 | } |
diff --git a/tools/testing/radix-tree/rcupdate.c b/tools/testing/radix-tree/rcupdate.c deleted file mode 100644 index 31a2d14225d6..000000000000 --- a/tools/testing/radix-tree/rcupdate.c +++ /dev/null | |||
@@ -1,86 +0,0 @@ | |||
1 | #include <linux/rcupdate.h> | ||
2 | #include <pthread.h> | ||
3 | #include <stdio.h> | ||
4 | #include <assert.h> | ||
5 | |||
6 | static pthread_mutex_t rculock = PTHREAD_MUTEX_INITIALIZER; | ||
7 | static struct rcu_head *rcuhead_global = NULL; | ||
8 | static __thread int nr_rcuhead = 0; | ||
9 | static __thread struct rcu_head *rcuhead = NULL; | ||
10 | static __thread struct rcu_head *rcutail = NULL; | ||
11 | |||
12 | static pthread_cond_t rcu_worker_cond = PTHREAD_COND_INITIALIZER; | ||
13 | |||
14 | /* switch to urcu implementation when it is merged. */ | ||
15 | void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *head)) | ||
16 | { | ||
17 | head->func = func; | ||
18 | head->next = rcuhead; | ||
19 | rcuhead = head; | ||
20 | if (!rcutail) | ||
21 | rcutail = head; | ||
22 | nr_rcuhead++; | ||
23 | if (nr_rcuhead >= 1000) { | ||
24 | int signal = 0; | ||
25 | |||
26 | pthread_mutex_lock(&rculock); | ||
27 | if (!rcuhead_global) | ||
28 | signal = 1; | ||
29 | rcutail->next = rcuhead_global; | ||
30 | rcuhead_global = head; | ||
31 | pthread_mutex_unlock(&rculock); | ||
32 | |||
33 | nr_rcuhead = 0; | ||
34 | rcuhead = NULL; | ||
35 | rcutail = NULL; | ||
36 | |||
37 | if (signal) { | ||
38 | pthread_cond_signal(&rcu_worker_cond); | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static void *rcu_worker(void *arg) | ||
44 | { | ||
45 | struct rcu_head *r; | ||
46 | |||
47 | rcupdate_thread_init(); | ||
48 | |||
49 | while (1) { | ||
50 | pthread_mutex_lock(&rculock); | ||
51 | while (!rcuhead_global) { | ||
52 | pthread_cond_wait(&rcu_worker_cond, &rculock); | ||
53 | } | ||
54 | r = rcuhead_global; | ||
55 | rcuhead_global = NULL; | ||
56 | |||
57 | pthread_mutex_unlock(&rculock); | ||
58 | |||
59 | synchronize_rcu(); | ||
60 | |||
61 | while (r) { | ||
62 | struct rcu_head *tmp = r->next; | ||
63 | r->func(r); | ||
64 | r = tmp; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | rcupdate_thread_exit(); | ||
69 | |||
70 | return NULL; | ||
71 | } | ||
72 | |||
73 | static pthread_t worker_thread; | ||
74 | void rcupdate_init(void) | ||
75 | { | ||
76 | pthread_create(&worker_thread, NULL, rcu_worker, NULL); | ||
77 | } | ||
78 | |||
79 | void rcupdate_thread_init(void) | ||
80 | { | ||
81 | rcu_register_thread(); | ||
82 | } | ||
83 | void rcupdate_thread_exit(void) | ||
84 | { | ||
85 | rcu_unregister_thread(); | ||
86 | } | ||
diff --git a/tools/testing/radix-tree/regression2.c b/tools/testing/radix-tree/regression2.c index 63bf347aaf33..a41325d7a170 100644 --- a/tools/testing/radix-tree/regression2.c +++ b/tools/testing/radix-tree/regression2.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <stdio.h> | 50 | #include <stdio.h> |
51 | 51 | ||
52 | #include "regression.h" | 52 | #include "regression.h" |
53 | #include "test.h" | ||
53 | 54 | ||
54 | #define PAGECACHE_TAG_DIRTY 0 | 55 | #define PAGECACHE_TAG_DIRTY 0 |
55 | #define PAGECACHE_TAG_WRITEBACK 1 | 56 | #define PAGECACHE_TAG_WRITEBACK 1 |
@@ -90,7 +91,7 @@ void regression2_test(void) | |||
90 | /* 1. */ | 91 | /* 1. */ |
91 | start = 0; | 92 | start = 0; |
92 | end = max_slots - 2; | 93 | end = max_slots - 2; |
93 | radix_tree_range_tag_if_tagged(&mt_tree, &start, end, 1, | 94 | tag_tagged_items(&mt_tree, NULL, start, end, 1, |
94 | PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE); | 95 | PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE); |
95 | 96 | ||
96 | /* 2. */ | 97 | /* 2. */ |
diff --git a/tools/testing/radix-tree/regression3.c b/tools/testing/radix-tree/regression3.c index 1f06ed73d0a8..b594841fae85 100644 --- a/tools/testing/radix-tree/regression3.c +++ b/tools/testing/radix-tree/regression3.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * In following radix_tree_next_slot current chunk size becomes zero. | 5 | * In following radix_tree_next_slot current chunk size becomes zero. |
6 | * This isn't checked and it tries to dereference null pointer in slot. | 6 | * This isn't checked and it tries to dereference null pointer in slot. |
7 | * | 7 | * |
8 | * Helper radix_tree_iter_next reset slot to NULL and next_index to index + 1, | 8 | * Helper radix_tree_iter_resume reset slot to NULL and next_index to index + 1, |
9 | * for tagger iteraction it also must reset cached tags in iterator to abort | 9 | * for tagger iteraction it also must reset cached tags in iterator to abort |
10 | * next radix_tree_next_slot and go to slow-path into radix_tree_next_chunk. | 10 | * next radix_tree_next_slot and go to slow-path into radix_tree_next_chunk. |
11 | * | 11 | * |
@@ -88,7 +88,7 @@ void regression3_test(void) | |||
88 | printf("slot %ld %p\n", iter.index, *slot); | 88 | printf("slot %ld %p\n", iter.index, *slot); |
89 | if (!iter.index) { | 89 | if (!iter.index) { |
90 | printf("next at %ld\n", iter.index); | 90 | printf("next at %ld\n", iter.index); |
91 | slot = radix_tree_iter_next(&iter); | 91 | slot = radix_tree_iter_resume(slot, &iter); |
92 | } | 92 | } |
93 | } | 93 | } |
94 | 94 | ||
@@ -96,7 +96,7 @@ void regression3_test(void) | |||
96 | printf("contig %ld %p\n", iter.index, *slot); | 96 | printf("contig %ld %p\n", iter.index, *slot); |
97 | if (!iter.index) { | 97 | if (!iter.index) { |
98 | printf("next at %ld\n", iter.index); | 98 | printf("next at %ld\n", iter.index); |
99 | slot = radix_tree_iter_next(&iter); | 99 | slot = radix_tree_iter_resume(slot, &iter); |
100 | } | 100 | } |
101 | } | 101 | } |
102 | 102 | ||
@@ -106,7 +106,7 @@ void regression3_test(void) | |||
106 | printf("tagged %ld %p\n", iter.index, *slot); | 106 | printf("tagged %ld %p\n", iter.index, *slot); |
107 | if (!iter.index) { | 107 | if (!iter.index) { |
108 | printf("next at %ld\n", iter.index); | 108 | printf("next at %ld\n", iter.index); |
109 | slot = radix_tree_iter_next(&iter); | 109 | slot = radix_tree_iter_resume(slot, &iter); |
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
diff --git a/tools/testing/radix-tree/tag_check.c b/tools/testing/radix-tree/tag_check.c index b0ac05741750..fd98c132207a 100644 --- a/tools/testing/radix-tree/tag_check.c +++ b/tools/testing/radix-tree/tag_check.c | |||
@@ -23,7 +23,7 @@ __simple_checks(struct radix_tree_root *tree, unsigned long index, int tag) | |||
23 | item_tag_set(tree, index, tag); | 23 | item_tag_set(tree, index, tag); |
24 | ret = item_tag_get(tree, index, tag); | 24 | ret = item_tag_get(tree, index, tag); |
25 | assert(ret != 0); | 25 | assert(ret != 0); |
26 | ret = radix_tree_range_tag_if_tagged(tree, &first, ~0UL, 10, tag, !tag); | 26 | ret = tag_tagged_items(tree, NULL, first, ~0UL, 10, tag, !tag); |
27 | assert(ret == 1); | 27 | assert(ret == 1); |
28 | ret = item_tag_get(tree, index, !tag); | 28 | ret = item_tag_get(tree, index, !tag); |
29 | assert(ret != 0); | 29 | assert(ret != 0); |
@@ -51,6 +51,7 @@ void simple_checks(void) | |||
51 | verify_tag_consistency(&tree, 1); | 51 | verify_tag_consistency(&tree, 1); |
52 | printf("before item_kill_tree: %d allocated\n", nr_allocated); | 52 | printf("before item_kill_tree: %d allocated\n", nr_allocated); |
53 | item_kill_tree(&tree); | 53 | item_kill_tree(&tree); |
54 | rcu_barrier(); | ||
54 | printf("after item_kill_tree: %d allocated\n", nr_allocated); | 55 | printf("after item_kill_tree: %d allocated\n", nr_allocated); |
55 | } | 56 | } |
56 | 57 | ||
@@ -319,10 +320,13 @@ static void single_check(void) | |||
319 | assert(ret == 0); | 320 | assert(ret == 0); |
320 | verify_tag_consistency(&tree, 0); | 321 | verify_tag_consistency(&tree, 0); |
321 | verify_tag_consistency(&tree, 1); | 322 | verify_tag_consistency(&tree, 1); |
322 | ret = radix_tree_range_tag_if_tagged(&tree, &first, 10, 10, 0, 1); | 323 | ret = tag_tagged_items(&tree, NULL, first, 10, 10, 0, 1); |
323 | assert(ret == 1); | 324 | assert(ret == 1); |
324 | ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 1); | 325 | ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 1); |
325 | assert(ret == 1); | 326 | assert(ret == 1); |
327 | item_tag_clear(&tree, 0, 0); | ||
328 | ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 0); | ||
329 | assert(ret == 0); | ||
326 | item_kill_tree(&tree); | 330 | item_kill_tree(&tree); |
327 | } | 331 | } |
328 | 332 | ||
@@ -331,12 +335,16 @@ void tag_check(void) | |||
331 | single_check(); | 335 | single_check(); |
332 | extend_checks(); | 336 | extend_checks(); |
333 | contract_checks(); | 337 | contract_checks(); |
338 | rcu_barrier(); | ||
334 | printf("after extend_checks: %d allocated\n", nr_allocated); | 339 | printf("after extend_checks: %d allocated\n", nr_allocated); |
335 | __leak_check(); | 340 | __leak_check(); |
336 | leak_check(); | 341 | leak_check(); |
342 | rcu_barrier(); | ||
337 | printf("after leak_check: %d allocated\n", nr_allocated); | 343 | printf("after leak_check: %d allocated\n", nr_allocated); |
338 | simple_checks(); | 344 | simple_checks(); |
345 | rcu_barrier(); | ||
339 | printf("after simple_checks: %d allocated\n", nr_allocated); | 346 | printf("after simple_checks: %d allocated\n", nr_allocated); |
340 | thrash_tags(); | 347 | thrash_tags(); |
348 | rcu_barrier(); | ||
341 | printf("after thrash_tags: %d allocated\n", nr_allocated); | 349 | printf("after thrash_tags: %d allocated\n", nr_allocated); |
342 | } | 350 | } |
diff --git a/tools/testing/radix-tree/test.c b/tools/testing/radix-tree/test.c index a6e8099eaf4f..e5726e373646 100644 --- a/tools/testing/radix-tree/test.c +++ b/tools/testing/radix-tree/test.c | |||
@@ -24,21 +24,29 @@ int item_tag_get(struct radix_tree_root *root, unsigned long index, int tag) | |||
24 | return radix_tree_tag_get(root, index, tag); | 24 | return radix_tree_tag_get(root, index, tag); |
25 | } | 25 | } |
26 | 26 | ||
27 | int __item_insert(struct radix_tree_root *root, struct item *item, | 27 | int __item_insert(struct radix_tree_root *root, struct item *item) |
28 | unsigned order) | ||
29 | { | 28 | { |
30 | return __radix_tree_insert(root, item->index, order, item); | 29 | return __radix_tree_insert(root, item->index, item->order, item); |
31 | } | 30 | } |
32 | 31 | ||
33 | int item_insert(struct radix_tree_root *root, unsigned long index) | 32 | int item_insert(struct radix_tree_root *root, unsigned long index) |
34 | { | 33 | { |
35 | return __item_insert(root, item_create(index), 0); | 34 | return __item_insert(root, item_create(index, 0)); |
36 | } | 35 | } |
37 | 36 | ||
38 | int item_insert_order(struct radix_tree_root *root, unsigned long index, | 37 | int item_insert_order(struct radix_tree_root *root, unsigned long index, |
39 | unsigned order) | 38 | unsigned order) |
40 | { | 39 | { |
41 | return __item_insert(root, item_create(index), order); | 40 | return __item_insert(root, item_create(index, order)); |
41 | } | ||
42 | |||
43 | void item_sanity(struct item *item, unsigned long index) | ||
44 | { | ||
45 | unsigned long mask; | ||
46 | assert(!radix_tree_is_internal_node(item)); | ||
47 | assert(item->order < BITS_PER_LONG); | ||
48 | mask = (1UL << item->order) - 1; | ||
49 | assert((item->index | mask) == (index | mask)); | ||
42 | } | 50 | } |
43 | 51 | ||
44 | int item_delete(struct radix_tree_root *root, unsigned long index) | 52 | int item_delete(struct radix_tree_root *root, unsigned long index) |
@@ -46,18 +54,19 @@ int item_delete(struct radix_tree_root *root, unsigned long index) | |||
46 | struct item *item = radix_tree_delete(root, index); | 54 | struct item *item = radix_tree_delete(root, index); |
47 | 55 | ||
48 | if (item) { | 56 | if (item) { |
49 | assert(item->index == index); | 57 | item_sanity(item, index); |
50 | free(item); | 58 | free(item); |
51 | return 1; | 59 | return 1; |
52 | } | 60 | } |
53 | return 0; | 61 | return 0; |
54 | } | 62 | } |
55 | 63 | ||
56 | struct item *item_create(unsigned long index) | 64 | struct item *item_create(unsigned long index, unsigned int order) |
57 | { | 65 | { |
58 | struct item *ret = malloc(sizeof(*ret)); | 66 | struct item *ret = malloc(sizeof(*ret)); |
59 | 67 | ||
60 | ret->index = index; | 68 | ret->index = index; |
69 | ret->order = order; | ||
61 | return ret; | 70 | return ret; |
62 | } | 71 | } |
63 | 72 | ||
@@ -66,8 +75,8 @@ void item_check_present(struct radix_tree_root *root, unsigned long index) | |||
66 | struct item *item; | 75 | struct item *item; |
67 | 76 | ||
68 | item = radix_tree_lookup(root, index); | 77 | item = radix_tree_lookup(root, index); |
69 | assert(item != 0); | 78 | assert(item != NULL); |
70 | assert(item->index == index); | 79 | item_sanity(item, index); |
71 | } | 80 | } |
72 | 81 | ||
73 | struct item *item_lookup(struct radix_tree_root *root, unsigned long index) | 82 | struct item *item_lookup(struct radix_tree_root *root, unsigned long index) |
@@ -80,7 +89,7 @@ void item_check_absent(struct radix_tree_root *root, unsigned long index) | |||
80 | struct item *item; | 89 | struct item *item; |
81 | 90 | ||
82 | item = radix_tree_lookup(root, index); | 91 | item = radix_tree_lookup(root, index); |
83 | assert(item == 0); | 92 | assert(item == NULL); |
84 | } | 93 | } |
85 | 94 | ||
86 | /* | 95 | /* |
@@ -142,6 +151,62 @@ void item_full_scan(struct radix_tree_root *root, unsigned long start, | |||
142 | assert(nfound == 0); | 151 | assert(nfound == 0); |
143 | } | 152 | } |
144 | 153 | ||
154 | /* Use the same pattern as tag_pages_for_writeback() in mm/page-writeback.c */ | ||
155 | int tag_tagged_items(struct radix_tree_root *root, pthread_mutex_t *lock, | ||
156 | unsigned long start, unsigned long end, unsigned batch, | ||
157 | unsigned iftag, unsigned thentag) | ||
158 | { | ||
159 | unsigned long tagged = 0; | ||
160 | struct radix_tree_iter iter; | ||
161 | void **slot; | ||
162 | |||
163 | if (batch == 0) | ||
164 | batch = 1; | ||
165 | |||
166 | if (lock) | ||
167 | pthread_mutex_lock(lock); | ||
168 | radix_tree_for_each_tagged(slot, root, &iter, start, iftag) { | ||
169 | if (iter.index > end) | ||
170 | break; | ||
171 | radix_tree_iter_tag_set(root, &iter, thentag); | ||
172 | tagged++; | ||
173 | if ((tagged % batch) != 0) | ||
174 | continue; | ||
175 | slot = radix_tree_iter_resume(slot, &iter); | ||
176 | if (lock) { | ||
177 | pthread_mutex_unlock(lock); | ||
178 | rcu_barrier(); | ||
179 | pthread_mutex_lock(lock); | ||
180 | } | ||
181 | } | ||
182 | if (lock) | ||
183 | pthread_mutex_unlock(lock); | ||
184 | |||
185 | return tagged; | ||
186 | } | ||
187 | |||
188 | /* Use the same pattern as find_swap_entry() in mm/shmem.c */ | ||
189 | unsigned long find_item(struct radix_tree_root *root, void *item) | ||
190 | { | ||
191 | struct radix_tree_iter iter; | ||
192 | void **slot; | ||
193 | unsigned long found = -1; | ||
194 | unsigned long checked = 0; | ||
195 | |||
196 | radix_tree_for_each_slot(slot, root, &iter, 0) { | ||
197 | if (*slot == item) { | ||
198 | found = iter.index; | ||
199 | break; | ||
200 | } | ||
201 | checked++; | ||
202 | if ((checked % 4) != 0) | ||
203 | continue; | ||
204 | slot = radix_tree_iter_resume(slot, &iter); | ||
205 | } | ||
206 | |||
207 | return found; | ||
208 | } | ||
209 | |||
145 | static int verify_node(struct radix_tree_node *slot, unsigned int tag, | 210 | static int verify_node(struct radix_tree_node *slot, unsigned int tag, |
146 | int tagged) | 211 | int tagged) |
147 | { | 212 | { |
@@ -200,9 +265,16 @@ void verify_tag_consistency(struct radix_tree_root *root, unsigned int tag) | |||
200 | 265 | ||
201 | void item_kill_tree(struct radix_tree_root *root) | 266 | void item_kill_tree(struct radix_tree_root *root) |
202 | { | 267 | { |
268 | struct radix_tree_iter iter; | ||
269 | void **slot; | ||
203 | struct item *items[32]; | 270 | struct item *items[32]; |
204 | int nfound; | 271 | int nfound; |
205 | 272 | ||
273 | radix_tree_for_each_slot(slot, root, &iter, 0) { | ||
274 | if (radix_tree_exceptional_entry(*slot)) | ||
275 | radix_tree_delete(root, iter.index); | ||
276 | } | ||
277 | |||
206 | while ((nfound = radix_tree_gang_lookup(root, (void **)items, 0, 32))) { | 278 | while ((nfound = radix_tree_gang_lookup(root, (void **)items, 0, 32))) { |
207 | int i; | 279 | int i; |
208 | 280 | ||
diff --git a/tools/testing/radix-tree/test.h b/tools/testing/radix-tree/test.h index 217fb2403f09..056a23b56467 100644 --- a/tools/testing/radix-tree/test.h +++ b/tools/testing/radix-tree/test.h | |||
@@ -5,11 +5,11 @@ | |||
5 | 5 | ||
6 | struct item { | 6 | struct item { |
7 | unsigned long index; | 7 | unsigned long index; |
8 | unsigned int order; | ||
8 | }; | 9 | }; |
9 | 10 | ||
10 | struct item *item_create(unsigned long index); | 11 | struct item *item_create(unsigned long index, unsigned int order); |
11 | int __item_insert(struct radix_tree_root *root, struct item *item, | 12 | int __item_insert(struct radix_tree_root *root, struct item *item); |
12 | unsigned order); | ||
13 | int item_insert(struct radix_tree_root *root, unsigned long index); | 13 | int item_insert(struct radix_tree_root *root, unsigned long index); |
14 | int item_insert_order(struct radix_tree_root *root, unsigned long index, | 14 | int item_insert_order(struct radix_tree_root *root, unsigned long index, |
15 | unsigned order); | 15 | unsigned order); |
@@ -25,9 +25,15 @@ void item_full_scan(struct radix_tree_root *root, unsigned long start, | |||
25 | unsigned long nr, int chunk); | 25 | unsigned long nr, int chunk); |
26 | void item_kill_tree(struct radix_tree_root *root); | 26 | void item_kill_tree(struct radix_tree_root *root); |
27 | 27 | ||
28 | int tag_tagged_items(struct radix_tree_root *, pthread_mutex_t *, | ||
29 | unsigned long start, unsigned long end, unsigned batch, | ||
30 | unsigned iftag, unsigned thentag); | ||
31 | unsigned long find_item(struct radix_tree_root *, void *item); | ||
32 | |||
28 | void tag_check(void); | 33 | void tag_check(void); |
29 | void multiorder_checks(void); | 34 | void multiorder_checks(void); |
30 | void iteration_test(void); | 35 | void iteration_test(unsigned order, unsigned duration); |
36 | void benchmark(void); | ||
31 | 37 | ||
32 | struct item * | 38 | struct item * |
33 | item_tag_set(struct radix_tree_root *root, unsigned long index, int tag); | 39 | item_tag_set(struct radix_tree_root *root, unsigned long index, int tag); |
@@ -40,7 +46,14 @@ void verify_tag_consistency(struct radix_tree_root *root, unsigned int tag); | |||
40 | extern int nr_allocated; | 46 | extern int nr_allocated; |
41 | 47 | ||
42 | /* Normally private parts of lib/radix-tree.c */ | 48 | /* Normally private parts of lib/radix-tree.c */ |
49 | struct radix_tree_node *entry_to_node(void *ptr); | ||
43 | void radix_tree_dump(struct radix_tree_root *root); | 50 | void radix_tree_dump(struct radix_tree_root *root); |
44 | int root_tag_get(struct radix_tree_root *root, unsigned int tag); | 51 | int root_tag_get(struct radix_tree_root *root, unsigned int tag); |
45 | unsigned long node_maxindex(struct radix_tree_node *); | 52 | unsigned long node_maxindex(struct radix_tree_node *); |
46 | unsigned long shift_maxindex(unsigned int shift); | 53 | unsigned long shift_maxindex(unsigned int shift); |
54 | int radix_tree_cpu_dead(unsigned int cpu); | ||
55 | struct radix_tree_preload { | ||
56 | unsigned nr; | ||
57 | struct radix_tree_node *nodes; | ||
58 | }; | ||
59 | extern struct radix_tree_preload radix_tree_preloads; | ||