[PATCH 02/08] dm: use idr_replace for minor_idr

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



 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 <[email protected]>
--
 drivers/md/dm.c |   17 ++++++++++++++---
 1 files changed, 14 insertions(+), 3 deletions(-)

diff -ruNpX ../dontdiff linux-2.6.16-staging1/drivers/md/dm.c linux-2.6.16-staging2/drivers/md/dm.c
--- linux-2.6.16-staging1/drivers/md/dm.c	2006-04-11 13:57:50.000000000 -0400
+++ linux-2.6.16-staging2/drivers/md/dm.c	2006-04-13 16:18:16.000000000 -0400
@@ -51,6 +51,8 @@ union map_info *dm_get_mapinfo(struct bi
         return NULL;
 }
 
+#define MINOR_ALLOCED ((void *)-1)
+
 /*
  * Bits for the md->flags field.
  */
@@ -728,7 +730,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;
 	}
@@ -757,7 +759,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;
 	}
@@ -840,6 +842,12 @@ 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 */
+	down(&_minor_lock);
+	r = idr_replace(&_minor_idr, md, minor);
+	up(&_minor_lock);
+	BUG_ON(r < 0);
+
 	return md;
 
  bad4:
@@ -963,7 +971,7 @@ static struct mapped_device *dm_find_md(
 	down(&_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;
 
 	up(&_minor_lock);
@@ -1007,6 +1015,9 @@ void dm_put(struct mapped_device *md)
 	struct dm_table *map = dm_get_table(md);
 
 	if (atomic_dec_and_test(&md->holders)) {
+		down(&_minor_lock);
+		idr_replace(&_minor_idr, MINOR_ALLOCED, md->disk->first_minor);
+		up(&_minor_lock);
 		if (!dm_suspended(md)) {
 			dm_table_presuspend_targets(map);
 			dm_table_postsuspend_targets(map);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux