Commit fbd7fa39 authored by Kevin Corry's avatar Kevin Corry Committed by Linus Torvalds

[PATCH] dm: Remove 1024 devices limitation

Remove the limitation of 1024 DM devices.
Signed-off-by: default avatarKevin Corry <kevcorry@us.ibm.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 98b2ac37
...@@ -17,11 +17,13 @@ ...@@ -17,11 +17,13 @@
#include <linux/slab.h> #include <linux/slab.h>
static const char *_name = DM_NAME; static const char *_name = DM_NAME;
#define MAX_DEVICES 1024
static unsigned int major = 0; static unsigned int major = 0;
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. * One of these is allocated per bio.
*/ */
...@@ -111,11 +113,19 @@ static int __init local_init(void) ...@@ -111,11 +113,19 @@ static int __init local_init(void)
return -ENOMEM; return -ENOMEM;
} }
r = realloc_minor_bits(1024);
if (r < 0) {
kmem_cache_destroy(_tio_cache);
kmem_cache_destroy(_io_cache);
return r;
}
_major = major; _major = major;
r = register_blkdev(_major, _name); r = register_blkdev(_major, _name);
if (r < 0) { if (r < 0) {
kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_tio_cache);
kmem_cache_destroy(_io_cache); kmem_cache_destroy(_io_cache);
free_minor_bits();
return r; return r;
} }
...@@ -129,6 +139,7 @@ static void local_exit(void) ...@@ -129,6 +139,7 @@ static void local_exit(void)
{ {
kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_tio_cache);
kmem_cache_destroy(_io_cache); kmem_cache_destroy(_io_cache);
free_minor_bits();
if (unregister_blkdev(_major, _name) < 0) if (unregister_blkdev(_major, _name) < 0)
DMERR("devfs_unregister_blkdev failed"); DMERR("devfs_unregister_blkdev failed");
...@@ -615,14 +626,58 @@ static int dm_any_congested(void *congested_data, int bdi_bits) ...@@ -615,14 +626,58 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* A bitset is used to keep track of allocated minor numbers. * A bitset is used to keep track of allocated minor numbers.
*---------------------------------------------------------------*/ *---------------------------------------------------------------*/
static spinlock_t _minor_lock = SPIN_LOCK_UNLOCKED; static DECLARE_MUTEX(_minor_lock);
static unsigned long _minor_bits[MAX_DEVICES / BITS_PER_LONG]; 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 void free_minor(unsigned int minor) static void free_minor(unsigned int minor)
{ {
spin_lock(&_minor_lock); down(&_minor_lock);
clear_bit(minor, _minor_bits); if (minor < _max_minors)
spin_unlock(&_minor_lock); clear_bit(minor, _minor_bits);
up(&_minor_lock);
} }
/* /*
...@@ -630,37 +685,48 @@ static void free_minor(unsigned int minor) ...@@ -630,37 +685,48 @@ static void free_minor(unsigned int minor)
*/ */
static int specific_minor(unsigned int minor) static int specific_minor(unsigned int minor)
{ {
int r = -EBUSY; int r = 0;
if (minor >= MAX_DEVICES) { if (minor > (1 << MINORBITS))
DMWARN("request for a mapped_device beyond MAX_DEVICES (%d)",
MAX_DEVICES);
return -EINVAL; return -EINVAL;
down(&_minor_lock);
if (minor >= _max_minors) {
r = realloc_minor_bits(minor);
if (r) {
up(&_minor_lock);
return r;
}
} }
spin_lock(&_minor_lock); if (test_and_set_bit(minor, _minor_bits))
if (!test_and_set_bit(minor, _minor_bits)) r = -EBUSY;
r = 0; up(&_minor_lock);
spin_unlock(&_minor_lock);
return r; return r;
} }
static int next_free_minor(unsigned int *minor) static int next_free_minor(unsigned int *minor)
{ {
int r = -EBUSY; int r;
unsigned int m; unsigned int m;
spin_lock(&_minor_lock); down(&_minor_lock);
m = find_first_zero_bit(_minor_bits, MAX_DEVICES); m = find_first_zero_bit(_minor_bits, _max_minors);
if (m != MAX_DEVICES) { if (m >= _max_minors) {
set_bit(m, _minor_bits); r = realloc_minor_bits(_max_minors * 2);
*minor = m; if (r) {
r = 0; up(&_minor_lock);
return r;
}
m = find_first_zero_bit(_minor_bits, _max_minors);
} }
spin_unlock(&_minor_lock);
return r; set_bit(m, _minor_bits);
*minor = m;
up(&_minor_lock);
return 0;
} }
static struct block_device_operations dm_blk_dops; static struct block_device_operations dm_blk_dops;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment