aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/idr.c70
1 files changed, 61 insertions, 9 deletions
diff --git a/lib/idr.c b/lib/idr.c
index b47055efceb0..c98d77fcf393 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -36,18 +36,21 @@ int idr_alloc_u32(struct idr *idr, void *ptr, u32 *nextid,
36{ 36{
37 struct radix_tree_iter iter; 37 struct radix_tree_iter iter;
38 void __rcu **slot; 38 void __rcu **slot;
39 int base = idr->idr_base;
40 int id = *nextid;
39 41
40 if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr))) 42 if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr)))
41 return -EINVAL; 43 return -EINVAL;
42 if (WARN_ON_ONCE(!(idr->idr_rt.gfp_mask & ROOT_IS_IDR))) 44 if (WARN_ON_ONCE(!(idr->idr_rt.gfp_mask & ROOT_IS_IDR)))
43 idr->idr_rt.gfp_mask |= IDR_RT_MARKER; 45 idr->idr_rt.gfp_mask |= IDR_RT_MARKER;
44 46
45 radix_tree_iter_init(&iter, *nextid); 47 id = (id < base) ? 0 : id - base;
46 slot = idr_get_free(&idr->idr_rt, &iter, gfp, max); 48 radix_tree_iter_init(&iter, id);
49 slot = idr_get_free(&idr->idr_rt, &iter, gfp, max - base);
47 if (IS_ERR(slot)) 50 if (IS_ERR(slot))
48 return PTR_ERR(slot); 51 return PTR_ERR(slot);
49 52
50 *nextid = iter.index; 53 *nextid = iter.index + base;
51 /* there is a memory barrier inside radix_tree_iter_replace() */ 54 /* there is a memory barrier inside radix_tree_iter_replace() */
52 radix_tree_iter_replace(&idr->idr_rt, &iter, slot, ptr); 55 radix_tree_iter_replace(&idr->idr_rt, &iter, slot, ptr);
53 radix_tree_iter_tag_clear(&idr->idr_rt, &iter, IDR_FREE); 56 radix_tree_iter_tag_clear(&idr->idr_rt, &iter, IDR_FREE);
@@ -136,6 +139,46 @@ int idr_alloc_cyclic(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
136EXPORT_SYMBOL(idr_alloc_cyclic); 139EXPORT_SYMBOL(idr_alloc_cyclic);
137 140
138/** 141/**
142 * idr_remove() - Remove an ID from the IDR.
143 * @idr: IDR handle.
144 * @id: Pointer ID.
145 *
146 * Removes this ID from the IDR. If the ID was not previously in the IDR,
147 * this function returns %NULL.
148 *
149 * Since this function modifies the IDR, the caller should provide their
150 * own locking to ensure that concurrent modification of the same IDR is
151 * not possible.
152 *
153 * Return: The pointer formerly associated with this ID.
154 */
155void *idr_remove(struct idr *idr, unsigned long id)
156{
157 return radix_tree_delete_item(&idr->idr_rt, id - idr->idr_base, NULL);
158}
159EXPORT_SYMBOL_GPL(idr_remove);
160
161/**
162 * idr_find() - Return pointer for given ID.
163 * @idr: IDR handle.
164 * @id: Pointer ID.
165 *
166 * Looks up the pointer associated with this ID. A %NULL pointer may
167 * indicate that @id is not allocated or that the %NULL pointer was
168 * associated with this ID.
169 *
170 * This function can be called under rcu_read_lock(), given that the leaf
171 * pointers lifetimes are correctly managed.
172 *
173 * Return: The pointer associated with this ID.
174 */
175void *idr_find(const struct idr *idr, unsigned long id)
176{
177 return radix_tree_lookup(&idr->idr_rt, id - idr->idr_base);
178}
179EXPORT_SYMBOL_GPL(idr_find);
180
181/**
139 * idr_for_each() - Iterate through all stored pointers. 182 * idr_for_each() - Iterate through all stored pointers.
140 * @idr: IDR handle. 183 * @idr: IDR handle.
141 * @fn: Function to be called for each pointer. 184 * @fn: Function to be called for each pointer.
@@ -157,13 +200,14 @@ int idr_for_each(const struct idr *idr,
157{ 200{
158 struct radix_tree_iter iter; 201 struct radix_tree_iter iter;
159 void __rcu **slot; 202 void __rcu **slot;
203 int base = idr->idr_base;
160 204
161 radix_tree_for_each_slot(slot, &idr->idr_rt, &iter, 0) { 205 radix_tree_for_each_slot(slot, &idr->idr_rt, &iter, 0) {
162 int ret; 206 int ret;
163 207
164 if (WARN_ON_ONCE(iter.index > INT_MAX)) 208 if (WARN_ON_ONCE(iter.index > INT_MAX))
165 break; 209 break;
166 ret = fn(iter.index, rcu_dereference_raw(*slot), data); 210 ret = fn(iter.index + base, rcu_dereference_raw(*slot), data);
167 if (ret) 211 if (ret)
168 return ret; 212 return ret;
169 } 213 }
@@ -186,15 +230,19 @@ void *idr_get_next(struct idr *idr, int *nextid)
186{ 230{
187 struct radix_tree_iter iter; 231 struct radix_tree_iter iter;
188 void __rcu **slot; 232 void __rcu **slot;
233 int base = idr->idr_base;
234 int id = *nextid;
189 235
190 slot = radix_tree_iter_find(&idr->idr_rt, &iter, *nextid); 236 id = (id < base) ? 0 : id - base;
237 slot = radix_tree_iter_find(&idr->idr_rt, &iter, id);
191 if (!slot) 238 if (!slot)
192 return NULL; 239 return NULL;
240 id = iter.index + base;
193 241
194 if (WARN_ON_ONCE(iter.index > INT_MAX)) 242 if (WARN_ON_ONCE(id > INT_MAX))
195 return NULL; 243 return NULL;
196 244
197 *nextid = iter.index; 245 *nextid = id;
198 return rcu_dereference_raw(*slot); 246 return rcu_dereference_raw(*slot);
199} 247}
200EXPORT_SYMBOL(idr_get_next); 248EXPORT_SYMBOL(idr_get_next);
@@ -213,12 +261,15 @@ void *idr_get_next_ul(struct idr *idr, unsigned long *nextid)
213{ 261{
214 struct radix_tree_iter iter; 262 struct radix_tree_iter iter;
215 void __rcu **slot; 263 void __rcu **slot;
264 unsigned long base = idr->idr_base;
265 unsigned long id = *nextid;
216 266
217 slot = radix_tree_iter_find(&idr->idr_rt, &iter, *nextid); 267 id = (id < base) ? 0 : id - base;
268 slot = radix_tree_iter_find(&idr->idr_rt, &iter, id);
218 if (!slot) 269 if (!slot)
219 return NULL; 270 return NULL;
220 271
221 *nextid = iter.index; 272 *nextid = iter.index + base;
222 return rcu_dereference_raw(*slot); 273 return rcu_dereference_raw(*slot);
223} 274}
224EXPORT_SYMBOL(idr_get_next_ul); 275EXPORT_SYMBOL(idr_get_next_ul);
@@ -245,6 +296,7 @@ void *idr_replace(struct idr *idr, void *ptr, unsigned long id)
245 296
246 if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr))) 297 if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr)))
247 return ERR_PTR(-EINVAL); 298 return ERR_PTR(-EINVAL);
299 id -= idr->idr_base;
248 300
249 entry = __radix_tree_lookup(&idr->idr_rt, id, &node, &slot); 301 entry = __radix_tree_lookup(&idr->idr_rt, id, &node, &slot);
250 if (!slot || radix_tree_tag_get(&idr->idr_rt, id, IDR_FREE)) 302 if (!slot || radix_tree_tag_get(&idr->idr_rt, id, IDR_FREE))