[dm-devel] Is there a bd_claim leak in upgrade_mode?

Christophe Saout christophe at saout.de
Tue Jan 20 09:02:02 UTC 2004


Hi!

The upgrade_mode function in dm-table.c seems somewhat strange to me:

When dm_get_device -> __table_get_device finds that a block device is
already opened by dm but read-only and read-write access is requested it
decides to upgrade the mode. Ok so far.

upgrade_mode opens the device a second time, open_dev calls bd_claim a
second time. But dm_put_device will release the device only once.

Has this ever been tested? I think it is very unlikely that one target
will open a block device read-only and the next one read-write. Hmm.

If there is a bug, might this be a solution?


--- linux.orig/drivers/md/dm-table.c	2004-01-20 14:12:29.621546000 +0100
+++ linux/drivers/md/dm-table.c	2004-01-20 14:55:04.147199944 +0100
@@ -406,8 +406,10 @@
 	r = open_dev(dd, dev);
 	if (!r)
 		close_dev(&dd_copy);
-	else
+	else {
 		memcpy(dd, &dd_copy, sizeof(dd_copy));
+		bd_release(dd->bdev);
+	}
 
 	return r;
 }


The other way I could think of is to add paramters to open_dev and
close_dev to tell whether the bd_claim/bd_release mechanism should
be used, and then make upgrade_mode not use it.


--- linux.orig/drivers/md/dm-table.c	2004-01-20 14:12:29.621546000 +0100
+++ linux/drivers/md/dm-table.c	2004-01-20 14:51:25.786395832 +0100
@@ -343,12 +343,12 @@
 /*
  * Open a device so we can use it as a map destination.
  */
-static int open_dev(struct dm_dev *d, dev_t dev)
+static int open_dev(struct dm_dev *d, dev_t dev, int claim)
 {
 	static char *_claim_ptr = "I belong to device-mapper";
 	struct block_device *bdev;
 
-	int r;
+	int r = 0;
 
 	if (d->bdev)
 		BUG();
@@ -356,7 +356,8 @@
 	bdev = open_by_devnum(dev, d->mode, BDEV_RAW);
 	if (IS_ERR(bdev))
 		return PTR_ERR(bdev);
-	r = bd_claim(bdev, _claim_ptr);
+	if (claim)
+		r = bd_claim(bdev, _claim_ptr);
 	if (r)
 		blkdev_put(bdev, BDEV_RAW);
 	else
@@ -367,12 +368,13 @@
 /*
  * Close a device that we've been using.
  */
-static void close_dev(struct dm_dev *d)
+static void close_dev(struct dm_dev *d, int release)
 {
 	if (!d->bdev)
 		return;
 
-	bd_release(d->bdev);
+	if (release)
+		bd_release(d->bdev);
 	blkdev_put(d->bdev, BDEV_RAW);
 	d->bdev = NULL;
 }
@@ -403,9 +405,9 @@
 
 	dd->mode |= new_mode;
 	dd->bdev = NULL;
-	r = open_dev(dd, dev);
+	r = open_dev(dd, dev, 0);
 	if (!r)
-		close_dev(&dd_copy);
+		close_dev(&dd_copy, 0);
 	else
 		memcpy(dd, &dd_copy, sizeof(dd_copy));
 
@@ -448,7 +450,7 @@
 		dd->mode = mode;
 		dd->bdev = NULL;
 
-		if ((r = open_dev(dd, dev))) {
+		if ((r = open_dev(dd, dev, 1))) {
 			kfree(dd);
 			return r;
 		}
@@ -532,7 +534,7 @@
 void dm_put_device(struct dm_target *ti, struct dm_dev *dd)
 {
 	if (atomic_dec_and_test(&dd->count)) {
-		close_dev(dd);
+		close_dev(dd, 1);
 		list_del(&dd->list);
 		kfree(dd);
 	}





More information about the dm-devel mailing list