idr: Fix idr_get_next_ul race with idr_remove
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Sat, 2 Nov 2019 01:36:39 +0000 (21:36 -0400)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Sat, 2 Nov 2019 02:26:34 +0000 (22:26 -0400)
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>
lib/idr.c

index 66a3748924828dcf4be6f3ffb06ef4a785600f7d..c2cf2c52bbde5c54534b2227cee2176baf78383a 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -215,7 +215,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.
  *
@@ -224,7 +224,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;
@@ -245,18 +245,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.
  *
@@ -265,22 +261,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.