Callbacks from dm-multisnap.c These functions are called directly from exception-store-neutral code. The find the chunk or perform chunk reallocations. Signed-off-by: Mikulas Patocka --- drivers/md/dm-multisnap-io.c | 209 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) Index: linux-2.6.32-devel/drivers/md/dm-multisnap-io.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.32-devel/drivers/md/dm-multisnap-io.c 2009-12-16 08:32:42.000000000 +0100 @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2009 Red Hat Czech, s.r.o. + * + * Mikulas Patocka + * + * This file is released under the GPL. + */ + +#include "dm-multisnap-mikulas.h" + +/* + * This function will check if there is remapping for a given snapid/chunk. + * It returns 1 if remapping exists and is read-only (shared by other snapshots) + * and 2 if it exists and is read-write (not shared by anyone). + */ + +int dm_multisnap_find_snapshot_chunk(struct dm_exception_store *s, snapid_t snapid, chunk_t chunk, int write, chunk_t *result) +{ + int r; + struct bt_key key; + mikulas_snapid_t from, to; + mikulas_snapid_t find_from, find_to; + + from = dm_multisnap_find_next_subsnapshot(s, snapid); + to = snapid; + + key.chunk = chunk; + key.snap_from = snapid; + key.snap_to = snapid; + r = dm_multisnap_find_in_btree(s, &key, result); + if (unlikely(r < 0)) + return r; + + if (!r) { + s->query_new_key.chunk = chunk; + s->query_new_key.snap_from = from; + s->query_new_key.snap_to = to; + s->query_active = 1; + return 0; + } + + if (!write) + return 1; + + /* + * We are writing to a snapshot --- check if anything outside + * range exists, if it does, it needs to be copied. + */ + + if (key.snap_from < from) { + if (likely(dm_multisnap_find_next_snapid_range(s, key.snap_from, &find_from, &find_to))) { + if (find_from < from) { + s->query_new_key.chunk = chunk; + s->query_new_key.snap_from = from; + s->query_new_key.snap_to = key.snap_to; + s->query_block_from = key.snap_from; + s->query_block_to = key.snap_to; + s->query_active = 2; + return 1; + } + if (unlikely(find_from > from)) + BUG(); /* SNAPID not in our tree */ + } else + BUG(); /* we're asking for a SNAPID not in our tree */ + } + if (key.snap_to > to) { + if (likely(dm_multisnap_find_next_snapid_range(s, to + 1, &find_from, &find_to))) { + if (find_from <= key.snap_to) { + s->query_new_key.chunk = chunk; + s->query_new_key.snap_from = key.snap_from; + s->query_new_key.snap_to = to; + s->query_block_from = key.snap_from; + s->query_block_to = key.snap_to; + s->query_active = 2; + return 1; + } + } + } + return 2; +} + +/* + * Reset the query/remap state machine. + */ + +void dm_multisnap_reset_query(struct dm_exception_store *s) +{ + s->query_active = 0; + s->query_snapid = 0; +} + +/* + * Find the next snapid range to remap. + */ + +int dm_multisnap_query_next_remap(struct dm_exception_store *s, chunk_t chunk) +{ + int r; + chunk_t sink; + mikulas_snapid_t from, to; + + s->query_active = 0; + + while (dm_multisnap_find_next_snapid_range(s, s->query_snapid, &from, &to)) { + struct bt_key key; +next_btree_search: + if (dm_multisnap_has_error(s->dm)) + return -1; + key.chunk = chunk; + key.snap_from = from; + key.snap_to = to; + r = dm_multisnap_find_in_btree(s, &key, &sink); + if (unlikely(r < 0)) + return -1; + + if (!r) { + s->query_new_key.chunk = chunk; + s->query_new_key.snap_from = from; + s->query_new_key.snap_to = to; + s->query_active = 1; + return 1; + } + + if (key.snap_from > from) { + s->query_new_key.chunk = chunk; + s->query_new_key.snap_from = from; + s->query_new_key.snap_to = key.snap_from - 1; + s->query_active = 1; + return 1; + } + + if (key.snap_to < to) { + from = key.snap_to + 1; + goto next_btree_search; + } + + s->query_snapid = to + 1; + } + + return 0; +} + +/* + * Perform the remap on the range returned by dm_multisnap_query_next_remap. + */ + +void dm_multisnap_add_next_remap(struct dm_exception_store *s, union chunk_descriptor *cd, chunk_t *new_chunk) +{ + int r; + + BUG_ON(s->query_active != 1); + s->query_active = 0; + + cd->range.from = s->query_new_key.snap_from; + cd->range.to = s->query_new_key.snap_to; + + r = dm_multisnap_alloc_blocks(s, new_chunk, 1, 0); + if (unlikely(r < 0)) + return; + + dm_multisnap_status_lock(s->dm); + s->data_allocated++; + dm_multisnap_status_unlock(s->dm); + + dm_multisnap_add_to_btree(s, &s->query_new_key, *new_chunk); + dm_multisnap_transaction_mark(s); +} + +/* + * Make the chunk writeable (i.e. unshare multiple snapshots). + */ + +void dm_multisnap_make_chunk_writeable(struct dm_exception_store *s, union chunk_descriptor *cd, chunk_t *new_chunk) +{ + int r; + + BUG_ON(s->query_active != 2); + s->query_active = 0; + + cd->range.from = s->query_block_from; + cd->range.to = s->query_block_to; + + r = dm_multisnap_alloc_blocks(s, new_chunk, 1, 0); + if (unlikely(r < 0)) + return; + + dm_multisnap_status_lock(s->dm); + s->data_allocated++; + dm_multisnap_status_unlock(s->dm); + + dm_multisnap_restrict_btree_entry(s, &s->query_new_key); + dm_multisnap_transaction_mark(s); + + if (unlikely(dm_multisnap_has_error(s->dm))) + return; + + dm_multisnap_add_to_btree(s, &s->query_new_key, *new_chunk); + dm_multisnap_transaction_mark(s); +} + +/* + * Check if the snapshot belongs to the remap range specified by "cd". + */ + +int dm_multisnap_check_conflict(struct dm_exception_store *s, union chunk_descriptor *cd, snapid_t snapid) +{ + return snapid >= cd->range.from && snapid <= cd->range.to; +} +