<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">Writing the commit block.

Signed-off-by: Mikulas Patocka &lt;mpatocka@redhat.com&gt;

---
 drivers/md/dm-multisnap-commit.c |  227 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 227 insertions(+)

Index: linux-2.6.32/drivers/md/dm-multisnap-commit.c
===================================================================
--- /dev/null
+++ linux-2.6.32/drivers/md/dm-multisnap-commit.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2009 Red Hat Czech, s.r.o.
+ *
+ * Mikulas Patocka &lt;mpatocka@redhat.com&gt;
+ *
+ * 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-&gt;n_used_tmp_remaps) {
+		if (dm_multisnap_has_error(s-&gt;dm))
+			return;
+		if (s-&gt;n_used_tmp_remaps &lt; N_REMAPS - 1) {
+			/*
+			 * prefer btree remaps ...
+			 * if there are none, do bitmap remaps
+			 */
+			if (!list_empty(&amp;s-&gt;used_bt_tmp_remaps)) {
+				t = container_of(s-&gt;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(&amp;s-&gt;used_bitmap_tmp_remaps)) {
+			t = container_of(s-&gt;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 {
+			DMERR("dm_multisnap_finalize_tmp_remaps: no bitmap tmp remaps, n_used_tmp_remaps %u", s-&gt;n_used_tmp_remaps);
+			dm_multisnap_set_error(s-&gt;dm, -EFSERROR);
+			return;
+		}
+	}
+
+	if (dm_multisnap_has_error(s-&gt;dm))
+		return;
+
+	for (i = s-&gt;n_preallocated_blocks - 1; i &gt;= 0; i--)
+		dm_multisnap_free_blocks_immediate(s, s-&gt;preallocated_blocks[i], 1);
+	s-&gt;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_transaction_mark(struct dm_exception_store *s)
+{
+	/*
+	 * Accounting:
+	 * max number of modified/allocated blocks during btree add:
+	 *	s-&gt;bt_depth * 2 + 1
+	 * one additional entry for newly allocated data chunk
+	 * one additional entry for bitmap finalization
+	 */
+	if (unlikely(N_REMAPS - s-&gt;n_used_tmp_remaps &lt; s-&gt;bt_depth * 2 + 3))
+		dm_multisnap_finalize_tmp_remaps(s);
+}
+
+/*
+ * 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_transaction_mark(s);
+
+	dm_multisnap_flush_freelist_before_commit(s);
+
+	if (dm_multisnap_has_error(s-&gt;dm)) {
+		struct multisnap_superblock *sb;
+
+		if (!dm_multisnap_drop_on_error(s-&gt;dm))
+			return;
+
+		sb = dm_bufio_read(s-&gt;bufio, SB_BLOCK, &amp;bp);
+		if (IS_ERR(sb))
+			return;
+
+		if (!le32_to_cpu(sb-&gt;error)) {
+			sb-&gt;error = cpu_to_le32(dm_multisnap_has_error(s-&gt;dm));
+			dm_bufio_mark_buffer_dirty(bp);
+		}
+
+		dm_bufio_release(bp);
+		return;
+	}
+
+	list_for_each_entry(t, &amp;s-&gt;used_bitmap_tmp_remaps, list)
+		t-&gt;uncommitted = 0;
+
+	list_for_each_entry(t, &amp;s-&gt;used_bt_tmp_remaps, list)
+		t-&gt;uncommitted = 0;
+
+	r = dm_bufio_write_dirty_buffers(s-&gt;bufio);
+	if (unlikely(r &lt; 0)) {
+		DMERR("dm_multisnap_commit: error writing data");
+		dm_multisnap_set_error(s-&gt;dm, r);
+		return;
+	}
+
+	cb_addr = s-&gt;alloc_rover;
+
+	if (cb_addr &lt; FIRST_CB_BLOCK)
+		cb_addr = FIRST_CB_BLOCK;
+	cb_div = cb_addr - FIRST_CB_BLOCK;
+	cb_offset = sector_div(cb_div, s-&gt;cb_stride);
+	cb_addr += s-&gt;cb_stride - cb_offset;
+	if (cb_offset &lt; s-&gt;cb_stride / 2 || cb_addr &gt;= s-&gt;dev_size)
+		cb_addr -= s-&gt;cb_stride;
+
+	cb = dm_bufio_new(s-&gt;bufio, cb_addr, &amp;bp);
+	if (IS_ERR(cb)) {
+		DMERR("dm_multisnap_commit: can't allocate new commit block at %llx", (unsigned long long)cb_addr);
+		dm_multisnap_set_error(s-&gt;dm, PTR_ERR(cb));
+		return;
+	}
+
+	s-&gt;commit_sequence++;
+
+	cb-&gt;signature = CB_SIGNATURE;
+	cb-&gt;snapshot_num = cpu_to_le32(s-&gt;snapshot_num);
+	cb-&gt;sequence = cpu_to_le64(s-&gt;commit_sequence);
+	write_48(cb, dev_size, s-&gt;dev_size);
+	write_48(cb, total_allocated, s-&gt;total_allocated);
+	write_48(cb, data_allocated, s-&gt;data_allocated);
+	write_48(cb, bitmap_root, s-&gt;bitmap_root);
+	write_48(cb, alloc_rover, s-&gt;alloc_rover);
+	write_48(cb, freelist, s-&gt;freelist_ptr);
+	write_48(cb, delete_rover, s-&gt;delete_rover_chunk);
+	write_48(cb, bt_root, s-&gt;bt_root);
+	cb-&gt;bt_depth = s-&gt;bt_depth;
+	cb-&gt;flags = s-&gt;flags;
+	memset(cb-&gt;pad, 0, sizeof cb-&gt;pad);
+	idx = 0;
+	list_for_each_entry(t, &amp;s-&gt;used_bitmap_tmp_remaps, list) {
+		BUG_ON(idx &gt;= N_REMAPS);
+		write_48(&amp;cb-&gt;tmp_remap[idx], old, t-&gt;old);
+		write_48(&amp;cb-&gt;tmp_remap[idx], new, t-&gt;new);
+		cb-&gt;tmp_remap[idx].bitmap_idx = cpu_to_le32(t-&gt;bitmap_idx);
+		idx++;
+	}
+	list_for_each_entry(t, &amp;s-&gt;used_bt_tmp_remaps, list) {
+		BUG_ON(idx &gt;= N_REMAPS);
+		write_48(&amp;cb-&gt;tmp_remap[idx], old, t-&gt;old);
+		write_48(&amp;cb-&gt;tmp_remap[idx], new, t-&gt;new);
+		cb-&gt;tmp_remap[idx].bitmap_idx = cpu_to_le32(t-&gt;bitmap_idx);
+		idx++;
+	}
+	for (; idx &lt; N_REMAPS; idx++) {
+		write_48(&amp;cb-&gt;tmp_remap[idx], old, 0);
+		write_48(&amp;cb-&gt;tmp_remap[idx], new, 0);
+		cb-&gt;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-&gt;bufio);
+	if (unlikely(r &lt; 0)) {
+		DMERR("dm_multisnap_commit: can't write commit block at %llx", (unsigned long long)cb_addr);
+		dm_multisnap_set_error(s-&gt;dm, r);
+		return;
+	}
+
+	if (likely(cb_addr == s-&gt;valid_commit_block) ||
+	    likely(cb_addr == s-&gt;valid_commit_block + s-&gt;cb_stride))
+		goto return_success;
+
+	sb = dm_bufio_read(s-&gt;bufio, SB_BLOCK, &amp;bp);
+	if (IS_ERR(sb)) {
+		DMERR("dm_multisnap_commit: can't read super block");
+		dm_multisnap_set_error(s-&gt;dm, PTR_ERR(sb));
+		return;
+	}
+
+	if (unlikely(sb-&gt;signature != SB_SIGNATURE)) {
+		dm_bufio_release(bp);
+		DMERR("dm_multisnap_commit: invalid super block signature when committing");
+		dm_multisnap_set_error(s-&gt;dm, -EFSERROR);
+		return;
+	}
+
+	sb-&gt;commit_block = cpu_to_le64(cb_addr);
+
+	dm_bufio_mark_buffer_dirty(bp);
+	dm_bufio_release(bp);
+	r = dm_bufio_write_dirty_buffers(s-&gt;bufio);
+	if (unlikely(r &lt; 0)) {
+		DMERR("dm_multisnap_commit: can't write super block");
+		dm_multisnap_set_error(s-&gt;dm, r);
+		return;
+	}
+
+return_success:
+	s-&gt;valid_commit_block = cb_addr;
+
+	dm_multisnap_load_freelist(s);
+
+	return;
+}
</pre></body></html>