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