From: Mike Snitzer <[email-masked]>

The __open_device() error paths in __create_thin() and __create_snap()
incorrectly call __close_device() even if td was not initialized by
__open_device().  Remove this.  

Also document __open_device() return values, remove a redundant
td->changed = 1 in __create_thin(), and insert an additional
safeguard against creating an already-existing device.

Signed-off-by: Mike Snitzer <[email-masked]>
Cc: [email-masked]
Signed-off-by: Alasdair G Kergon <[email-masked]>

---
 drivers/md/dm-thin-metadata.c |   22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

Index: linux-3.3-rc6/drivers/md/dm-thin-metadata.c
===================================================================
--- linux-3.3-rc6.orig/drivers/md/dm-thin-metadata.c
+++ linux-3.3-rc6/drivers/md/dm-thin-metadata.c
@@ -789,6 +789,11 @@ int dm_pool_metadata_close(struct dm_poo
 	return 0;
 }
 
+/*
+ * __open_device: Returns @td corresponding to device with id @dev,
+ * creating it if @create is set and incrementing @td->open_count.
+ * On failure, @td is undefined.
+ */
 static int __open_device(struct dm_pool_metadata *pmd,
 			 dm_thin_id dev, int create,
 			 struct dm_thin_device **td)
@@ -799,10 +804,16 @@ static int __open_device(struct dm_pool_
 	struct disk_device_details details_le;
 
 	/*
-	 * Check the device isn't already open.
+	 * If the device is already open, return it.
 	 */
 	list_for_each_entry(td2, &pmd->thin_devices, list)
 		if (td2->id == dev) {
+			/*
+			 * May not create an already-open device.
+			 */
+			if (create)
+				return -EEXIST;
+
 			td2->open_count++;
 			*td = td2;
 			return 0;
@@ -817,6 +828,9 @@ static int __open_device(struct dm_pool_
 		if (r != -ENODATA || !create)
 			return r;
 
+		/*
+		 * Create new device.
+		 */
 		changed = 1;
 		details_le.mapped_blocks = 0;
 		details_le.transaction_id = cpu_to_le64(pmd->trans_id);
@@ -882,12 +896,10 @@ static int __create_thin(struct dm_pool_
 
 	r = __open_device(pmd, dev, 1, &td);
 	if (r) {
-		__close_device(td);
 		dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root);
 		dm_btree_del(&pmd->bl_info, dev_root);
 		return r;
 	}
-	td->changed = 1;
 	__close_device(td);
 
 	return r;
@@ -967,14 +979,14 @@ static int __create_snap(struct dm_pool_
 		goto bad;
 
 	r = __set_snapshot_details(pmd, td, origin, pmd->time);
+	__close_device(td);
+
 	if (r)
 		goto bad;
 
-	__close_device(td);
 	return 0;
 
 bad:
-	__close_device(td);
 	dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root);
 	dm_btree_remove(&pmd->details_info, pmd->details_root,
 			&key, &pmd->details_root);