LWN.net Logo

dm update 3/3

From:  Joe Thornber <joe@fib011235813.fsnet.co.uk>
To:  Linus Torvalds <torvalds@transmeta.com>
Subject:  [PATCH] dm update 3/3
Date:  Tue, 29 Oct 2002 17:20:16 +0000
Cc:  Linux Mailing List <linux-kernel@vger.kernel.org>

Keep track of allocated minors in a bitset rather than abusing
get_gendisk.


--- diff/drivers/md/dm.c	2002-10-29 16:22:36.000000000 +0000
+++ source/drivers/md/dm.c	2002-10-29 16:34:45.000000000 +0000
@@ -15,7 +15,7 @@
 #include <linux/slab.h>
 
 static const char *_name = DM_NAME;
-#define MAX_DEVICES 256
+#define MAX_DEVICES (1 << KDEV_MINOR_BITS)
 #define SECTOR_SHIFT 9
 
 static int major = 0;
@@ -483,13 +483,25 @@
 	return 0;
 }
 
+/*-----------------------------------------------------------------
+ * 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 void free_minor(int minor)
+{
+	spin_lock(&_minor_lock);
+	clear_bit(minor, _minor_bits);
+	spin_unlock(&_minor_lock);
+}
+
 /*
  * See if the device with a specific minor # is free.
  */
-static int specific_dev(int minor, struct mapped_device *md)
+static int specific_minor(int minor)
 {
-	struct gendisk *disk;
-	int part;
+	int r = -EBUSY;
 
 	if (minor >= MAX_DEVICES) {
 		DMWARN("request for a mapped_device beyond MAX_DEVICES (%d)",
@@ -497,26 +509,32 @@
 		return -EINVAL;
 	}
 
-	disk = get_gendisk(MKDEV(_major, minor), &part);
-	if (disk) {
-		put_disk(disk);
-		return -EBUSY;
+	spin_lock(&_minor_lock);
+	if (!test_bit(minor, _minor_bits)) {
+		r = minor;
+		set_bit(minor, _minor_bits);
 	}
+	spin_unlock(&_minor_lock);
 
-	return minor;
+	return r;
 }
 
-static int any_old_dev(struct mapped_device *md)
+static int any_old_minor(void)
 {
-	int i;
+	int i, r = -EBUSY;
 
-	for (i = 0; i < MAX_DEVICES; i++)
-		if (specific_dev(i, md) >= 0) {
+	spin_lock(&_minor_lock);
+	for (i = 0; i < MAX_DEVICES; i++) {
+		if (!test_bit(i, _minor_bits)) {
+			r = i;
+			set_bit(i, _minor_bits);
 			DMWARN("allocating minor = %d", i);
-			return i;
+			break;
 		}
+	}
+	spin_unlock(&_minor_lock);
 
-	return -EBUSY;
+	return r;
 }
 
 /*
@@ -532,7 +550,7 @@
 	}
 
 	/* get a minor number for the dev */
-	minor = (minor < 0) ? any_old_dev(md) : specific_dev(minor, md);
+	minor = (minor < 0) ? any_old_minor() : specific_minor(minor);
 	if (minor < 0) {
 		kfree(md);
 		return NULL;
@@ -547,6 +565,7 @@
 
 	md->disk = alloc_disk(1);
 	if (!md->disk) {
+		free_minor(md->disk->first_minor);
 		kfree(md);
 		return NULL;
 	}
@@ -566,6 +585,7 @@
 
 static void free_dev(struct mapped_device *md)
 {
+	free_minor(md->disk->first_minor);
 	del_gendisk(md->disk);
 	put_disk(md->disk);
 	kfree(md);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Copyright © 2002, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds
Powered by Rackspace Managed Hosting.