From 9fb9a3ec7bd634ad38741c1f367d77732259dd1e Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 12 Jul 2012 13:14:43 +0100 Subject: [PATCH 40/41] dm thin metadata: introduce dm_pool_abort_metadata Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer --- drivers/md/dm-thin-metadata.c | 143 +++++++++++++++++++++++++++++++---------- drivers/md/dm-thin-metadata.h | 12 ++++ 2 files changed, 121 insertions(+), 34 deletions(-) diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 4b35131..6da4d1a 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -185,6 +185,7 @@ struct dm_pool_metadata { unsigned long flags; sector_t data_block_size; bool read_only:1; + bool fail_io:1; }; struct dm_thin_device { @@ -193,7 +194,8 @@ struct dm_thin_device { dm_thin_id id; int open_count; - int changed; + bool changed:1; + bool aborted_with_changes:1; uint64_t mapped_blocks; uint64_t transaction_id; uint32_t creation_time; @@ -735,9 +737,6 @@ static int __write_changed_details(struct dm_pool_metadata *pmd) static int __commit_transaction(struct dm_pool_metadata *pmd) { - /* - * FIXME: Associated pool should be made read-only on failure. - */ int r; size_t metadata_len, data_len; struct thin_disk_superblock *disk_super; @@ -813,6 +812,7 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev, pmd->time = 0; INIT_LIST_HEAD(&pmd->thin_devices); pmd->read_only = 0; + pmd->fail_io = 0; pmd->bdev = bdev; pmd->data_block_size = data_block_size; @@ -855,16 +855,17 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd) return -EBUSY; } - if (!pmd->read_only) { + if (!pmd->read_only && !pmd->fail_io) { r = __commit_transaction(pmd); if (r < 0) DMWARN("%s: __commit_transaction() failed, error = %d", __func__, r); } - __destroy_persistent_data_objects(pmd); - kfree(pmd); + if (!pmd->fail_io) + __destroy_persistent_data_objects(pmd); + kfree(pmd); return 0; } @@ -925,6 +926,7 @@ static int __open_device(struct dm_pool_metadata *pmd, (*td)->id = dev; (*td)->open_count = 1; (*td)->changed = changed; + (*td)->aborted_with_changes = 0; (*td)->mapped_blocks = le64_to_cpu(details_le.mapped_blocks); (*td)->transaction_id = le64_to_cpu(details_le.transaction_id); (*td)->creation_time = le32_to_cpu(details_le.creation_time); @@ -989,7 +991,7 @@ int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_thin_id dev) int r; down_write(&pmd->root_lock); - r = __create_thin(pmd, dev); + r = pmd->fail_io ? -EINVAL : __create_thin(pmd, dev); up_write(&pmd->root_lock); return r; @@ -1079,7 +1081,7 @@ int dm_pool_create_snap(struct dm_pool_metadata *pmd, int r; down_write(&pmd->root_lock); - r = __create_snap(pmd, dev, origin); + r = pmd->fail_io ? -EINVAL : __create_snap(pmd, dev, origin); up_write(&pmd->root_lock); return r; @@ -1121,7 +1123,7 @@ int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd, int r; down_write(&pmd->root_lock); - r = __delete_device(pmd, dev); + r = pmd->fail_io ? -EINVAL : __delete_device(pmd, dev); up_write(&pmd->root_lock); return r; @@ -1131,27 +1133,40 @@ int dm_pool_set_metadata_transaction_id(struct dm_pool_metadata *pmd, uint64_t current_id, uint64_t new_id) { + int r; + down_write(&pmd->root_lock); - if (pmd->trans_id != current_id) { - up_write(&pmd->root_lock); - DMERR("mismatched transaction id"); - return -EINVAL; + if (pmd->fail_io) + r = -EINVAL; + else { + if (pmd->trans_id != current_id) { + DMERR("mismatched transaction id"); + r = -EINVAL; + } else { + pmd->trans_id = new_id; + r = 0; + } } - - pmd->trans_id = new_id; up_write(&pmd->root_lock); - return 0; + return r; } int dm_pool_get_metadata_transaction_id(struct dm_pool_metadata *pmd, uint64_t *result) { + int r; + down_read(&pmd->root_lock); - *result = pmd->trans_id; + if (pmd->fail_io) + r = -EINVAL; + else { + *result = pmd->trans_id; + r = 0; + } up_read(&pmd->root_lock); - return 0; + return r; } static int __reserve_metadata_snap(struct dm_pool_metadata *pmd) @@ -1218,7 +1233,7 @@ int dm_pool_reserve_metadata_snap(struct dm_pool_metadata *pmd) int r; down_write(&pmd->root_lock); - r = __reserve_metadata_snap(pmd); + r = pmd->fail_io ? -EINVAL : __reserve_metadata_snap(pmd); up_write(&pmd->root_lock); return r; @@ -1263,7 +1278,7 @@ int dm_pool_release_metadata_snap(struct dm_pool_metadata *pmd) int r; down_write(&pmd->root_lock); - r = __release_metadata_snap(pmd); + r = pmd->fail_io ? -EINVAL : __release_metadata_snap(pmd); up_write(&pmd->root_lock); return r; @@ -1293,7 +1308,7 @@ int dm_pool_get_metadata_snap(struct dm_pool_metadata *pmd, int r; down_read(&pmd->root_lock); - r = __get_metadata_snap(pmd, result); + r = pmd->fail_io ? -EINVAL : __get_metadata_snap(pmd, result); up_read(&pmd->root_lock); return r; @@ -1305,7 +1320,7 @@ int dm_pool_open_thin_device(struct dm_pool_metadata *pmd, dm_thin_id dev, int r; down_write(&pmd->root_lock); - r = __open_device(pmd, dev, 0, td); + r = pmd->fail_io ? -EINVAL : __open_device(pmd, dev, 0, td); up_write(&pmd->root_lock); return r; @@ -1341,12 +1356,22 @@ int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block, if (can_block) { down_read(&pmd->root_lock); + if (pmd->fail_io) { + up_read(&pmd->root_lock); + return -EINVAL; + } + r = dm_btree_lookup(&pmd->info, pmd->root, keys, &value); if (!r) block_time = le64_to_cpu(value); up_read(&pmd->root_lock); } else if (down_read_trylock(&pmd->root_lock)) { + if (pmd->fail_io) { + up_read(&pmd->root_lock); + return -EINVAL; + } + r = dm_btree_lookup(&pmd->nb_info, pmd->root, keys, &value); if (!r) block_time = le64_to_cpu(value); @@ -1396,7 +1421,7 @@ int dm_thin_insert_block(struct dm_thin_device *td, dm_block_t block, int r; down_write(&td->pmd->root_lock); - r = __insert(td, block, data_block); + r = td->pmd->fail_io ? -EINVAL : __insert(td, block, data_block); up_write(&td->pmd->root_lock); return r; @@ -1423,7 +1448,7 @@ int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block) int r; down_write(&td->pmd->root_lock); - r = __remove(td, block); + r = td->pmd->fail_io ? -EINVAL : __remove(td, block); up_write(&td->pmd->root_lock); return r; @@ -1440,12 +1465,23 @@ bool dm_thin_changed_this_transaction(struct dm_thin_device *td) return r; } +bool dm_thin_aborted_changes(struct dm_thin_device *td) +{ + int r; + + down_read(&td->pmd->root_lock); + r = td->aborted_with_changes; + up_read(&td->pmd->root_lock); + + return r; +} + int dm_pool_alloc_data_block(struct dm_pool_metadata *pmd, dm_block_t *result) { int r; down_write(&pmd->root_lock); - r = dm_sm_new_block(pmd->data_sm, result); + r = pmd->fail_io ? -EINVAL : dm_sm_new_block(pmd->data_sm, result); up_write(&pmd->root_lock); return r; @@ -1456,6 +1492,10 @@ int dm_pool_commit_metadata(struct dm_pool_metadata *pmd) int r; down_write(&pmd->root_lock); + if (pmd->fail_io) { + r = -EINVAL; + goto out; + } r = __commit_transaction(pmd); if (r <= 0) @@ -1470,12 +1510,41 @@ out: return r; } +static void __set_abort_with_changes_flags(struct dm_pool_metadata *pmd) +{ + struct dm_thin_device *td; + + list_for_each_entry(td, &pmd->thin_devices, list) + td->aborted_with_changes = td->changed; +} + +int dm_pool_abort_metadata(struct dm_pool_metadata *pmd) +{ + int r; + + down_write(&pmd->root_lock); + if (pmd->fail_io) { + r = -EINVAL; + goto out; + } + + __set_abort_with_changes_flags(pmd); + __destroy_persistent_data_objects(pmd); + r = __create_persistent_data_objects(pmd, DM_THIN_OPEN); + if (r) + pmd->fail_io = 1; + +out: + up_write(&pmd->root_lock); + return r; +} + int dm_pool_get_free_block_count(struct dm_pool_metadata *pmd, dm_block_t *result) { int r; down_read(&pmd->root_lock); - r = dm_sm_get_nr_free(pmd->data_sm, result); + r = pmd->fail_io ? -EINVAL : dm_sm_get_nr_free(pmd->data_sm, result); up_read(&pmd->root_lock); return r; @@ -1487,7 +1556,7 @@ int dm_pool_get_free_metadata_block_count(struct dm_pool_metadata *pmd, int r; down_read(&pmd->root_lock); - r = dm_sm_get_nr_free(pmd->metadata_sm, result); + r = pmd->fail_io ? -EINVAL : dm_sm_get_nr_free(pmd->metadata_sm, result); up_read(&pmd->root_lock); return r; @@ -1499,7 +1568,7 @@ int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd, int r; down_read(&pmd->root_lock); - r = dm_sm_get_nr_blocks(pmd->metadata_sm, result); + r = pmd->fail_io ? -EINVAL : dm_sm_get_nr_blocks(pmd->metadata_sm, result); up_read(&pmd->root_lock); return r; @@ -1519,7 +1588,7 @@ int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result) int r; down_read(&pmd->root_lock); - r = dm_sm_get_nr_blocks(pmd->data_sm, result); + r = pmd->fail_io ? -EINVAL : dm_sm_get_nr_blocks(pmd->data_sm, result); up_read(&pmd->root_lock); return r; @@ -1527,13 +1596,19 @@ int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result) int dm_thin_get_mapped_count(struct dm_thin_device *td, dm_block_t *result) { + int r; struct dm_pool_metadata *pmd = td->pmd; down_read(&pmd->root_lock); - *result = td->mapped_blocks; + if (pmd->fail_io) + r = -EINVAL; + else { + *result = td->mapped_blocks; + r = 0; + } up_read(&pmd->root_lock); - return 0; + return r; } static int __highest_block(struct dm_thin_device *td, dm_block_t *result) @@ -1559,7 +1634,7 @@ int dm_thin_get_highest_mapped_block(struct dm_thin_device *td, struct dm_pool_metadata *pmd = td->pmd; down_read(&pmd->root_lock); - r = __highest_block(td, result); + r = pmd->fail_io ? -EINVAL : __highest_block(td, result); up_read(&pmd->root_lock); return r; @@ -1590,7 +1665,7 @@ int dm_pool_resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_count) int r; down_write(&pmd->root_lock); - r = __resize_data_dev(pmd, new_count); + r = pmd->fail_io ? -EINVAL : __resize_data_dev(pmd, new_count); up_write(&pmd->root_lock); return r; diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h index 19c4f8b..b7d0946 100644 --- a/drivers/md/dm-thin-metadata.h +++ b/drivers/md/dm-thin-metadata.h @@ -85,6 +85,16 @@ int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd, int dm_pool_commit_metadata(struct dm_pool_metadata *pmd); /* + * Discards all uncommitted changes. Rereads the superblock, rolling back + * to the last good transaction. Thin devices remain open, if they had + * uncommitted changes dm_thin_aborted_changes() will tell you. + * + * If this call fails it's only useful to call dm_pool_metadata_close(). + * All other methods will fail with -EINVAL. + */ +int dm_pool_abort_metadata(struct dm_pool_metadata *pmd); + +/* * Set/get userspace transaction id. */ int dm_pool_set_metadata_transaction_id(struct dm_pool_metadata *pmd, @@ -155,6 +165,8 @@ int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block); */ bool dm_thin_changed_this_transaction(struct dm_thin_device *td); +bool dm_thin_aborted_changes(struct dm_thin_device *td); + int dm_thin_get_highest_mapped_block(struct dm_thin_device *td, dm_block_t *highest_mapped); -- 1.7.1