[dm-devel] [PATCH] 5/5: Remove 1024 device limit

Kevin Corry kevcorry at us.ibm.com
Mon Jun 21 22:57:25 UTC 2004


Remove the limitation of 1024 DM devices. Each time the minor_bits array fills
up, allocate a new minor_bits array double the size of the existing one.

--- diff/drivers/md/dm.c	2004-06-21 16:17:16.000000000 -0500
+++ source/drivers/md/dm.c	2004-06-21 17:37:56.407152088 -0500
@@ -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 unsigned long *_minor_bits = NULL;
+static int realloc_minor_bits(void);
+
 /*
  * One of these is allocated per bio.
  */
@@ -111,11 +113,19 @@
 		return -ENOMEM;
 	}
 
+	r = realloc_minor_bits();
+	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);
+		kfree(_minor_bits);
 		return r;
 	}
 
@@ -129,6 +139,7 @@
 {
 	kmem_cache_destroy(_tio_cache);
 	kmem_cache_destroy(_io_cache);
+	kfree(_minor_bits);
 
 	if (unregister_blkdev(_major, _name) < 0)
 		DMERR("devfs_unregister_blkdev failed");
@@ -615,14 +626,48 @@
 /*-----------------------------------------------------------------
  * 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 _max_devices = 0;
+
+static int realloc_minor_bits(void)
+{
+	unsigned long max_devices;
+	unsigned long *minor_bits, *tmp;
+
+	/* Start with 1024 bits, then keep doubling the size of
+	 * the bit-set. Can't go beyond 2^20 devices.
+	 */
+	max_devices = (_max_devices) ? (_max_devices * 2) : 1024;
+	if (max_devices > (1 << MINORBITS))
+		return -EINVAL;
+
+	minor_bits = kmalloc((max_devices / BITS_PER_LONG) *
+			     sizeof(unsigned long), GFP_KERNEL);
+	if (!minor_bits)
+		return -ENOMEM;
+	memset(minor_bits, 0,
+	       (max_devices / BITS_PER_LONG) * sizeof(unsigned long));
+
+	/* Copy the existing bit-set to the new one. */
+	if (_minor_bits)
+		memcpy(minor_bits, _minor_bits,
+		       ((_max_devices / BITS_PER_LONG) * sizeof(unsigned long)));
+
+	tmp = _minor_bits;
+	_minor_bits = minor_bits;
+	_max_devices = max_devices;
+	kfree(tmp);
+
+	DMINFO("Allocated new minor_bits array for %lu devices", _max_devices);
+	return 0;
+}
 
 static void free_minor(unsigned int minor)
 {
-	spin_lock(&_minor_lock);
-	clear_bit(minor, _minor_bits);
-	spin_unlock(&_minor_lock);
+	down(&_minor_lock);
+	if (minor < _max_devices)
+		clear_bit(minor, _minor_bits);
+	up(&_minor_lock);
 }
 
 /*
@@ -630,37 +675,46 @@
  */
 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);
-		return -EINVAL;
+	down(&_minor_lock);
+	while (minor >= _max_devices) {
+		r = realloc_minor_bits();
+		if (r) {
+			DMWARN("request for a mapped_device beyond "
+			       "max_devices (%lu)", _max_devices);
+			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) {
-		set_bit(m, _minor_bits);
-		*minor = m;
-		r = 0;
+	down(&_minor_lock);
+	while ((m = find_first_zero_bit(_minor_bits, _max_devices))
+	       >= _max_devices) {
+		r = realloc_minor_bits();
+		if (r) {
+			up(&_minor_lock);
+			return r;
+		}
 	}
-	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;




More information about the dm-devel mailing list