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 @@
#include <linux/slab.h>
static const char *_name = DM_NAME;
#define MAX_DEVICES 1024
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.
*/
......@@ -111,11 +113,19 @@ 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;
}
......@@ -129,6 +139,7 @@ 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");
......@@ -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.
*---------------------------------------------------------------*/
static spinlock_t _minor_lock = SPIN_LOCK_UNLOCKED;
static unsigned long _minor_bits[MAX_DEVICES / BITS_PER_LONG];
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 void free_minor(unsigned int minor)
{
spin_lock(&_minor_lock);
down(&_minor_lock);
if (minor < _max_minors)
clear_bit(minor, _minor_bits);
spin_unlock(&_minor_lock);
up(&_minor_lock);
}
/*
......@@ -630,37 +685,48 @@ static void free_minor(unsigned int minor)
*/
static int specific_minor(unsigned int minor)
{
int r = -EBUSY;
int r = 0;
if (minor >= MAX_DEVICES) {
DMWARN("request for a mapped_device beyond MAX_DEVICES (%d)",
MAX_DEVICES);
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;
}
}
spin_lock(&_minor_lock);
if (!test_and_set_bit(minor, _minor_bits))
r = 0;
spin_unlock(&_minor_lock);
if (test_and_set_bit(minor, _minor_bits))
r = -EBUSY;
up(&_minor_lock);
return r;
}
static int next_free_minor(unsigned int *minor)
{
int r = -EBUSY;
int r;
unsigned int m;
spin_lock(&_minor_lock);
m = find_first_zero_bit(_minor_bits, MAX_DEVICES);
if (m != MAX_DEVICES) {
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);
}
set_bit(m, _minor_bits);
*minor = m;
r = 0;
}
spin_unlock(&_minor_lock);
up(&_minor_lock);
return r;
return 0;
}
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