2002-10-29 17:14:00

by Joe Thornber

[permalink] [raw]
Subject: [PATCH] dm update 3/3

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);


2002-10-29 17:36:04

by Alexander Viro

[permalink] [raw]
Subject: Re: [PATCH] dm update 3/3



On Tue, 29 Oct 2002, Joe Thornber wrote:

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

> + 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);

Ugh. See find_first_zero_bit() - no need to reinvent that wheel...

2002-10-30 10:10:08

by Joe Thornber

[permalink] [raw]
Subject: Re: [PATCH] dm update 3/3

On Tue, Oct 29, 2002 at 12:42:24PM -0500, Alexander Viro wrote:
> Ugh. See find_first_zero_bit() - no need to reinvent that wheel...


--- diff/drivers/md/dm.c 2002-10-30 09:38:39.000000000 +0000
+++ source/drivers/md/dm.c 2002-10-30 10:03:54.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,27 @@
return -EINVAL;
}

- disk = get_gendisk(MKDEV(_major, minor), &part);
- if (disk) {
- put_disk(disk);
- return -EBUSY;
- }
+ spin_lock(&_minor_lock);
+ if (!test_and_set_bit(minor, _minor_bits))
+ r = minor;
+ spin_unlock(&_minor_lock);

- return minor;
+ return r;
}

-static int any_old_dev(struct mapped_device *md)
+static int next_free_minor(void)
{
- int i;
+ int minor, r = -EBUSY;

- for (i = 0; i < MAX_DEVICES; i++)
- if (specific_dev(i, md) >= 0) {
- DMWARN("allocating minor = %d", i);
- return i;
- }
+ spin_lock(&_minor_lock);
+ minor = find_first_zero_bit(_minor_bits, MAX_DEVICES);
+ if (minor != MAX_DEVICES) {
+ set_bit(minor, _minor_bits);
+ r = minor;
+ }
+ spin_unlock(&_minor_lock);

- return -EBUSY;
+ return r;
}

/*
@@ -532,12 +545,13 @@
}

/* get a minor number for the dev */
- minor = (minor < 0) ? any_old_dev(md) : specific_dev(minor, md);
+ minor = (minor < 0) ? next_free_minor() : specific_minor(minor);
if (minor < 0) {
kfree(md);
return NULL;
}

+ DMWARN("allocating minor %d.", minor);
memset(md, 0, sizeof(*md));
init_rwsem(&md->lock);
atomic_set(&md->holders, 1);
@@ -547,6 +561,7 @@

md->disk = alloc_disk(1);
if (!md->disk) {
+ free_minor(md->disk->first_minor);
kfree(md);
return NULL;
}
@@ -566,6 +581,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);