Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ida: simplified functions for id allocation

The current hyper-optimized functions are overkill if you simply want to
allocate an id for a device. Create versions which use an internal
lock.

In followup patches, numerous drivers are converted to use this
interface.

Thanks to Tejun for feedback.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Acked-by: Tejun Heo <tj@kernel.org>
Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Rusty Russell and committed by
Linus Torvalds
88eca020 a7295898

+71
+4
include/linux/idr.h
··· 146 146 void ida_destroy(struct ida *ida); 147 147 void ida_init(struct ida *ida); 148 148 149 + int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, 150 + gfp_t gfp_mask); 151 + void ida_simple_remove(struct ida *ida, unsigned int id); 152 + 149 153 void __init idr_init_cache(void); 150 154 151 155 #endif /* __IDR_H__ */
+67
lib/idr.c
··· 34 34 #include <linux/err.h> 35 35 #include <linux/string.h> 36 36 #include <linux/idr.h> 37 + #include <linux/spinlock.h> 37 38 38 39 static struct kmem_cache *idr_layer_cache; 40 + static DEFINE_SPINLOCK(simple_ida_lock); 39 41 40 42 static struct idr_layer *get_from_free_list(struct idr *idp) 41 43 { ··· 926 924 kfree(ida->free_bitmap); 927 925 } 928 926 EXPORT_SYMBOL(ida_destroy); 927 + 928 + /** 929 + * ida_simple_get - get a new id. 930 + * @ida: the (initialized) ida. 931 + * @start: the minimum id (inclusive, < 0x8000000) 932 + * @end: the maximum id (exclusive, < 0x8000000 or 0) 933 + * @gfp_mask: memory allocation flags 934 + * 935 + * Allocates an id in the range start <= id < end, or returns -ENOSPC. 936 + * On memory allocation failure, returns -ENOMEM. 937 + * 938 + * Use ida_simple_remove() to get rid of an id. 939 + */ 940 + int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, 941 + gfp_t gfp_mask) 942 + { 943 + int ret, id; 944 + unsigned int max; 945 + 946 + BUG_ON((int)start < 0); 947 + BUG_ON((int)end < 0); 948 + 949 + if (end == 0) 950 + max = 0x80000000; 951 + else { 952 + BUG_ON(end < start); 953 + max = end - 1; 954 + } 955 + 956 + again: 957 + if (!ida_pre_get(ida, gfp_mask)) 958 + return -ENOMEM; 959 + 960 + spin_lock(&simple_ida_lock); 961 + ret = ida_get_new_above(ida, start, &id); 962 + if (!ret) { 963 + if (id > max) { 964 + ida_remove(ida, id); 965 + ret = -ENOSPC; 966 + } else { 967 + ret = id; 968 + } 969 + } 970 + spin_unlock(&simple_ida_lock); 971 + 972 + if (unlikely(ret == -EAGAIN)) 973 + goto again; 974 + 975 + return ret; 976 + } 977 + EXPORT_SYMBOL(ida_simple_get); 978 + 979 + /** 980 + * ida_simple_remove - remove an allocated id. 981 + * @ida: the (initialized) ida. 982 + * @id: the id returned by ida_simple_get. 983 + */ 984 + void ida_simple_remove(struct ida *ida, unsigned int id) 985 + { 986 + BUG_ON((int)id < 0); 987 + spin_lock(&simple_ida_lock); 988 + ida_remove(ida, id); 989 + spin_unlock(&simple_ida_lock); 990 + } 991 + EXPORT_SYMBOL(ida_simple_remove); 929 992 930 993 /** 931 994 * ida_init - initialize ida handle