Here is a prototype of block redirect for btree nodes.  It has not been tested 
at all, it just compiles (patch attached).  It has one severe deficiency: it 
can't handle redirecting the root of a btree because the btree cursor does not 
know where the btree root is cached.

To place this in conext, redirect on write comes in two distinctly different 
flavors:

  Redirect a data extent in file page cache:
    - Logically mapped
        - no need to relocate data blocks in cache
        - just need to update pointer in parent (dleaf)
    - Handled by map_region

  Redirect a btree node in volume cache:
    - Physically mapped
        - need to move data to a new buffer and release old
    - Handled various functions in btree.c

In either case, we are releasing some data blocks and allocating new ones, 
because the contents of cache has changed and we need to place it on disk 
without overwriting any part of the existing, stable filesystem image.

int redirect(struct cursor *cursor, unsigned level)
{
        struct btree *btree = cursor->btree;
        struct sb *sb = btree->sb;
        struct buffer_head *buffer = cursor->path[level].buffer;
        assert(buffer->state >= BUFFER_DIRTY);
        block_t child;
        int err = balloc(sb, 1, &child);
        if (err)
                return err;
        struct buffer_head *shadow = blockget(mapping(sb->volmap), child);
        if (!shadow)
                return -ENOMEM; // ERR_PTR me!!!
        memcpy(bufdata(shadow), bufdata(buffer), sb->blocksize);
        cursor->path[level].buffer = shadow;
        cursor->path[level].next += bufdata(shadow) - bufdata(buffer);
        brelse(buffer);

        // what about redirecting root??? cursor needs to know where root is.
        struct index_entry *entry = cursor->path[level - 1].next - 1;
        block_t parent = bufindex(cursor->path[level - 1].buffer);
        log_alloc(sb, from_be_u64(entry->block), 1, 0);
        log_alloc(sb, child, 1, 1); // implied by update???
        log_update(sb, child, parent, from_be_u64(entry->key));
        entry->block = to_be_u64(child);
        // add old block to free-at-end-of-delta list
        // set_buffer_state(shadow, sb->delta & (BUFFER_DIRTY_STATES - 1));
        return 0;
}
diff -r 3279337c3d7d user/btree.c
--- a/user/btree.c	Tue Jan 13 01:27:28 2009 -0800
+++ b/user/btree.c	Tue Jan 13 01:44:27 2009 -0800
@@ -22,7 +22,8 @@
 #define trace trace_off
 #endif
 
-#include "tux3.h"	/* include user/tux3.h, not user/kernel/tux3.h */
+#include "tux3.h"
+#include "kernel/log.c"
 #include "kernel/btree.c"
 
 #ifndef main
diff -r 3279337c3d7d user/commit.c
--- a/user/commit.c	Tue Jan 13 01:27:28 2009 -0800
+++ b/user/commit.c	Tue Jan 13 01:44:27 2009 -0800
@@ -14,7 +14,6 @@
 
 #define include_inode_c
 #include "inode.c"
-#include "kernel/log.c"
 
 void replay(struct sb *sb)
 {
diff -r 3279337c3d7d user/filemap.c
--- a/user/filemap.c	Tue Jan 13 01:27:28 2009 -0800
+++ b/user/filemap.c	Tue Jan 13 01:44:27 2009 -0800
@@ -11,6 +11,7 @@
 
 #include "kernel/xattr.c"
 #include "kernel/dleaf.c"
+#include "kernel/log.c"
 #include "kernel/btree.c"
 #include "kernel/iattr.c"
 #include "kernel/ileaf.c"
diff -r 3279337c3d7d user/kernel/btree.c
--- a/user/kernel/btree.c	Tue Jan 13 01:27:28 2009 -0800
+++ b/user/kernel/btree.c	Tue Jan 13 01:44:27 2009 -0800
@@ -250,6 +250,36 @@ eek:
 eek:
 	release_cursor(cursor);
 	return -EIO; /* stupid, it might have been NOMEM */
+}
+
+int redirect(struct cursor *cursor, unsigned level)
+{
+	struct btree *btree = cursor->btree;
+	struct sb *sb = btree->sb;
+	struct buffer_head *buffer = cursor->path[level].buffer;
+	assert(buffer->state >= BUFFER_DIRTY);
+	block_t child;
+	int err = balloc(sb, 1, &child);
+	if (err)
+		return err;
+	struct buffer_head *shadow = blockget(mapping(sb->volmap), child);
+	if (!shadow)
+		return -ENOMEM; // ERR_PTR me!!!
+	memcpy(bufdata(shadow), bufdata(buffer), sb->blocksize);
+	cursor->path[level].buffer = shadow;
+	cursor->path[level].next += bufdata(shadow) - bufdata(buffer);
+	brelse(buffer);
+
+	// what about redirecting root??? cursor needs to know where root is.
+	struct index_entry *entry = cursor->path[level - 1].next - 1;
+	block_t parent = bufindex(cursor->path[level - 1].buffer);
+	log_alloc(sb, from_be_u64(entry->block), 1, 0);
+	log_alloc(sb, child, 1, 1); // implied by update???
+	log_update(sb, child, parent, from_be_u64(entry->key));
+	entry->block = to_be_u64(child);
+	// add old block to free-at-end-of-delta list
+	// set_buffer_state(shadow, sb->delta & (BUFFER_DIRTY_STATES - 1));
+	return 0;
 }
 
 int advance(struct btree *btree, struct cursor *cursor)
_______________________________________________
Tux3 mailing list
[email protected]
http://mailman.tux3.org/cgi-bin/mailman/listinfo/tux3

Reply via email to