[dm-devel] [PATCH 02/08] dm: use idr_replace for minor_idr
Jeff Mahoney
jeffm at suse.com
Mon Apr 17 15:16:02 UTC 2006
A patch was submitted in August 2004 to replace the old bitmap minor
allocation tracking with an IDR to both track allocation and provide
a mapping.
This works pretty well in execution, but the author overlooked a pretty
important detail. With the old bitmap, it was enough to just mark the
minor as allocated and return it. With the IDR code, the mapped_device
is used to mark the minor as in use. The problem with that approach is
that the mapped_device isn't done initializing, and is placed on a
subsystem-wide data structure, which is then unlocked. Even if the
assignment was delayed or the lock was held until initialization
completed, there would still be a race when we register the disk with
the block subsystem since we'd need a minor to register, but we'd need
to be done registering before making the device available.
This patch uses a place holder value, MINOR_ALLOCED, to mark the minor
as allocated but in a state where it can't be used, such as
mid-allocation or mid-free. At the end of the initialization, we
replace the place holder with the pointer to the mapped_device, making
it available to the rest of the dm subsystem.
During the free process, we again use the place holder value in the
IDR to indicate the minor is allocated but unavailable for use.
Signed-off-by: Jeff Mahoney <jeffm at suse.com>
--
drivers/md/dm.c | 19 ++++++++++++++++---
1 files changed, 16 insertions(+), 3 deletions(-)
diff -ruNpX ../dontdiff 2.6.17-rc1-staging1/drivers/md/dm.c 2.6.17-rc1-staging2/drivers/md/dm.c
--- 2.6.17-rc1-staging1/drivers/md/dm.c 2006-04-13 20:22:45.000000000 -0400
+++ 2.6.17-rc1-staging2/drivers/md/dm.c 2006-04-17 10:51:42.000000000 -0400
@@ -54,6 +54,8 @@ union map_info *dm_get_mapinfo(struct bi
return NULL;
}
+#define MINOR_ALLOCED ((void *)-1)
+
/*
* Bits for the md->flags field.
*/
@@ -777,7 +779,7 @@ static int specific_minor(struct mapped_
goto out;
}
- r = idr_get_new_above(&_minor_idr, md, minor, &m);
+ r = idr_get_new_above(&_minor_idr, MINOR_ALLOCED, minor, &m);
if (r) {
goto out;
}
@@ -806,7 +808,7 @@ static int next_free_minor(struct mapped
goto out;
}
- r = idr_get_new(&_minor_idr, md, &m);
+ r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m);
if (r) {
goto out;
}
@@ -833,6 +835,7 @@ static struct mapped_device *alloc_dev(u
{
int r;
struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
+ void *old_ide;
if (!md) {
DMWARN("unable to allocate device, out of memory.");
@@ -888,6 +891,13 @@ static struct mapped_device *alloc_dev(u
init_waitqueue_head(&md->wait);
init_waitqueue_head(&md->eventq);
+ /* Populate the mapping, nobody knows we exist yet */
+ mutex_lock(&_minor_lock);
+ old_ide = idr_replace(&_minor_idr, md, minor);
+ mutex_unlock(&_minor_lock);
+
+ BUG_ON(old_ide != MINOR_ALLOCED);
+
return md;
bad4:
@@ -1018,7 +1028,7 @@ static struct mapped_device *dm_find_md(
mutex_lock(&_minor_lock);
md = idr_find(&_minor_idr, minor);
- if (!md || (dm_disk(md)->first_minor != minor))
+ if (md && (md == MINOR_ALLOCED || (dm_disk(md)->first_minor != minor)))
md = NULL;
mutex_unlock(&_minor_lock);
@@ -1057,6 +1067,9 @@ void dm_put(struct mapped_device *md)
if (atomic_dec_and_test(&md->holders)) {
map = dm_get_table(md);
+ mutex_lock(&_minor_lock);
+ idr_replace(&_minor_idr, MINOR_ALLOCED, md->disk->first_minor);
+ mutex_unlock(&_minor_lock);
if (!dm_suspended(md)) {
dm_table_presuspend_targets(map);
dm_table_postsuspend_targets(map);
More information about the dm-devel
mailing list