|
@@ -34,8 +34,10 @@
|
|
#include <linux/err.h>
|
|
#include <linux/err.h>
|
|
#include <linux/string.h>
|
|
#include <linux/string.h>
|
|
#include <linux/idr.h>
|
|
#include <linux/idr.h>
|
|
|
|
+#include <linux/spinlock.h>
|
|
|
|
|
|
static struct kmem_cache *idr_layer_cache;
|
|
static struct kmem_cache *idr_layer_cache;
|
|
|
|
+static DEFINE_SPINLOCK(simple_ida_lock);
|
|
|
|
|
|
static struct idr_layer *get_from_free_list(struct idr *idp)
|
|
static struct idr_layer *get_from_free_list(struct idr *idp)
|
|
{
|
|
{
|
|
@@ -925,6 +927,71 @@ void ida_destroy(struct ida *ida)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(ida_destroy);
|
|
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.
|
|
|
|
+ *
|
|
|
|
+ * 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)
|
|
|
|
+{
|
|
|
|
+ int ret, id;
|
|
|
|
+ unsigned int max;
|
|
|
|
+
|
|
|
|
+ BUG_ON((int)start < 0);
|
|
|
|
+ BUG_ON((int)end < 0);
|
|
|
|
+
|
|
|
|
+ if (end == 0)
|
|
|
|
+ max = 0x80000000;
|
|
|
|
+ else {
|
|
|
|
+ BUG_ON(end < start);
|
|
|
|
+ max = end - 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+again:
|
|
|
|
+ if (!ida_pre_get(ida, gfp_mask))
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ spin_lock(&simple_ida_lock);
|
|
|
|
+ ret = ida_get_new_above(ida, start, &id);
|
|
|
|
+ if (!ret) {
|
|
|
|
+ if (id > max) {
|
|
|
|
+ ida_remove(ida, id);
|
|
|
|
+ ret = -ENOSPC;
|
|
|
|
+ } else {
|
|
|
|
+ ret = id;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ spin_unlock(&simple_ida_lock);
|
|
|
|
+
|
|
|
|
+ if (unlikely(ret == -EAGAIN))
|
|
|
|
+ goto again;
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(ida_simple_get);
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * ida_simple_remove - remove an allocated id.
|
|
|
|
+ * @ida: the (initialized) ida.
|
|
|
|
+ * @id: the id returned by ida_simple_get.
|
|
|
|
+ */
|
|
|
|
+void ida_simple_remove(struct ida *ida, unsigned int id)
|
|
|
|
+{
|
|
|
|
+ BUG_ON((int)id < 0);
|
|
|
|
+ spin_lock(&simple_ida_lock);
|
|
|
|
+ ida_remove(ida, id);
|
|
|
|
+ spin_unlock(&simple_ida_lock);
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(ida_simple_remove);
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* ida_init - initialize ida handle
|
|
* ida_init - initialize ida handle
|
|
* @ida: ida handle
|
|
* @ida: ida handle
|