diff --git a/[refs] b/[refs] index ed7950bf80fb..fd1a63a0537d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 1212268fd9816e3b8801e57b896fceaec71969ad +refs/heads/master: 1f3db25d8be4ac50b897b39609802183ea68a514 diff --git a/trunk/drivers/md/dm-thin-metadata.c b/trunk/drivers/md/dm-thin-metadata.c index 59c4f0446ffa..13d964636d57 100644 --- a/trunk/drivers/md/dm-thin-metadata.c +++ b/trunk/drivers/md/dm-thin-metadata.c @@ -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);