OSDN Git Service

dm thin metadata: remove incorrect close_device on creation error paths
authorMike Snitzer <snitzer@redhat.com>
Wed, 7 Mar 2012 19:09:41 +0000 (19:09 +0000)
committerAlasdair G Kergon <agk@redhat.com>
Wed, 7 Mar 2012 19:09:41 +0000 (19:09 +0000)
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 <snitzer@redhat.com>
Cc: stable@kernel.org
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
drivers/md/dm-thin-metadata.c

index 59c4f04..13d9646 100644 (file)
@@ -789,6 +789,11 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
        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_metadata *pmd,
        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_metadata *pmd,
                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_metadata *pmd,
 
        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_metadata *pmd,
                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);