@@ -176,6 +176,7 @@ DECLARE_PER_CPU(struct ida_bitmap *, ida_bitmap);
struct ida {
struct radix_tree_root ida_rt;
+ unsigned int ida_next;
};
#define IDA_INIT { \
@@ -188,6 +189,8 @@ 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_cyclic(struct ida *ida, unsigned int start, unsigned int end,
+ gfp_t gfp_mask);
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);
@@ -407,25 +407,10 @@ 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.
- *
- * Compared to ida_get_new_above() this function does its own locking, and
- * should be used unless there are special requirements.
- *
- * Use ida_simple_remove() to get rid of an id.
- */
-int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
- gfp_t gfp_mask)
+static int __ida_simple_get(struct ida *ida, unsigned int start,
+ unsigned int end, bool cyclic, gfp_t gfp_mask)
{
- int ret, id;
+ int ret, id, curr;
unsigned int max;
unsigned long flags;
@@ -439,18 +424,28 @@ int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
max = end - 1;
}
+ curr = start;
again:
if (!ida_pre_get(ida, gfp_mask))
return -ENOMEM;
spin_lock_irqsave(&simple_ida_lock, flags);
- ret = ida_get_new_above(ida, start, &id);
+ if (cyclic && ida->ida_next > curr)
+ curr = ida->ida_next;
+
+ ret = ida_get_new_above(ida, curr, &id);
if (!ret) {
if (id > max) {
ida_remove(ida, id);
- ret = -ENOSPC;
+ if (cyclic && ida->ida_next > start) {
+ curr = ida->ida_next = start;
+ ret = -EAGAIN;
+ } else {
+ ret = -ENOSPC;
+ }
} else {
ret = id;
+ ida->ida_next = id + 1U;
}
}
spin_unlock_irqrestore(&simple_ida_lock, flags);
@@ -460,9 +455,53 @@ int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
return ret;
}
+
+/**
+ * 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.
+ *
+ * Compared to ida_get_new_above() this function does its own locking, and
+ * should be used unless there are special requirements.
+ *
+ * Use ida_simple_remove() to get rid of an id.
+ */
+int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
+ gfp_t gfp_mask)
+{
+ return __ida_simple_get(ida, start, end, false, gfp_mask);
+}
EXPORT_SYMBOL(ida_simple_get);
/**
+ * ida_simple_get_cyclic - 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 larger than the last ID allocated and less than @end.
+ * If @end is reached, it will attempt to allocate the smallest ID that is
+ * larger or equal to @start.
+ *
+ * If there are no available IDs returns -ENOSPC.
+ * On memory allocation failure, returns -ENOMEM.
+ *
+ * Use ida_simple_remove() to get rid of an id.
+ */
+int ida_simple_get_cyclic(struct ida *ida, unsigned int start, unsigned int end,
+ gfp_t gfp_mask)
+{
+ return __ida_simple_get(ida, start, end, true, gfp_mask);
+}
+EXPORT_SYMBOL(ida_simple_get_cyclic);
+
+/**
* ida_simple_remove - remove an allocated id.
* @ida: the (initialized) ida.
* @id: the id returned by ida_simple_get.
This patch modifies ida_get_simple to support cyclic allocation similar to idr_alloc_cyclic. It will be used in the next target layer patches to allocate IDs for info that is passed to apps that were relying on the info's IDs to change after device deletion then readdition sequences. Signed-off-by: Mike Christie <mchristi@redhat.com> --- include/linux/idr.h | 3 ++ lib/idr.c | 79 +++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 62 insertions(+), 20 deletions(-)