From 50d97d50715a8664f6bddc18211279cd74b8c3bf Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Thu, 21 Jun 2018 15:36:45 -0400 Subject: ida: Lock the IDA in ida_destroy The user has no need to handle locking between ida_simple_get() and ida_simple_remove(). They shouldn't be forced to think about whether ida_destroy() might be called at the same time as any of their other IDA manipulation calls. Improve the documnetation while I'm in here. Signed-off-by: Matthew Wilcox --- lib/idr.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'lib/idr.c') diff --git a/lib/idr.c b/lib/idr.c index ed9c169c12bd..352c6160e2e0 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -523,25 +523,30 @@ void ida_remove(struct ida *ida, int id) EXPORT_SYMBOL(ida_remove); /** - * ida_destroy - Free the contents of an ida - * @ida: ida handle + * ida_destroy() - Free all IDs. + * @ida: IDA handle. + * + * Calling this function frees all IDs and releases all resources used + * by an IDA. When this call returns, the IDA is empty and can be reused + * or freed. If the IDA is already empty, there is no need to call this + * function. * - * Calling this function releases all resources associated with an IDA. When - * this call returns, the IDA is empty and can be reused or freed. The caller - * should not allow ida_remove() or ida_get_new_above() to be called at the - * same time. + * Context: Any context. */ void ida_destroy(struct ida *ida) { + unsigned long flags; struct radix_tree_iter iter; void __rcu **slot; + xa_lock_irqsave(&ida->ida_rt, flags); radix_tree_for_each_slot(slot, &ida->ida_rt, &iter, 0) { struct ida_bitmap *bitmap = rcu_dereference_raw(*slot); if (!radix_tree_exception(bitmap)) kfree(bitmap); radix_tree_iter_delete(&ida->ida_rt, &iter, slot); } + xa_unlock_irqrestore(&ida->ida_rt, flags); } EXPORT_SYMBOL(ida_destroy); -- cgit v1.2.3 From 5ade60dda43c8906d4554374226c2eb11cc2ffba Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 20 Mar 2018 17:07:11 -0400 Subject: ida: Add new API Add ida_alloc(), ida_alloc_min(), ida_alloc_max(), ida_alloc_range() and ida_free(). The ida_alloc_max() and ida_alloc_range() functions differ from ida_simple_get() in that they take an inclusive 'max' parameter instead of an exclusive 'end' parameter. Callers are about evenly split whether they'd like inclusive or exclusive parameters and 'max' is easier to document than 'end'. Change the IDA allocation to first attempt to allocate a bit using existing memory, and only allocate memory afterwards. Also change the behaviour of 'min' > INT_MAX from being a BUG() to returning -ENOSPC. Leave compatibility wrappers in place for ida_simple_get() and ida_simple_remove() to avoid changing all callers. Signed-off-by: Matthew Wilcox --- include/linux/idr.h | 59 +++++++++++++++++++++++++++++++++++++++++--- lib/idr.c | 70 ++++++++++++++++++++++++----------------------------- 2 files changed, 87 insertions(+), 42 deletions(-) (limited to 'lib/idr.c') diff --git a/include/linux/idr.h b/include/linux/idr.h index e856f4e0ab35..cd339da0b1aa 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h @@ -230,15 +230,68 @@ int ida_get_new_above(struct ida *ida, int starting_id, int *p_id); void ida_remove(struct ida *ida, int id); void ida_destroy(struct ida *ida); -int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, - gfp_t gfp_mask); -void ida_simple_remove(struct ida *ida, unsigned int id); +int ida_alloc_range(struct ida *, unsigned int min, unsigned int max, gfp_t); +void ida_free(struct ida *, unsigned int id); + +/** + * ida_alloc() - Allocate an unused ID. + * @ida: IDA handle. + * @gfp: Memory allocation flags. + * + * Allocate an ID between 0 and %INT_MAX, inclusive. + * + * Context: Any context. + * Return: The allocated ID, or %-ENOMEM if memory could not be allocated, + * or %-ENOSPC if there are no free IDs. + */ +static inline int ida_alloc(struct ida *ida, gfp_t gfp) +{ + return ida_alloc_range(ida, 0, ~0, gfp); +} + +/** + * ida_alloc_min() - Allocate an unused ID. + * @ida: IDA handle. + * @min: Lowest ID to allocate. + * @gfp: Memory allocation flags. + * + * Allocate an ID between @min and %INT_MAX, inclusive. + * + * Context: Any context. + * Return: The allocated ID, or %-ENOMEM if memory could not be allocated, + * or %-ENOSPC if there are no free IDs. + */ +static inline int ida_alloc_min(struct ida *ida, unsigned int min, gfp_t gfp) +{ + return ida_alloc_range(ida, min, ~0, gfp); +} + +/** + * ida_alloc_max() - Allocate an unused ID. + * @ida: IDA handle. + * @max: Highest ID to allocate. + * @gfp: Memory allocation flags. + * + * Allocate an ID between 0 and @max, inclusive. + * + * Context: Any context. + * Return: The allocated ID, or %-ENOMEM if memory could not be allocated, + * or %-ENOSPC if there are no free IDs. + */ +static inline int ida_alloc_max(struct ida *ida, unsigned int max, gfp_t gfp) +{ + return ida_alloc_range(ida, 0, max, gfp); +} static inline void ida_init(struct ida *ida) { INIT_RADIX_TREE(&ida->ida_rt, IDR_RT_MARKER | GFP_NOWAIT); } +#define ida_simple_get(ida, start, end, gfp) \ + ida_alloc_range(ida, start, (end) - 1, gfp) +#define ida_simple_remove(ida, id) ida_free(ida, id) + /** * ida_get_new - allocate new ID * @ida: idr handle diff --git a/lib/idr.c b/lib/idr.c index 352c6160e2e0..760fce92f1fb 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -317,7 +317,8 @@ EXPORT_SYMBOL(idr_replace); * bit per ID, and so is more space efficient than an IDR. To use an IDA, * define it using DEFINE_IDA() (or embed a &struct ida in a data structure, * then initialise it using ida_init()). To allocate a new ID, call - * ida_simple_get(). To free an ID, call ida_simple_remove(). + * ida_alloc(), ida_alloc_min(), ida_alloc_max() or ida_alloc_range(). + * To free an ID, call ida_free(). * * If you have more complex locking requirements, use a loop around * ida_pre_get() and ida_get_new() to allocate a new ID. Then use @@ -378,7 +379,7 @@ EXPORT_SYMBOL(idr_replace); * Allocate new ID above or equal to @start. It should be called * with any required locks to ensure that concurrent calls to * ida_get_new_above() / ida_get_new() / ida_remove() are not allowed. - * Consider using ida_simple_get() if you do not have complex locking + * Consider using ida_alloc_range() if you do not have complex locking * requirements. * * If memory is required, it will return %-EAGAIN, you should unlock @@ -551,43 +552,34 @@ void ida_destroy(struct ida *ida) EXPORT_SYMBOL(ida_destroy); /** - * ida_simple_get - get a new id. - * @ida: the (initialized) ida. - * @start: the minimum id (inclusive, < 0x8000000) - * @end: the maximum id (exclusive, < 0x8000000 or 0) - * @gfp_mask: memory allocation flags - * - * Allocates an id in the range start <= id < end, or returns -ENOSPC. - * On memory allocation failure, returns -ENOMEM. + * ida_alloc_range() - Allocate an unused ID. + * @ida: IDA handle. + * @min: Lowest ID to allocate. + * @max: Highest ID to allocate. + * @gfp: Memory allocation flags. * - * Compared to ida_get_new_above() this function does its own locking, and - * should be used unless there are special requirements. + * Allocate an ID between @min and @max, inclusive. The allocated ID will + * not exceed %INT_MAX, even if @max is larger. * - * Use ida_simple_remove() to get rid of an id. + * Context: Any context. + * Return: The allocated ID, or %-ENOMEM if memory could not be allocated, + * or %-ENOSPC if there are no free IDs. */ -int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, - gfp_t gfp_mask) +int ida_alloc_range(struct ida *ida, unsigned int min, unsigned int max, + gfp_t gfp) { int ret, id; - unsigned int max; unsigned long flags; - BUG_ON((int)start < 0); - BUG_ON((int)end < 0); + if ((int)min < 0) + return -ENOSPC; - if (end == 0) - max = 0x80000000; - else { - BUG_ON(end < start); - max = end - 1; - } + if ((int)max < 0) + max = INT_MAX; again: - if (!ida_pre_get(ida, gfp_mask)) - return -ENOMEM; - xa_lock_irqsave(&ida->ida_rt, flags); - ret = ida_get_new_above(ida, start, &id); + ret = ida_get_new_above(ida, min, &id); if (!ret) { if (id > max) { ida_remove(ida, id); @@ -598,24 +590,24 @@ again: } xa_unlock_irqrestore(&ida->ida_rt, flags); - if (unlikely(ret == -EAGAIN)) + if (unlikely(ret == -EAGAIN)) { + if (!ida_pre_get(ida, gfp)) + return -ENOMEM; goto again; + } return ret; } -EXPORT_SYMBOL(ida_simple_get); +EXPORT_SYMBOL(ida_alloc_range); /** - * ida_simple_remove - remove an allocated id. - * @ida: the (initialized) ida. - * @id: the id returned by ida_simple_get. - * - * Use to release an id allocated with ida_simple_get(). + * ida_free() - Release an allocated ID. + * @ida: IDA handle. + * @id: Previously allocated ID. * - * Compared to ida_remove() this function does its own locking, and should be - * used unless there are special requirements. + * Context: Any context. */ -void ida_simple_remove(struct ida *ida, unsigned int id) +void ida_free(struct ida *ida, unsigned int id) { unsigned long flags; @@ -624,4 +616,4 @@ void ida_simple_remove(struct ida *ida, unsigned int id) ida_remove(ida, id); xa_unlock_irqrestore(&ida->ida_rt, flags); } -EXPORT_SYMBOL(ida_simple_remove); +EXPORT_SYMBOL(ida_free); -- cgit v1.2.3 From b03f8e43c9261878bf29d8cc1c3ba458cc98287e Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 18 Jun 2018 19:02:48 -0400 Subject: ida: Remove old API Delete ida_pre_get(), ida_get_new(), ida_get_new_above() and ida_remove() from the public API. Some of these functions still exist as internal helpers, but they should not be called by consumers. Signed-off-by: Matthew Wilcox --- include/linux/idr.h | 21 ++++----------------- lib/idr.c | 48 +++++++----------------------------------------- lib/radix-tree.c | 9 --------- 3 files changed, 11 insertions(+), 67 deletions(-) (limited to 'lib/idr.c') diff --git a/include/linux/idr.h b/include/linux/idr.h index cd339da0b1aa..2e1db0e36486 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h @@ -225,13 +225,9 @@ struct ida { } #define DEFINE_IDA(name) struct ida name = IDA_INIT(name) -int ida_pre_get(struct ida *ida, gfp_t gfp_mask); -int ida_get_new_above(struct ida *ida, int starting_id, int *p_id); -void ida_remove(struct ida *ida, int id); -void ida_destroy(struct ida *ida); - int ida_alloc_range(struct ida *, unsigned int min, unsigned int max, gfp_t); void ida_free(struct ida *, unsigned int id); +void ida_destroy(struct ida *ida); /** * ida_alloc() - Allocate an unused ID. @@ -292,20 +288,11 @@ static inline void ida_init(struct ida *ida) ida_alloc_range(ida, start, (end) - 1, gfp) #define ida_simple_remove(ida, id) ida_free(ida, id) -/** - * ida_get_new - allocate new ID - * @ida: idr handle - * @p_id: pointer to the allocated handle - * - * Simple wrapper around ida_get_new_above() w/ @starting_id of zero. - */ -static inline int ida_get_new(struct ida *ida, int *p_id) -{ - return ida_get_new_above(ida, 0, p_id); -} - static inline bool ida_is_empty(const struct ida *ida) { return radix_tree_empty(&ida->ida_rt); } + +/* in lib/radix-tree.c */ +int ida_pre_get(struct ida *ida, gfp_t gfp_mask); #endif /* __IDR_H__ */ diff --git a/lib/idr.c b/lib/idr.c index 760fce92f1fb..1dc52191acb6 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -320,16 +320,9 @@ EXPORT_SYMBOL(idr_replace); * ida_alloc(), ida_alloc_min(), ida_alloc_max() or ida_alloc_range(). * To free an ID, call ida_free(). * - * If you have more complex locking requirements, use a loop around - * ida_pre_get() and ida_get_new() to allocate a new ID. Then use - * ida_remove() to free an ID. You must make sure that ida_get_new() and - * ida_remove() cannot be called at the same time as each other for the - * same IDA. - * - * You can also use ida_get_new_above() if you need an ID to be allocated - * above a particular number. ida_destroy() can be used to dispose of an - * IDA without needing to free the individual IDs in it. You can use - * ida_is_empty() to find out whether the IDA has any IDs currently allocated. + * ida_destroy() can be used to dispose of an IDA without needing to + * free the individual IDs in it. You can use ida_is_empty() to find + * out whether the IDA has any IDs currently allocated. * * IDs are currently limited to the range [0-INT_MAX]. If this is an awkward * limitation, it should be quite straightforward to raise the maximum. @@ -370,25 +363,7 @@ EXPORT_SYMBOL(idr_replace); #define IDA_MAX (0x80000000U / IDA_BITMAP_BITS - 1) -/** - * ida_get_new_above - allocate new ID above or equal to a start id - * @ida: ida handle - * @start: id to start search at - * @id: pointer to the allocated handle - * - * Allocate new ID above or equal to @start. It should be called - * with any required locks to ensure that concurrent calls to - * ida_get_new_above() / ida_get_new() / ida_remove() are not allowed. - * Consider using ida_alloc_range() if you do not have complex locking - * requirements. - * - * If memory is required, it will return %-EAGAIN, you should unlock - * and go back to the ida_pre_get() call. If the ida is full, it will - * return %-ENOSPC. On success, it will return 0. - * - * @id returns a value in the range @start ... %0x7fffffff. - */ -int ida_get_new_above(struct ida *ida, int start, int *id) +static int ida_get_new_above(struct ida *ida, int start, int *id) { struct radix_tree_root *root = &ida->ida_rt; void __rcu **slot; @@ -473,16 +448,8 @@ int ida_get_new_above(struct ida *ida, int start, int *id) return 0; } } -EXPORT_SYMBOL(ida_get_new_above); -/** - * ida_remove - Free the given ID - * @ida: ida handle - * @id: ID to free - * - * This function should not be called at the same time as ida_get_new_above(). - */ -void ida_remove(struct ida *ida, int id) +static void ida_remove(struct ida *ida, int id) { unsigned long index = id / IDA_BITMAP_BITS; unsigned offset = id % IDA_BITMAP_BITS; @@ -519,9 +486,8 @@ void ida_remove(struct ida *ida, int id) } return; err: - WARN(1, "ida_remove called for id=%d which is not allocated.\n", id); + WARN(1, "ida_free called for id=%d which is not allocated.\n", id); } -EXPORT_SYMBOL(ida_remove); /** * ida_destroy() - Free all IDs. @@ -568,7 +534,7 @@ EXPORT_SYMBOL(ida_destroy); int ida_alloc_range(struct ida *ida, unsigned int min, unsigned int max, gfp_t gfp) { - int ret, id; + int ret, id = 0; unsigned long flags; if ((int)min < 0) diff --git a/lib/radix-tree.c b/lib/radix-tree.c index cc6096b97afb..bc03ecc4dfd2 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -2106,14 +2106,6 @@ void idr_preload(gfp_t gfp_mask) } EXPORT_SYMBOL(idr_preload); -/** - * ida_pre_get - reserve resources for ida allocation - * @ida: ida handle - * @gfp: memory allocation flags - * - * This function should be called before calling ida_get_new_above(). If it - * is unable to allocate memory, it will return %0. On success, it returns %1. - */ int ida_pre_get(struct ida *ida, gfp_t gfp) { /* @@ -2134,7 +2126,6 @@ int ida_pre_get(struct ida *ida, gfp_t gfp) return 1; } -EXPORT_SYMBOL(ida_pre_get); void __rcu **idr_get_free(struct radix_tree_root *root, struct radix_tree_iter *iter, gfp_t gfp, -- cgit v1.2.3 From 1df895190233fcc30d46beca4550bcafb7b959a6 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 18 Jun 2018 19:11:56 -0400 Subject: ida: Change ida_get_new_above to return the id This calling convention makes more sense for the implementation as well as the callers. It even shaves 32 bytes off the compiled code size. Signed-off-by: Matthew Wilcox --- lib/idr.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) (limited to 'lib/idr.c') diff --git a/lib/idr.c b/lib/idr.c index 1dc52191acb6..fab2fd5bc326 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -363,7 +363,7 @@ EXPORT_SYMBOL(idr_replace); #define IDA_MAX (0x80000000U / IDA_BITMAP_BITS - 1) -static int ida_get_new_above(struct ida *ida, int start, int *id) +static int ida_get_new_above(struct ida *ida, int start) { struct radix_tree_root *root = &ida->ida_rt; void __rcu **slot; @@ -402,8 +402,8 @@ static int ida_get_new_above(struct ida *ida, int start, int *id) if (ebit < BITS_PER_LONG) { tmp |= 1UL << ebit; rcu_assign_pointer(*slot, (void *)tmp); - *id = new + ebit - RADIX_TREE_EXCEPTIONAL_SHIFT; - return 0; + return new + ebit - + RADIX_TREE_EXCEPTIONAL_SHIFT; } bitmap = this_cpu_xchg(ida_bitmap, NULL); if (!bitmap) @@ -434,8 +434,7 @@ static int ida_get_new_above(struct ida *ida, int start, int *id) RADIX_TREE_EXCEPTIONAL_ENTRY); radix_tree_iter_replace(root, &iter, slot, bitmap); - *id = new; - return 0; + return new; } bitmap = this_cpu_xchg(ida_bitmap, NULL); if (!bitmap) @@ -444,8 +443,7 @@ static int ida_get_new_above(struct ida *ida, int start, int *id) radix_tree_iter_replace(root, &iter, slot, bitmap); } - *id = new; - return 0; + return new; } } @@ -534,7 +532,7 @@ EXPORT_SYMBOL(ida_destroy); int ida_alloc_range(struct ida *ida, unsigned int min, unsigned int max, gfp_t gfp) { - int ret, id = 0; + int id = 0; unsigned long flags; if ((int)min < 0) @@ -545,24 +543,20 @@ int ida_alloc_range(struct ida *ida, unsigned int min, unsigned int max, again: xa_lock_irqsave(&ida->ida_rt, flags); - ret = ida_get_new_above(ida, min, &id); - if (!ret) { - if (id > max) { - ida_remove(ida, id); - ret = -ENOSPC; - } else { - ret = id; - } + id = ida_get_new_above(ida, min); + if (id > (int)max) { + ida_remove(ida, id); + id = -ENOSPC; } xa_unlock_irqrestore(&ida->ida_rt, flags); - if (unlikely(ret == -EAGAIN)) { + if (unlikely(id == -EAGAIN)) { if (!ida_pre_get(ida, gfp)) return -ENOMEM; goto again; } - return ret; + return id; } EXPORT_SYMBOL(ida_alloc_range); -- cgit v1.2.3