diff options
Diffstat (limited to 'lib/idr.c')
-rw-r--r-- | lib/idr.c | 48 |
1 files changed, 47 insertions, 1 deletions
diff --git a/lib/idr.c b/lib/idr.c index c11c5765cdef..80ca9aca038b 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -449,6 +449,7 @@ void idr_remove_all(struct idr *idp) n = idp->layers * IDR_BITS; p = idp->top; + rcu_assign_pointer(idp->top, NULL); max = 1 << n; id = 0; @@ -467,7 +468,6 @@ void idr_remove_all(struct idr *idp) p = *--paa; } } - rcu_assign_pointer(idp->top, NULL); idp->layers = 0; } EXPORT_SYMBOL(idr_remove_all); @@ -579,6 +579,52 @@ int idr_for_each(struct idr *idp, EXPORT_SYMBOL(idr_for_each); /** + * idr_get_next - lookup next object of id to given id. + * @idp: idr handle + * @id: pointer to lookup key + * + * Returns pointer to registered object with id, which is next number to + * given id. + */ + +void *idr_get_next(struct idr *idp, int *nextidp) +{ + struct idr_layer *p, *pa[MAX_LEVEL]; + struct idr_layer **paa = &pa[0]; + int id = *nextidp; + int n, max; + + /* find first ent */ + n = idp->layers * IDR_BITS; + max = 1 << n; + p = rcu_dereference(idp->top); + if (!p) + return NULL; + + while (id < max) { + while (n > 0 && p) { + n -= IDR_BITS; + *paa++ = p; + p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]); + } + + if (p) { + *nextidp = id; + return p; + } + + id += 1 << n; + while (n < fls(id)) { + n += IDR_BITS; + p = *--paa; + } + } + return NULL; +} + + + +/** * idr_replace - replace pointer for given id * @idp: idr handle * @ptr: pointer you want associated with the id |