forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
radix tree: Don't return retry entries from lookup
Commit 66ee620 ("idr: Permit any valid kernel pointer to be stored") changed the radix tree lookup so that it stops when reaching the bottom of the tree. However, the condition was added in the wrong place, making it possible to return retry entries to the caller. Reorder the tests to check for the retry entry before checking whether we're at the bottom of the tree. The retry entry should never be found in the tree root, so it's safe to defer the check until the end of the loop. Add a regression test to the test-suite to be sure this doesn't come back. Fixes: 66ee620 ("idr: Permit any valid kernel pointer to be stored") Reported-by: Greg Kurz <[email protected]> Signed-off-by: Matthew Wilcox <[email protected]>
- Loading branch information
Matthew Wilcox
committed
Dec 6, 2018
1 parent
cf76c36
commit eff3860
Showing
5 changed files
with
84 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
#include <linux/kernel.h> | ||
#include <linux/gfp.h> | ||
#include <linux/slab.h> | ||
#include <linux/radix-tree.h> | ||
#include <linux/rcupdate.h> | ||
#include <stdlib.h> | ||
#include <pthread.h> | ||
#include <stdio.h> | ||
#include <assert.h> | ||
|
||
#include "regression.h" | ||
|
||
static pthread_barrier_t worker_barrier; | ||
static int obj0, obj1; | ||
static RADIX_TREE(mt_tree, GFP_KERNEL); | ||
|
||
static void *reader_fn(void *arg) | ||
{ | ||
int i; | ||
void *entry; | ||
|
||
rcu_register_thread(); | ||
pthread_barrier_wait(&worker_barrier); | ||
|
||
for (i = 0; i < 1000000; i++) { | ||
rcu_read_lock(); | ||
entry = radix_tree_lookup(&mt_tree, 0); | ||
rcu_read_unlock(); | ||
if (entry != &obj0) { | ||
printf("iteration %d bad entry = %p\n", i, entry); | ||
abort(); | ||
} | ||
} | ||
|
||
rcu_unregister_thread(); | ||
|
||
return NULL; | ||
} | ||
|
||
static void *writer_fn(void *arg) | ||
{ | ||
int i; | ||
|
||
rcu_register_thread(); | ||
pthread_barrier_wait(&worker_barrier); | ||
|
||
for (i = 0; i < 1000000; i++) { | ||
radix_tree_insert(&mt_tree, 1, &obj1); | ||
radix_tree_delete(&mt_tree, 1); | ||
} | ||
|
||
rcu_unregister_thread(); | ||
|
||
return NULL; | ||
} | ||
|
||
void regression4_test(void) | ||
{ | ||
pthread_t reader, writer; | ||
|
||
printv(1, "regression test 4 starting\n"); | ||
|
||
radix_tree_insert(&mt_tree, 0, &obj0); | ||
pthread_barrier_init(&worker_barrier, NULL, 2); | ||
|
||
if (pthread_create(&reader, NULL, reader_fn, NULL) || | ||
pthread_create(&writer, NULL, writer_fn, NULL)) { | ||
perror("pthread_create"); | ||
exit(1); | ||
} | ||
|
||
if (pthread_join(reader, NULL) || pthread_join(writer, NULL)) { | ||
perror("pthread_join"); | ||
exit(1); | ||
} | ||
|
||
printv(1, "regression test 4 passed\n"); | ||
} |