diff options
Diffstat (limited to 'drivers/md/dm-thin-metadata.c')
-rw-r--r-- | drivers/md/dm-thin-metadata.c | 114 |
1 files changed, 76 insertions, 38 deletions
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index c219a053c..f962d6453 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -1395,8 +1395,21 @@ static bool __snapshotted_since(struct dm_thin_device *td, uint32_t time) return td->snapshotted_time > time; } -int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block, - int can_issue_io, struct dm_thin_lookup_result *result) +static void unpack_lookup_result(struct dm_thin_device *td, __le64 value, + struct dm_thin_lookup_result *result) +{ + uint64_t block_time = 0; + dm_block_t exception_block; + uint32_t exception_time; + + block_time = le64_to_cpu(value); + unpack_block_time(block_time, &exception_block, &exception_time); + result->block = exception_block; + result->shared = __snapshotted_since(td, exception_time); +} + +static int __find_block(struct dm_thin_device *td, dm_block_t block, + int can_issue_io, struct dm_thin_lookup_result *result) { int r; __le64 value; @@ -1404,39 +1417,56 @@ int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block, dm_block_t keys[2] = { td->id, block }; struct dm_btree_info *info; - down_read(&pmd->root_lock); - if (pmd->fail_io) { - up_read(&pmd->root_lock); - return -EINVAL; - } - if (can_issue_io) { info = &pmd->info; } else info = &pmd->nb_info; r = dm_btree_lookup(info, pmd->root, keys, &value); - if (!r) { - uint64_t block_time = 0; - dm_block_t exception_block; - uint32_t exception_time; - - block_time = le64_to_cpu(value); - unpack_block_time(block_time, &exception_block, - &exception_time); - result->block = exception_block; - result->shared = __snapshotted_since(td, exception_time); + if (!r) + unpack_lookup_result(td, value, result); + + return r; +} + +int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block, + int can_issue_io, struct dm_thin_lookup_result *result) +{ + int r; + struct dm_pool_metadata *pmd = td->pmd; + + down_read(&pmd->root_lock); + if (pmd->fail_io) { + up_read(&pmd->root_lock); + return -EINVAL; } + r = __find_block(td, block, can_issue_io, result); + up_read(&pmd->root_lock); return r; } -/* FIXME: write a more efficient one in btree */ -int dm_thin_find_mapped_range(struct dm_thin_device *td, - dm_block_t begin, dm_block_t end, - dm_block_t *thin_begin, dm_block_t *thin_end, - dm_block_t *pool_begin, bool *maybe_shared) +static int __find_next_mapped_block(struct dm_thin_device *td, dm_block_t block, + dm_block_t *vblock, + struct dm_thin_lookup_result *result) +{ + int r; + __le64 value; + struct dm_pool_metadata *pmd = td->pmd; + dm_block_t keys[2] = { td->id, block }; + + r = dm_btree_lookup_next(&pmd->info, pmd->root, keys, vblock, &value); + if (!r) + unpack_lookup_result(td, value, result); + + return r; +} + +static int __find_mapped_range(struct dm_thin_device *td, + dm_block_t begin, dm_block_t end, + dm_block_t *thin_begin, dm_block_t *thin_end, + dm_block_t *pool_begin, bool *maybe_shared) { int r; dm_block_t pool_end; @@ -1445,21 +1475,11 @@ int dm_thin_find_mapped_range(struct dm_thin_device *td, if (end < begin) return -ENODATA; - /* - * Find first mapped block. - */ - while (begin < end) { - r = dm_thin_find_block(td, begin, true, &lookup); - if (r) { - if (r != -ENODATA) - return r; - } else - break; - - begin++; - } + r = __find_next_mapped_block(td, begin, &begin, &lookup); + if (r) + return r; - if (begin == end) + if (begin >= end) return -ENODATA; *thin_begin = begin; @@ -1469,7 +1489,7 @@ int dm_thin_find_mapped_range(struct dm_thin_device *td, begin++; pool_end = *pool_begin + 1; while (begin != end) { - r = dm_thin_find_block(td, begin, true, &lookup); + r = __find_block(td, begin, true, &lookup); if (r) { if (r == -ENODATA) break; @@ -1489,6 +1509,24 @@ int dm_thin_find_mapped_range(struct dm_thin_device *td, return 0; } +int dm_thin_find_mapped_range(struct dm_thin_device *td, + dm_block_t begin, dm_block_t end, + dm_block_t *thin_begin, dm_block_t *thin_end, + dm_block_t *pool_begin, bool *maybe_shared) +{ + int r = -EINVAL; + struct dm_pool_metadata *pmd = td->pmd; + + down_read(&pmd->root_lock); + if (!pmd->fail_io) { + r = __find_mapped_range(td, begin, end, thin_begin, thin_end, + pool_begin, maybe_shared); + } + up_read(&pmd->root_lock); + + return r; +} + static int __insert(struct dm_thin_device *td, dm_block_t block, dm_block_t data_block) { |