From: Kevin Corry Keep track of allocated minor numbers with an IDR instead of a bit-set. Signed-off-by: Kevin Corry Signed-off-by: Andrew Morton --- 25-akpm/drivers/md/dm.c | 124 +++++++++++++++++------------------------------- 1 files changed, 45 insertions(+), 79 deletions(-) diff -puN drivers/md/dm.c~dm-use-idr drivers/md/dm.c --- 25/drivers/md/dm.c~dm-use-idr Fri Jul 2 16:10:54 2004 +++ 25-akpm/drivers/md/dm.c Fri Jul 2 16:10:54 2004 @@ -15,15 +15,13 @@ #include #include #include +#include static const char *_name = DM_NAME; static unsigned int major = 0; static unsigned int _major = 0; -static int realloc_minor_bits(unsigned long requested_minor); -static void free_minor_bits(void); - /* * One of these is allocated per bio. */ @@ -113,19 +111,11 @@ static int __init local_init(void) return -ENOMEM; } - r = realloc_minor_bits(1024); - if (r < 0) { - kmem_cache_destroy(_tio_cache); - kmem_cache_destroy(_io_cache); - return r; - } - _major = major; r = register_blkdev(_major, _name); if (r < 0) { kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_io_cache); - free_minor_bits(); return r; } @@ -139,7 +129,6 @@ static void local_exit(void) { kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_io_cache); - free_minor_bits(); if (unregister_blkdev(_major, _name) < 0) DMERR("devfs_unregister_blkdev failed"); @@ -639,59 +628,15 @@ static int dm_any_congested(void *conges } /*----------------------------------------------------------------- - * A bitset is used to keep track of allocated minor numbers. + * An IDR is used to keep track of allocated minor numbers. *---------------------------------------------------------------*/ static DECLARE_MUTEX(_minor_lock); -static unsigned long *_minor_bits = NULL; -static unsigned long _max_minors = 0; - -#define MINORS_SIZE(minors) ((minors / BITS_PER_LONG) * sizeof(unsigned long)) - -static int realloc_minor_bits(unsigned long requested_minor) -{ - unsigned long max_minors; - unsigned long *minor_bits, *tmp; - - if (requested_minor < _max_minors) - return -EINVAL; - - /* Round up the requested minor to the next power-of-2. */ - max_minors = 1 << fls(requested_minor - 1); - if (max_minors > (1 << MINORBITS)) - return -EINVAL; - - minor_bits = kmalloc(MINORS_SIZE(max_minors), GFP_KERNEL); - if (!minor_bits) - return -ENOMEM; - memset(minor_bits, 0, MINORS_SIZE(max_minors)); - - /* Copy the existing bit-set to the new one. */ - if (_minor_bits) - memcpy(minor_bits, _minor_bits, MINORS_SIZE(_max_minors)); - - tmp = _minor_bits; - _minor_bits = minor_bits; - _max_minors = max_minors; - if (tmp) - kfree(tmp); - - return 0; -} - -static void free_minor_bits(void) -{ - down(&_minor_lock); - kfree(_minor_bits); - _minor_bits = NULL; - _max_minors = 0; - up(&_minor_lock); -} +static DEFINE_IDR(_minor_idr); static void free_minor(unsigned int minor) { down(&_minor_lock); - if (minor < _max_minors) - clear_bit(minor, _minor_bits); + idr_remove(&_minor_idr, minor); up(&_minor_lock); } @@ -700,24 +645,37 @@ static void free_minor(unsigned int mino */ static int specific_minor(unsigned int minor) { - int r = 0; + int r, m; if (minor > (1 << MINORBITS)) return -EINVAL; down(&_minor_lock); - if (minor >= _max_minors) { - r = realloc_minor_bits(minor); - if (r) { - up(&_minor_lock); - return r; - } + + if (idr_find(&_minor_idr, minor)) { + r = -EBUSY; + goto out; } - if (test_and_set_bit(minor, _minor_bits)) + r = idr_pre_get(&_minor_idr, GFP_KERNEL); + if (!r) { + r = -ENOMEM; + goto out; + } + + r = idr_get_new_above(&_minor_idr, specific_minor, minor, &m); + if (r) { + goto out; + } + + if (m != minor) { + idr_remove(&_minor_idr, m); r = -EBUSY; - up(&_minor_lock); + goto out; + } +out: + up(&_minor_lock); return r; } @@ -727,21 +685,29 @@ static int next_free_minor(unsigned int unsigned int m; down(&_minor_lock); - m = find_first_zero_bit(_minor_bits, _max_minors); - if (m >= _max_minors) { - r = realloc_minor_bits(_max_minors * 2); - if (r) { - up(&_minor_lock); - return r; - } - m = find_first_zero_bit(_minor_bits, _max_minors); + + r = idr_pre_get(&_minor_idr, GFP_KERNEL); + if (!r) { + r = -ENOMEM; + goto out; + } + + r = idr_get_new(&_minor_idr, next_free_minor, &m); + if (r) { + goto out; + } + + if (m > (1 << MINORBITS)) { + idr_remove(&_minor_idr, m); + r = -ENOSPC; + goto out; } - set_bit(m, _minor_bits); *minor = m; - up(&_minor_lock); - return 0; +out: + up(&_minor_lock); + return r; } static struct block_device_operations dm_blk_dops; _