[dm-devel] [PATCH 07/14] dm-multisnap-mikulas-commit

Mike Snitzer snitzer at redhat.com
Tue Mar 2 00:23:51 UTC 2010


From: Mikulas Patocka <mpatocka at redhat.com>

Writing the commit block.

Signed-off-by: Mikulas Patocka <mpatocka at redhat.com>
---
 drivers/md/dm-multisnap-commit.c |  245 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 245 insertions(+), 0 deletions(-)
 create mode 100644 drivers/md/dm-multisnap-commit.c

diff --git a/drivers/md/dm-multisnap-commit.c b/drivers/md/dm-multisnap-commit.c
new file mode 100644
index 0000000..78b2583
--- /dev/null
+++ b/drivers/md/dm-multisnap-commit.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2009 Red Hat Czech, s.r.o.
+ *
+ * Mikulas Patocka <mpatocka at redhat.com>
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm-multisnap-mikulas.h"
+
+/*
+ * Flush existing tmp_remaps.
+ */
+static void dm_multisnap_finalize_tmp_remaps(struct dm_exception_store *s)
+{
+	struct tmp_remap *t;
+	int i;
+
+	while (s->n_used_tmp_remaps) {
+		if (dm_multisnap_has_error(s->dm))
+			return;
+		if (s->n_used_tmp_remaps < N_REMAPS - 1) {
+			/*
+			 * prefer btree remaps ...
+			 * if there are none, do bitmap remaps
+			 */
+			if (!list_empty(&s->used_bt_tmp_remaps)) {
+				t = container_of(s->used_bt_tmp_remaps.next,
+						 struct tmp_remap, list);
+				dm_multisnap_bt_finalize_tmp_remap(s, t);
+				dm_multisnap_free_tmp_remap(s, t);
+				continue;
+			}
+		}
+
+		/* else: 0 or 1 free remaps : finalize bitmaps */
+		if (!list_empty(&s->used_bitmap_tmp_remaps)) {
+			t = container_of(s->used_bitmap_tmp_remaps.next,
+					 struct tmp_remap, list);
+			dm_multisnap_bitmap_finalize_tmp_remap(s, t);
+			dm_multisnap_free_tmp_remap(s, t);
+			continue;
+		} else {
+			DM_MULTISNAP_SET_ERROR(s->dm, -EFSERROR,
+					       ("dm_multisnap_finalize_tmp_remaps: no bitmap tmp remaps, n_used_tmp_remaps %u",
+						s->n_used_tmp_remaps));
+			return;
+		}
+	}
+
+	if (dm_multisnap_has_error(s->dm))
+		return;
+
+	for (i = s->n_preallocated_blocks - 1; i >= 0; i--)
+		dm_multisnap_free_blocks_immediate(s, s->preallocated_blocks[i], 1);
+	s->n_preallocated_blocks = 0;
+}
+
+/*
+ * This function must be called before any two b+tree modification at a point
+ * when b+tree is consistent. It flushes tmp_remaps, so that tmp_remap array
+ * doesn't overflow. This function doesn't commit anything.
+ */
+void dm_multisnap_transition_mark(struct dm_exception_store *s)
+{
+	/*
+	 * Accounting:
+	 * max number of modified/allocated blocks during btree add:
+	 *	s->bt_depth * 2 + 1
+	 * one additional entry for newly allocated data chunk
+	 * one additional entry for bitmap finalization
+	 */
+	if (unlikely(N_REMAPS - s->n_used_tmp_remaps < s->bt_depth * 2 + 3))
+		dm_multisnap_finalize_tmp_remaps(s);
+}
+
+/*
+ * Flush buffers. This is called without the lock to reduce lock contention.
+ * The buffers will be flushed again, with the lock.
+ */
+void dm_multisnap_prepare_for_commit(struct dm_exception_store *s)
+{
+	int r;
+
+	r = dm_bufio_write_dirty_buffers(s->bufio);
+	if (unlikely(r < 0)) {
+		DM_MULTISNAP_SET_ERROR(s->dm, r,
+				       ("dm_multisnap_prepare_for_commit: error writing data"));
+		return;
+	}
+}
+
+/*
+ * This function makes any modifications make so far permanent.
+ *
+ * It is valid to make multiple modifications to the exception store and
+ * then commit them atomically at once with this function.
+ */
+void dm_multisnap_commit(struct dm_exception_store *s)
+{
+	struct tmp_remap *t;
+	chunk_t cb_addr;
+	chunk_t cb_div, cb_offset;
+	struct multisnap_commit_block *cb;
+	struct multisnap_superblock *sb;
+	unsigned idx;
+	struct dm_buffer *bp;
+	int r;
+
+	dm_multisnap_transition_mark(s);
+
+	/* Forget all uncommitted blocks --- they are going to be committed */
+	dm_multisnap_clear_uncommitted(s);
+
+	dm_multisnap_flush_freelist_before_commit(s);
+
+	if (dm_multisnap_has_error(s->dm)) {
+		if (!dm_multisnap_drop_on_error(s->dm))
+			return;
+
+		sb = dm_bufio_read(s->bufio, SB_BLOCK, &bp);
+		if (IS_ERR(sb))
+			return;
+
+		if (!le32_to_cpu(sb->error)) {
+			sb->error = cpu_to_le32(dm_multisnap_has_error(s->dm));
+			dm_bufio_mark_buffer_dirty(bp);
+		}
+
+		dm_bufio_release(bp);
+		return;
+	}
+
+	list_for_each_entry(t, &s->used_bitmap_tmp_remaps, list)
+		t->uncommitted = 0;
+
+	list_for_each_entry(t, &s->used_bt_tmp_remaps, list)
+		t->uncommitted = 0;
+
+	r = dm_bufio_write_dirty_buffers(s->bufio);
+	if (unlikely(r < 0)) {
+		DM_MULTISNAP_SET_ERROR(s->dm, r,
+				       ("dm_multisnap_commit: error writing data"));
+		return;
+	}
+
+	cb_addr = s->alloc_rover;
+
+	if (cb_addr < FIRST_CB_BLOCK)
+		cb_addr = FIRST_CB_BLOCK;
+	cb_div = cb_addr - FIRST_CB_BLOCK;
+	cb_offset = sector_div(cb_div, s->cb_stride);
+	cb_addr += s->cb_stride - cb_offset;
+	if (cb_offset < s->cb_stride / 2 || cb_addr >= s->dev_size)
+		cb_addr -= s->cb_stride;
+
+	cb = dm_bufio_new(s->bufio, cb_addr, &bp);
+	if (IS_ERR(cb)) {
+		DM_MULTISNAP_SET_ERROR(s->dm, PTR_ERR(cb),
+				       ("dm_multisnap_commit: can't allocate new commit block at %llx",
+					(unsigned long long)cb_addr));
+		return;
+	}
+
+	s->commit_sequence++;
+
+	cb->signature = CB_SIGNATURE;
+	cb->snapshot_num = cpu_to_le32(s->snapshot_num);
+	cb->sequence = cpu_to_le64(s->commit_sequence);
+	write_48(cb, dev_size, s->dev_size);
+	write_48(cb, total_allocated, s->total_allocated);
+	write_48(cb, data_allocated, s->data_allocated);
+	write_48(cb, bitmap_root, s->bitmap_root);
+	write_48(cb, alloc_rover, s->alloc_rover);
+	write_48(cb, freelist, s->freelist_ptr);
+	write_48(cb, delete_rover, s->delete_rover_chunk);
+	write_48(cb, bt_root, s->bt_root);
+	cb->bt_depth = s->bt_depth;
+	cb->flags = s->flags;
+	memset(cb->pad, 0, sizeof cb->pad);
+	idx = 0;
+	list_for_each_entry(t, &s->used_bitmap_tmp_remaps, list) {
+		BUG_ON(idx >= N_REMAPS);
+		write_48(&cb->tmp_remap[idx], old, t->old);
+		write_48(&cb->tmp_remap[idx], new, t->new);
+		cb->tmp_remap[idx].bitmap_idx = cpu_to_le32(t->bitmap_idx);
+		idx++;
+	}
+	list_for_each_entry(t, &s->used_bt_tmp_remaps, list) {
+		BUG_ON(idx >= N_REMAPS);
+		write_48(&cb->tmp_remap[idx], old, t->old);
+		write_48(&cb->tmp_remap[idx], new, t->new);
+		cb->tmp_remap[idx].bitmap_idx = cpu_to_le32(t->bitmap_idx);
+		idx++;
+	}
+	for (; idx < N_REMAPS; idx++) {
+		write_48(&cb->tmp_remap[idx], old, 0);
+		write_48(&cb->tmp_remap[idx], new, 0);
+		cb->tmp_remap[idx].bitmap_idx = cpu_to_le32(0);
+	}
+	dm_bufio_mark_buffer_dirty(bp);
+	dm_bufio_release(bp);
+	r = dm_bufio_write_dirty_buffers(s->bufio);
+	if (unlikely(r < 0)) {
+		DM_MULTISNAP_SET_ERROR(s->dm, r,
+				       ("dm_multisnap_commit: can't write commit block at %llx",
+					(unsigned long long)cb_addr));
+		return;
+	}
+
+	if (likely(cb_addr == s->valid_commit_block) ||
+	    likely(cb_addr == s->valid_commit_block + s->cb_stride))
+		goto return_success;
+
+	sb = dm_bufio_read(s->bufio, SB_BLOCK, &bp);
+	if (IS_ERR(sb)) {
+		DM_MULTISNAP_SET_ERROR(s->dm, PTR_ERR(sb),
+				       ("dm_multisnap_commit: can't read super block"));
+		return;
+	}
+
+	if (unlikely(sb->signature != SB_SIGNATURE)) {
+		dm_bufio_release(bp);
+		DM_MULTISNAP_SET_ERROR(s->dm, -EFSERROR,
+				       ("dm_multisnap_commit: invalid super block signature when committing"));
+		return;
+	}
+
+	sb->commit_block = cpu_to_le64(cb_addr);
+
+	dm_bufio_mark_buffer_dirty(bp);
+	dm_bufio_release(bp);
+	r = dm_bufio_write_dirty_buffers(s->bufio);
+	if (unlikely(r < 0)) {
+		DM_MULTISNAP_SET_ERROR(s->dm, r, ("dm_multisnap_commit: can't write super block"));
+		return;
+	}
+
+return_success:
+	s->valid_commit_block = cb_addr;
+
+	dm_multisnap_load_freelist(s);
+
+	return;
+}
-- 
1.6.5.2




More information about the dm-devel mailing list