diff options
author | Matthew Wilcox (Oracle) <willy@infradead.org> | 2019-11-01 21:36:39 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-12-17 20:36:02 +0100 |
commit | 0cec640db89bfbb2d01d7ea9fe33bbab696ee595 (patch) | |
tree | 2d814b25c843e949369f284df324939a24c039fa | |
parent | 052d878cc2d138e350ee13ce5e6ad4c8309928bb (diff) | |
download | linux-stable-0cec640db89bfbb2d01d7ea9fe33bbab696ee595.tar.gz linux-stable-0cec640db89bfbb2d01d7ea9fe33bbab696ee595.tar.bz2 linux-stable-0cec640db89bfbb2d01d7ea9fe33bbab696ee595.zip |
idr: Fix idr_get_next_ul race with idr_remove
[ Upstream commit 5a74ac4c4a97bd8b7dba054304d598e2a882fea6 ]
Commit 5c089fd0c734 ("idr: Fix idr_get_next race with idr_remove")
neglected to fix idr_get_next_ul(). As far as I can tell, nobody's
actually using this interface under the RCU read lock, but fix it now
before anybody decides to use it.
Fixes: 5c089fd0c734 ("idr: Fix idr_get_next race with idr_remove")
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r-- | lib/idr.c | 31 |
1 files changed, 11 insertions, 20 deletions
diff --git a/lib/idr.c b/lib/idr.c index 61383564a6c5..6ff3b1c36e0a 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -218,7 +218,7 @@ int idr_for_each(const struct idr *idr, EXPORT_SYMBOL(idr_for_each); /** - * idr_get_next() - Find next populated entry. + * idr_get_next_ul() - Find next populated entry. * @idr: IDR handle. * @nextid: Pointer to an ID. * @@ -227,7 +227,7 @@ EXPORT_SYMBOL(idr_for_each); * to the ID of the found value. To use in a loop, the value pointed to by * nextid must be incremented by the user. */ -void *idr_get_next(struct idr *idr, int *nextid) +void *idr_get_next_ul(struct idr *idr, unsigned long *nextid) { struct radix_tree_iter iter; void __rcu **slot; @@ -249,18 +249,14 @@ void *idr_get_next(struct idr *idr, int *nextid) } if (!slot) return NULL; - id = iter.index + base; - - if (WARN_ON_ONCE(id > INT_MAX)) - return NULL; - *nextid = id; + *nextid = iter.index + base; return entry; } -EXPORT_SYMBOL(idr_get_next); +EXPORT_SYMBOL(idr_get_next_ul); /** - * idr_get_next_ul() - Find next populated entry. + * idr_get_next() - Find next populated entry. * @idr: IDR handle. * @nextid: Pointer to an ID. * @@ -269,22 +265,17 @@ EXPORT_SYMBOL(idr_get_next); * to the ID of the found value. To use in a loop, the value pointed to by * nextid must be incremented by the user. */ -void *idr_get_next_ul(struct idr *idr, unsigned long *nextid) +void *idr_get_next(struct idr *idr, int *nextid) { - struct radix_tree_iter iter; - void __rcu **slot; - unsigned long base = idr->idr_base; unsigned long id = *nextid; + void *entry = idr_get_next_ul(idr, &id); - id = (id < base) ? 0 : id - base; - slot = radix_tree_iter_find(&idr->idr_rt, &iter, id); - if (!slot) + if (WARN_ON_ONCE(id > INT_MAX)) return NULL; - - *nextid = iter.index + base; - return rcu_dereference_raw(*slot); + *nextid = id; + return entry; } -EXPORT_SYMBOL(idr_get_next_ul); +EXPORT_SYMBOL(idr_get_next); /** * idr_replace() - replace pointer for given ID. |