tux3: Add ->leaf_pre_write() callback to btree_write()
For overwrite mode, we don't want to dirty leaf if all extents are
exists already.
But, current btree_write() dirty leaf unconditionally. So, this adds
->leaf_pre_write() callback before dirty leaf.
With this, leaf operations can control whether leaf is dirtied or not.
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
diff --git a/fs/tux3/btree.c b/fs/tux3/btree.c
index d414efb..04d0655 100644
--- a/fs/tux3/btree.c
+++ b/fs/tux3/btree.c
@@ -1161,6 +1161,12 @@
return 0;
}
+int noop_pre_write(struct btree *btree, tuxkey_t key_bottom, tuxkey_t key_limit,
+ void *leaf, struct btree_key_range *key)
+{
+ return BTREE_DO_DIRTY;
+}
+
int btree_write(struct cursor *cursor, struct btree_key_range *key)
{
struct btree *btree = cursor->btree;
@@ -1171,34 +1177,46 @@
while (key->len > 0) {
tuxkey_t bottom, limit;
void *leaf;
- int need_split;
+ int ret;
err = btree_advance(cursor, key);
if (err)
return err; /* FIXME: error handling */
- err = cursor_redirect(cursor);
- if (err)
- return err; /* FIXME: error handling */
-
bottom = cursor_this_key(cursor);
limit = cursor_next_key(cursor);
- leaf = bufdata(cursor_leafbuf(cursor));
assert(bottom <= key->start && key->start < limit);
- assert(ops->leaf_sniff(btree, leaf));
- need_split = ops->leaf_write(btree, bottom, limit, leaf, key,
- &split_hint);
- if (need_split < 0)
- return need_split;
- else if (!need_split) {
- mark_buffer_dirty_non(cursor_leafbuf(cursor));
+ leaf = bufdata(cursor_leafbuf(cursor));
+ ret = ops->leaf_pre_write(btree, bottom, limit, leaf, key);
+ assert(ret >= 0);
+ if (ret == BTREE_DO_RETRY)
continue;
+
+ if (ret == BTREE_DO_DIRTY) {
+ err = cursor_redirect(cursor);
+ if (err)
+ return err; /* FIXME: error handling */
+
+ /* Reread leaf after redirect */
+ leaf = bufdata(cursor_leafbuf(cursor));
+ assert(ops->leaf_sniff(btree, leaf));
+
+ ret = ops->leaf_write(btree, bottom, limit, leaf, key,
+ &split_hint);
+ if (ret < 0)
+ return ret;
+ if (ret == BTREE_DO_RETRY) {
+ mark_buffer_dirty_non(cursor_leafbuf(cursor));
+ continue;
+ }
}
- err = btree_leaf_split(cursor, key->start, split_hint);
- if (err)
- return err; /* FIXME: error handling */
+ if (ret == BTREE_DO_SPLIT) {
+ err = btree_leaf_split(cursor, key->start, split_hint);
+ if (err)
+ return err; /* FIXME: error handling */
+ }
}
return 0;
diff --git a/fs/tux3/dleaf2.c b/fs/tux3/dleaf2.c
index fa424c6..4c40681 100644
--- a/fs/tux3/dleaf2.c
+++ b/fs/tux3/dleaf2.c
@@ -676,7 +676,7 @@
goto need_split;
}
- return 0;
+ return BTREE_DO_RETRY;
need_split:
/* FIXME: do we should split at sentinel when filling hole? */
@@ -690,13 +690,13 @@
tux3_dbg("key %Lu bottom %Lu, limit %Lu, hint %Lu",
key->start, key_bottom, key_limit,
*split_hint);
- return 1;
+ return BTREE_DO_SPLIT;
}
}
/* FIXME: use better split position */
*split_hint = dleaf2_split_at_center(dleaf);
- return 1; /* try to split dleaf2 */
+ return BTREE_DO_SPLIT;
}
/* Read extents */
@@ -774,6 +774,7 @@
.leaf_split = dleaf2_split,
.leaf_merge = dleaf2_merge,
.leaf_chop = dleaf2_chop,
+ .leaf_pre_write = noop_pre_write,
.leaf_write = dleaf2_write,
.leaf_read = dleaf2_read,
.balloc = balloc,
diff --git a/fs/tux3/ileaf.c b/fs/tux3/ileaf.c
index 6cbbd5b..a3c747c 100644
--- a/fs/tux3/ileaf.c
+++ b/fs/tux3/ileaf.c
@@ -441,7 +441,7 @@
if (attrs == NULL) {
/* There is no space to store */
*split_hint = ileaf_split_hint(btree, ileaf, key->start, size);
- return 1; /* need to split */
+ return BTREE_DO_SPLIT;
}
attr_ops->encode(btree, rq->data, attrs, size);
@@ -449,7 +449,7 @@
key->start++;
key->len--;
- return 0;
+ return BTREE_DO_RETRY;
}
static int ileaf_read(struct btree *btree, tuxkey_t key_bottom,
@@ -475,6 +475,7 @@
.leaf_split = ileaf_split,
.leaf_merge = ileaf_merge,
.leaf_chop = ileaf_chop,
+ .leaf_pre_write = noop_pre_write,
.leaf_write = ileaf_write,
.leaf_read = ileaf_read,
.balloc = balloc,
@@ -491,6 +492,7 @@
.leaf_split = ileaf_split,
.leaf_merge = ileaf_merge,
.leaf_chop = ileaf_chop,
+ .leaf_pre_write = noop_pre_write,
.leaf_write = ileaf_write,
.leaf_read = ileaf_read,
.balloc = balloc,
diff --git a/fs/tux3/tux3.h b/fs/tux3/tux3.h
index 2519115..c073f3b 100644
--- a/fs/tux3/tux3.h
+++ b/fs/tux3/tux3.h
@@ -557,6 +557,12 @@
unsigned len;
};
+enum btree_result {
+ BTREE_DO_RETRY = 0,
+ BTREE_DO_DIRTY,
+ BTREE_DO_SPLIT,
+};
+
struct btree_ops {
void (*btree_init)(struct btree *btree);
int (*leaf_init)(struct btree *btree, void *leaf);
@@ -565,7 +571,9 @@
int (*leaf_chop)(struct btree *btree, tuxkey_t start, u64 len, void *leaf);
/* return value: 1 - merged, 0 - couldn't merge */
int (*leaf_merge)(struct btree *btree, void *into, void *from);
- /* return value: 1 - need to split leaf, 0 - success, < 0 - error */
+ /* return value: < 0 - error, 0 >= - btree_result */
+ int (*leaf_pre_write)(struct btree *btree, tuxkey_t key_bottom, tuxkey_t key_limit, void *leaf, struct btree_key_range *key);
+ /* return value: < 0 - error, 0 >= - btree_result */
int (*leaf_write)(struct btree *btree, tuxkey_t key_bottom, tuxkey_t key_limit, void *leaf, struct btree_key_range *key, tuxkey_t *split_hint);
int (*leaf_read)(struct btree *btree, tuxkey_t key_bottom, tuxkey_t key_limit, void *leaf, struct btree_key_range *key);
int (*balloc)(struct sb *sb, unsigned blocks, struct block_segment *seg, int segs);
@@ -721,6 +729,8 @@
int btree_chop(struct btree *btree, tuxkey_t start, u64 len);
int btree_insert_leaf(struct cursor *cursor, tuxkey_t key, struct buffer_head *leafbuf);
void *btree_expand(struct cursor *cursor, tuxkey_t key, unsigned newsize);
+int noop_pre_write(struct btree *btree, tuxkey_t key_bottom, tuxkey_t key_limit,
+ void *leaf, struct btree_key_range *key);
int btree_write(struct cursor *cursor, struct btree_key_range *key);
int btree_read(struct cursor *cursor, struct btree_key_range *key);
void show_tree_range(struct btree *btree, tuxkey_t start, unsigned count);