diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/idr.c | 70 |
1 files changed, 61 insertions, 9 deletions
| @@ -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) | |||
| 136 | EXPORT_SYMBOL(idr_alloc_cyclic); | 139 | EXPORT_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 | */ | ||
| 155 | void *idr_remove(struct idr *idr, unsigned long id) | ||
| 156 | { | ||
| 157 | return radix_tree_delete_item(&idr->idr_rt, id - idr->idr_base, NULL); | ||
| 158 | } | ||
| 159 | EXPORT_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 | */ | ||
| 175 | void *idr_find(const struct idr *idr, unsigned long id) | ||
| 176 | { | ||
| 177 | return radix_tree_lookup(&idr->idr_rt, id - idr->idr_base); | ||
| 178 | } | ||
| 179 | EXPORT_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 | } |
| 200 | EXPORT_SYMBOL(idr_get_next); | 248 | EXPORT_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 | } |
| 224 | EXPORT_SYMBOL(idr_get_next_ul); | 275 | EXPORT_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)) |
