Merge branch 'bkl/ioctl' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic...
[safe/jmp/linux-2.6] / fs / nilfs2 / btree.c
index 115b157..b27a342 100644 (file)
 #include "alloc.h"
 #include "dat.h"
 
-/**
- * struct nilfs_btree_path - A path on which B-tree operations are executed
- * @bp_bh: buffer head of node block
- * @bp_sib_bh: buffer head of sibling node block
- * @bp_index: index of child node
- * @bp_oldreq: ptr end request for old ptr
- * @bp_newreq: ptr alloc request for new ptr
- * @bp_op: rebalance operation
- */
-struct nilfs_btree_path {
-       struct buffer_head *bp_bh;
-       struct buffer_head *bp_sib_bh;
-       int bp_index;
-       union nilfs_bmap_ptr_req bp_oldreq;
-       union nilfs_bmap_ptr_req bp_newreq;
-       struct nilfs_btnode_chkey_ctxt bp_ctxt;
-       void (*bp_op)(struct nilfs_btree *, struct nilfs_btree_path *,
-                     int, __u64 *, __u64 *);
-};
-
-/*
- * B-tree path operations
- */
-
-static struct kmem_cache *nilfs_btree_path_cache;
-
-int __init nilfs_btree_path_cache_init(void)
-{
-       nilfs_btree_path_cache =
-               kmem_cache_create("nilfs2_btree_path_cache",
-                                 sizeof(struct nilfs_btree_path) *
-                                 NILFS_BTREE_LEVEL_MAX, 0, 0, NULL);
-       return (nilfs_btree_path_cache != NULL) ? 0 : -ENOMEM;
-}
-
-void nilfs_btree_path_cache_destroy(void)
+static struct nilfs_btree_path *nilfs_btree_alloc_path(void)
 {
-       kmem_cache_destroy(nilfs_btree_path_cache);
-}
-
-static inline struct nilfs_btree_path *nilfs_btree_alloc_path(void)
-{
-       return kmem_cache_alloc(nilfs_btree_path_cache, GFP_NOFS);
-}
-
-static inline void nilfs_btree_free_path(struct nilfs_btree_path *path)
-{
-       kmem_cache_free(nilfs_btree_path_cache, path);
-}
+       struct nilfs_btree_path *path;
+       int level = NILFS_BTREE_LEVEL_DATA;
 
-static void nilfs_btree_init_path(struct nilfs_btree_path *path)
-{
-       int level;
+       path = kmem_cache_alloc(nilfs_btree_path_cache, GFP_NOFS);
+       if (path == NULL)
+               goto out;
 
-       for (level = NILFS_BTREE_LEVEL_DATA;
-            level < NILFS_BTREE_LEVEL_MAX;
-            level++) {
+       for (; level < NILFS_BTREE_LEVEL_MAX; level++) {
                path[level].bp_bh = NULL;
                path[level].bp_sib_bh = NULL;
                path[level].bp_index = 0;
@@ -95,15 +48,19 @@ static void nilfs_btree_init_path(struct nilfs_btree_path *path)
                path[level].bp_newreq.bpr_ptr = NILFS_BMAP_INVALID_PTR;
                path[level].bp_op = NULL;
        }
+
+out:
+       return path;
 }
 
-static void nilfs_btree_release_path(struct nilfs_btree_path *path)
+static void nilfs_btree_free_path(struct nilfs_btree_path *path)
 {
-       int level;
+       int level = NILFS_BTREE_LEVEL_DATA;
 
-       for (level = NILFS_BTREE_LEVEL_DATA; level < NILFS_BTREE_LEVEL_MAX;
-            level++)
+       for (; level < NILFS_BTREE_LEVEL_MAX; level++)
                brelse(path[level].bp_bh);
+
+       kmem_cache_free(nilfs_btree_path_cache, path);
 }
 
 /*
@@ -114,7 +71,18 @@ static int nilfs_btree_get_block(const struct nilfs_btree *btree, __u64 ptr,
 {
        struct address_space *btnc =
                &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache;
-       return nilfs_btnode_get(btnc, ptr, 0, bhp, 0);
+       int err;
+
+       err = nilfs_btnode_submit_block(btnc, ptr, 0, bhp);
+       if (err)
+               return err == -EEXIST ? 0 : err;
+
+       wait_on_buffer(*bhp);
+       if (!buffer_uptodate(*bhp)) {
+               brelse(*bhp);
+               return -EIO;
+       }
+       return 0;
 }
 
 static int nilfs_btree_get_new_block(const struct nilfs_btree *btree,
@@ -122,12 +90,15 @@ static int nilfs_btree_get_new_block(const struct nilfs_btree *btree,
 {
        struct address_space *btnc =
                &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache;
-       int ret;
+       struct buffer_head *bh;
 
-       ret = nilfs_btnode_get(btnc, ptr, 0, bhp, 1);
-       if (!ret)
-               set_buffer_nilfs_volatile(*bhp);
-       return ret;
+       bh = nilfs_btnode_create_block(btnc, ptr);
+       if (!bh)
+               return -ENOMEM;
+
+       set_buffer_nilfs_volatile(bh);
+       *bhp = bh;
+       return 0;
 }
 
 static inline int
@@ -444,6 +415,18 @@ nilfs_btree_get_node(const struct nilfs_btree *btree,
                nilfs_btree_get_nonroot_node(path, level);
 }
 
+static inline int
+nilfs_btree_bad_node(struct nilfs_btree_node *node, int level)
+{
+       if (unlikely(nilfs_btree_node_get_level(node) != level)) {
+               dump_stack();
+               printk(KERN_CRIT "NILFS: btree level mismatch: %d != %d\n",
+                      nilfs_btree_node_get_level(node), level);
+               return 1;
+       }
+       return 0;
+}
+
 static int nilfs_btree_do_lookup(const struct nilfs_btree *btree,
                                 struct nilfs_btree_path *path,
                                 __u64 key, __u64 *ptrp, int minlevel)
@@ -467,7 +450,8 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree,
                if (ret < 0)
                        return ret;
                node = nilfs_btree_get_nonroot_node(path, level);
-               BUG_ON(level != nilfs_btree_node_get_level(node));
+               if (nilfs_btree_bad_node(node, level))
+                       return -EINVAL;
                if (!found)
                        found = nilfs_btree_node_lookup(node, key, &index);
                else
@@ -512,7 +496,8 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_btree *btree,
                if (ret < 0)
                        return ret;
                node = nilfs_btree_get_nonroot_node(path, level);
-               BUG_ON(level != nilfs_btree_node_get_level(node));
+               if (nilfs_btree_bad_node(node, level))
+                       return -EINVAL;
                index = nilfs_btree_node_get_nchildren(node) - 1;
                ptr = nilfs_btree_node_get_ptr(btree, node, index);
                path[level].bp_index = index;
@@ -538,14 +523,12 @@ static int nilfs_btree_lookup(const struct nilfs_bmap *bmap,
        path = nilfs_btree_alloc_path();
        if (path == NULL)
                return -ENOMEM;
-       nilfs_btree_init_path(path);
 
        ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level);
 
        if (ptrp != NULL)
                *ptrp = ptr;
 
-       nilfs_btree_release_path(path);
        nilfs_btree_free_path(path);
 
        return ret;
@@ -566,7 +549,7 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap,
        path = nilfs_btree_alloc_path();
        if (path == NULL)
                return -ENOMEM;
-       nilfs_btree_init_path(path);
+
        ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level);
        if (ret < 0)
                goto out;
@@ -627,7 +610,6 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap,
        *ptrp = ptr;
        ret = cnt;
  out:
-       nilfs_btree_release_path(path);
        nilfs_btree_free_path(path);
        return ret;
 }
@@ -638,13 +620,11 @@ static void nilfs_btree_promote_key(struct nilfs_btree *btree,
 {
        if (level < nilfs_btree_height(btree) - 1) {
                do {
-                       lock_buffer(path[level].bp_bh);
                        nilfs_btree_node_set_key(
                                nilfs_btree_get_nonroot_node(path, level),
                                path[level].bp_index, key);
                        if (!buffer_dirty(path[level].bp_bh))
                                nilfs_btnode_mark_dirty(path[level].bp_bh);
-                       unlock_buffer(path[level].bp_bh);
                } while ((path[level].bp_index == 0) &&
                         (++level < nilfs_btree_height(btree) - 1));
        }
@@ -663,13 +643,11 @@ static void nilfs_btree_do_insert(struct nilfs_btree *btree,
        struct nilfs_btree_node *node;
 
        if (level < nilfs_btree_height(btree) - 1) {
-               lock_buffer(path[level].bp_bh);
                node = nilfs_btree_get_nonroot_node(path, level);
                nilfs_btree_node_insert(btree, node, *keyp, *ptrp,
                                        path[level].bp_index);
                if (!buffer_dirty(path[level].bp_bh))
                        nilfs_btnode_mark_dirty(path[level].bp_bh);
-               unlock_buffer(path[level].bp_bh);
 
                if (path[level].bp_index == 0)
                        nilfs_btree_promote_key(btree, path, level + 1,
@@ -689,9 +667,6 @@ static void nilfs_btree_carry_left(struct nilfs_btree *btree,
        struct nilfs_btree_node *node, *left;
        int nchildren, lnchildren, n, move;
 
-       lock_buffer(path[level].bp_bh);
-       lock_buffer(path[level].bp_sib_bh);
-
        node = nilfs_btree_get_nonroot_node(path, level);
        left = nilfs_btree_get_sib_node(path, level);
        nchildren = nilfs_btree_node_get_nchildren(node);
@@ -712,9 +687,6 @@ static void nilfs_btree_carry_left(struct nilfs_btree *btree,
        if (!buffer_dirty(path[level].bp_sib_bh))
                nilfs_btnode_mark_dirty(path[level].bp_sib_bh);
 
-       unlock_buffer(path[level].bp_bh);
-       unlock_buffer(path[level].bp_sib_bh);
-
        nilfs_btree_promote_key(btree, path, level + 1,
                                nilfs_btree_node_get_key(node, 0));
 
@@ -740,9 +712,6 @@ static void nilfs_btree_carry_right(struct nilfs_btree *btree,
        struct nilfs_btree_node *node, *right;
        int nchildren, rnchildren, n, move;
 
-       lock_buffer(path[level].bp_bh);
-       lock_buffer(path[level].bp_sib_bh);
-
        node = nilfs_btree_get_nonroot_node(path, level);
        right = nilfs_btree_get_sib_node(path, level);
        nchildren = nilfs_btree_node_get_nchildren(node);
@@ -763,9 +732,6 @@ static void nilfs_btree_carry_right(struct nilfs_btree *btree,
        if (!buffer_dirty(path[level].bp_sib_bh))
                nilfs_btnode_mark_dirty(path[level].bp_sib_bh);
 
-       unlock_buffer(path[level].bp_bh);
-       unlock_buffer(path[level].bp_sib_bh);
-
        path[level + 1].bp_index++;
        nilfs_btree_promote_key(btree, path, level + 1,
                                nilfs_btree_node_get_key(right, 0));
@@ -794,9 +760,6 @@ static void nilfs_btree_split(struct nilfs_btree *btree,
        __u64 newptr;
        int nchildren, n, move;
 
-       lock_buffer(path[level].bp_bh);
-       lock_buffer(path[level].bp_sib_bh);
-
        node = nilfs_btree_get_nonroot_node(path, level);
        right = nilfs_btree_get_sib_node(path, level);
        nchildren = nilfs_btree_node_get_nchildren(node);
@@ -815,9 +778,6 @@ static void nilfs_btree_split(struct nilfs_btree *btree,
        if (!buffer_dirty(path[level].bp_sib_bh))
                nilfs_btnode_mark_dirty(path[level].bp_sib_bh);
 
-       unlock_buffer(path[level].bp_bh);
-       unlock_buffer(path[level].bp_sib_bh);
-
        newkey = nilfs_btree_node_get_key(right, 0);
        newptr = path[level].bp_newreq.bpr_ptr;
 
@@ -852,8 +812,6 @@ static void nilfs_btree_grow(struct nilfs_btree *btree,
        struct nilfs_btree_node *root, *child;
        int n;
 
-       lock_buffer(path[level].bp_sib_bh);
-
        root = nilfs_btree_get_root(btree);
        child = nilfs_btree_get_sib_node(path, level);
 
@@ -865,8 +823,6 @@ static void nilfs_btree_grow(struct nilfs_btree *btree,
        if (!buffer_dirty(path[level].bp_sib_bh))
                nilfs_btnode_mark_dirty(path[level].bp_sib_bh);
 
-       unlock_buffer(path[level].bp_sib_bh);
-
        path[level].bp_bh = path[level].bp_sib_bh;
        path[level].bp_sib_bh = NULL;
 
@@ -940,17 +896,20 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
        struct nilfs_btree_node *node, *parent, *sib;
        __u64 sibptr;
        int pindex, level, ret;
+       struct inode *dat = NULL;
 
        stats->bs_nblocks = 0;
        level = NILFS_BTREE_LEVEL_DATA;
 
        /* allocate a new ptr for data block */
-       if (NILFS_BMAP_USE_VBN(&btree->bt_bmap))
+       if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) {
                path[level].bp_newreq.bpr_ptr =
                        nilfs_btree_find_target_v(btree, path, key);
+               dat = nilfs_bmap_get_dat(&btree->bt_bmap);
+       }
 
        ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap,
-                                          &path[level].bp_newreq);
+                                          &path[level].bp_newreq, dat);
        if (ret < 0)
                goto err_out_data;
 
@@ -1009,7 +968,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
                path[level].bp_newreq.bpr_ptr =
                        path[level - 1].bp_newreq.bpr_ptr + 1;
                ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap,
-                                                  &path[level].bp_newreq);
+                                                  &path[level].bp_newreq, dat);
                if (ret < 0)
                        goto err_out_child_node;
                ret = nilfs_btree_get_new_block(btree,
@@ -1020,11 +979,9 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
 
                stats->bs_nblocks++;
 
-               lock_buffer(bh);
                nilfs_btree_node_init(btree,
                                      (struct nilfs_btree_node *)bh->b_data,
                                      0, level, 0, NULL, NULL);
-               unlock_buffer(bh);
                path[level].bp_sib_bh = bh;
                path[level].bp_op = nilfs_btree_split;
        }
@@ -1041,7 +998,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
        /* grow */
        path[level].bp_newreq.bpr_ptr = path[level - 1].bp_newreq.bpr_ptr + 1;
        ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap,
-                                          &path[level].bp_newreq);
+                                          &path[level].bp_newreq, dat);
        if (ret < 0)
                goto err_out_child_node;
        ret = nilfs_btree_get_new_block(btree, path[level].bp_newreq.bpr_ptr,
@@ -1049,10 +1006,8 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
        if (ret < 0)
                goto err_out_curr_node;
 
-       lock_buffer(bh);
        nilfs_btree_node_init(btree, (struct nilfs_btree_node *)bh->b_data,
                              0, level, 0, NULL, NULL);
-       unlock_buffer(bh);
        path[level].bp_sib_bh = bh;
        path[level].bp_op = nilfs_btree_grow;
 
@@ -1069,16 +1024,18 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
 
        /* error */
  err_out_curr_node:
-       nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq);
+       nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq,
+                                  dat);
  err_out_child_node:
        for (level--; level > NILFS_BTREE_LEVEL_DATA; level--) {
                nilfs_btnode_delete(path[level].bp_sib_bh);
                nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap,
-                                          &path[level].bp_newreq);
+                                          &path[level].bp_newreq, dat);
 
        }
 
-       nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq);
+       nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq,
+                                  dat);
  err_out_data:
        *levelp = level;
        stats->bs_nblocks = 0;
@@ -1089,16 +1046,19 @@ static void nilfs_btree_commit_insert(struct nilfs_btree *btree,
                                      struct nilfs_btree_path *path,
                                      int maxlevel, __u64 key, __u64 ptr)
 {
+       struct inode *dat = NULL;
        int level;
 
        set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr));
        ptr = path[NILFS_BTREE_LEVEL_DATA].bp_newreq.bpr_ptr;
-       if (NILFS_BMAP_USE_VBN(&btree->bt_bmap))
+       if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) {
                nilfs_btree_set_target_v(btree, key, ptr);
+               dat = nilfs_bmap_get_dat(&btree->bt_bmap);
+       }
 
        for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) {
                nilfs_bmap_commit_alloc_ptr(&btree->bt_bmap,
-                                           &path[level - 1].bp_newreq);
+                                           &path[level - 1].bp_newreq, dat);
                path[level].bp_op(btree, path, level, &key, &ptr);
        }
 
@@ -1117,7 +1077,6 @@ static int nilfs_btree_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
        path = nilfs_btree_alloc_path();
        if (path == NULL)
                return -ENOMEM;
-       nilfs_btree_init_path(path);
 
        ret = nilfs_btree_do_lookup(btree, path, key, NULL,
                                    NILFS_BTREE_LEVEL_NODE_MIN);
@@ -1134,7 +1093,6 @@ static int nilfs_btree_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
        nilfs_bmap_add_blocks(bmap, stats.bs_nblocks);
 
  out:
-       nilfs_btree_release_path(path);
        nilfs_btree_free_path(path);
        return ret;
 }
@@ -1146,13 +1104,11 @@ static void nilfs_btree_do_delete(struct nilfs_btree *btree,
        struct nilfs_btree_node *node;
 
        if (level < nilfs_btree_height(btree) - 1) {
-               lock_buffer(path[level].bp_bh);
                node = nilfs_btree_get_nonroot_node(path, level);
                nilfs_btree_node_delete(btree, node, keyp, ptrp,
                                        path[level].bp_index);
                if (!buffer_dirty(path[level].bp_bh))
                        nilfs_btnode_mark_dirty(path[level].bp_bh);
-               unlock_buffer(path[level].bp_bh);
                if (path[level].bp_index == 0)
                        nilfs_btree_promote_key(btree, path, level + 1,
                                nilfs_btree_node_get_key(node, 0));
@@ -1172,9 +1128,6 @@ static void nilfs_btree_borrow_left(struct nilfs_btree *btree,
 
        nilfs_btree_do_delete(btree, path, level, keyp, ptrp);
 
-       lock_buffer(path[level].bp_bh);
-       lock_buffer(path[level].bp_sib_bh);
-
        node = nilfs_btree_get_nonroot_node(path, level);
        left = nilfs_btree_get_sib_node(path, level);
        nchildren = nilfs_btree_node_get_nchildren(node);
@@ -1189,9 +1142,6 @@ static void nilfs_btree_borrow_left(struct nilfs_btree *btree,
        if (!buffer_dirty(path[level].bp_sib_bh))
                nilfs_btnode_mark_dirty(path[level].bp_sib_bh);
 
-       unlock_buffer(path[level].bp_bh);
-       unlock_buffer(path[level].bp_sib_bh);
-
        nilfs_btree_promote_key(btree, path, level + 1,
                                nilfs_btree_node_get_key(node, 0));
 
@@ -1209,9 +1159,6 @@ static void nilfs_btree_borrow_right(struct nilfs_btree *btree,
 
        nilfs_btree_do_delete(btree, path, level, keyp, ptrp);
 
-       lock_buffer(path[level].bp_bh);
-       lock_buffer(path[level].bp_sib_bh);
-
        node = nilfs_btree_get_nonroot_node(path, level);
        right = nilfs_btree_get_sib_node(path, level);
        nchildren = nilfs_btree_node_get_nchildren(node);
@@ -1226,9 +1173,6 @@ static void nilfs_btree_borrow_right(struct nilfs_btree *btree,
        if (!buffer_dirty(path[level].bp_sib_bh))
                nilfs_btnode_mark_dirty(path[level].bp_sib_bh);
 
-       unlock_buffer(path[level].bp_bh);
-       unlock_buffer(path[level].bp_sib_bh);
-
        path[level + 1].bp_index++;
        nilfs_btree_promote_key(btree, path, level + 1,
                                nilfs_btree_node_get_key(right, 0));
@@ -1247,9 +1191,6 @@ static void nilfs_btree_concat_left(struct nilfs_btree *btree,
 
        nilfs_btree_do_delete(btree, path, level, keyp, ptrp);
 
-       lock_buffer(path[level].bp_bh);
-       lock_buffer(path[level].bp_sib_bh);
-
        node = nilfs_btree_get_nonroot_node(path, level);
        left = nilfs_btree_get_sib_node(path, level);
 
@@ -1260,9 +1201,6 @@ static void nilfs_btree_concat_left(struct nilfs_btree *btree,
        if (!buffer_dirty(path[level].bp_sib_bh))
                nilfs_btnode_mark_dirty(path[level].bp_sib_bh);
 
-       unlock_buffer(path[level].bp_bh);
-       unlock_buffer(path[level].bp_sib_bh);
-
        nilfs_btnode_delete(path[level].bp_bh);
        path[level].bp_bh = path[level].bp_sib_bh;
        path[level].bp_sib_bh = NULL;
@@ -1278,9 +1216,6 @@ static void nilfs_btree_concat_right(struct nilfs_btree *btree,
 
        nilfs_btree_do_delete(btree, path, level, keyp, ptrp);
 
-       lock_buffer(path[level].bp_bh);
-       lock_buffer(path[level].bp_sib_bh);
-
        node = nilfs_btree_get_nonroot_node(path, level);
        right = nilfs_btree_get_sib_node(path, level);
 
@@ -1291,9 +1226,6 @@ static void nilfs_btree_concat_right(struct nilfs_btree *btree,
        if (!buffer_dirty(path[level].bp_bh))
                nilfs_btnode_mark_dirty(path[level].bp_bh);
 
-       unlock_buffer(path[level].bp_bh);
-       unlock_buffer(path[level].bp_sib_bh);
-
        nilfs_btnode_delete(path[level].bp_sib_bh);
        path[level].bp_sib_bh = NULL;
        path[level + 1].bp_index++;
@@ -1308,7 +1240,6 @@ static void nilfs_btree_shrink(struct nilfs_btree *btree,
 
        nilfs_btree_do_delete(btree, path, level, keyp, ptrp);
 
-       lock_buffer(path[level].bp_bh);
        root = nilfs_btree_get_root(btree);
        child = nilfs_btree_get_nonroot_node(path, level);
 
@@ -1316,7 +1247,6 @@ static void nilfs_btree_shrink(struct nilfs_btree *btree,
        nilfs_btree_node_set_level(root, level);
        n = nilfs_btree_node_get_nchildren(child);
        nilfs_btree_node_move_left(btree, root, child, n);
-       unlock_buffer(path[level].bp_bh);
 
        nilfs_btnode_delete(path[level].bp_bh);
        path[level].bp_bh = NULL;
@@ -1326,7 +1256,8 @@ static void nilfs_btree_shrink(struct nilfs_btree *btree,
 static int nilfs_btree_prepare_delete(struct nilfs_btree *btree,
                                      struct nilfs_btree_path *path,
                                      int *levelp,
-                                     struct nilfs_bmap_stats *stats)
+                                     struct nilfs_bmap_stats *stats,
+                                     struct inode *dat)
 {
        struct buffer_head *bh;
        struct nilfs_btree_node *node, *parent, *sib;
@@ -1343,7 +1274,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree,
                        nilfs_btree_node_get_ptr(btree, node,
                                                 path[level].bp_index);
                ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap,
-                                                &path[level].bp_oldreq);
+                                                &path[level].bp_oldreq, dat);
                if (ret < 0)
                        goto err_out_child_node;
 
@@ -1421,7 +1352,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree,
                nilfs_btree_node_get_ptr(btree, node, path[level].bp_index);
 
        ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap,
-                                        &path[level].bp_oldreq);
+                                        &path[level].bp_oldreq, dat);
        if (ret < 0)
                goto err_out_child_node;
 
@@ -1436,12 +1367,12 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree,
 
        /* error */
  err_out_curr_node:
-       nilfs_bmap_abort_end_ptr(&btree->bt_bmap, &path[level].bp_oldreq);
+       nilfs_bmap_abort_end_ptr(&btree->bt_bmap, &path[level].bp_oldreq, dat);
  err_out_child_node:
        for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--) {
                brelse(path[level].bp_sib_bh);
                nilfs_bmap_abort_end_ptr(&btree->bt_bmap,
-                                        &path[level].bp_oldreq);
+                                        &path[level].bp_oldreq, dat);
        }
        *levelp = level;
        stats->bs_nblocks = 0;
@@ -1450,13 +1381,13 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree,
 
 static void nilfs_btree_commit_delete(struct nilfs_btree *btree,
                                      struct nilfs_btree_path *path,
-                                     int maxlevel)
+                                     int maxlevel, struct inode *dat)
 {
        int level;
 
        for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) {
                nilfs_bmap_commit_end_ptr(&btree->bt_bmap,
-                                         &path[level].bp_oldreq);
+                                         &path[level].bp_oldreq, dat);
                path[level].bp_op(btree, path, level, NULL, NULL);
        }
 
@@ -1470,26 +1401,30 @@ static int nilfs_btree_delete(struct nilfs_bmap *bmap, __u64 key)
        struct nilfs_btree *btree;
        struct nilfs_btree_path *path;
        struct nilfs_bmap_stats stats;
+       struct inode *dat;
        int level, ret;
 
        btree = (struct nilfs_btree *)bmap;
        path = nilfs_btree_alloc_path();
        if (path == NULL)
                return -ENOMEM;
-       nilfs_btree_init_path(path);
+
        ret = nilfs_btree_do_lookup(btree, path, key, NULL,
                                    NILFS_BTREE_LEVEL_NODE_MIN);
        if (ret < 0)
                goto out;
 
-       ret = nilfs_btree_prepare_delete(btree, path, &level, &stats);
+
+       dat = NILFS_BMAP_USE_VBN(&btree->bt_bmap) ?
+               nilfs_bmap_get_dat(&btree->bt_bmap) : NULL;
+
+       ret = nilfs_btree_prepare_delete(btree, path, &level, &stats, dat);
        if (ret < 0)
                goto out;
-       nilfs_btree_commit_delete(btree, path, level);
+       nilfs_btree_commit_delete(btree, path, level, dat);
        nilfs_bmap_sub_blocks(bmap, stats.bs_nblocks);
 
 out:
-       nilfs_btree_release_path(path);
        nilfs_btree_free_path(path);
        return ret;
 }
@@ -1504,11 +1439,9 @@ static int nilfs_btree_last_key(const struct nilfs_bmap *bmap, __u64 *keyp)
        path = nilfs_btree_alloc_path();
        if (path == NULL)
                return -ENOMEM;
-       nilfs_btree_init_path(path);
 
        ret = nilfs_btree_do_lookup_last(btree, path, keyp, NULL);
 
-       nilfs_btree_release_path(path);
        nilfs_btree_free_path(path);
 
        return ret;
@@ -1610,18 +1543,20 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key,
                                       struct nilfs_bmap_stats *stats)
 {
        struct buffer_head *bh;
-       struct nilfs_btree *btree;
+       struct nilfs_btree *btree = (struct nilfs_btree *)bmap;
+       struct inode *dat = NULL;
        int ret;
 
-       btree = (struct nilfs_btree *)bmap;
        stats->bs_nblocks = 0;
 
        /* for data */
        /* cannot find near ptr */
-       if (NILFS_BMAP_USE_VBN(bmap))
+       if (NILFS_BMAP_USE_VBN(bmap)) {
                dreq->bpr_ptr = nilfs_btree_find_target_v(btree, NULL, key);
+               dat = nilfs_bmap_get_dat(bmap);
+       }
 
-       ret = nilfs_bmap_prepare_alloc_ptr(bmap, dreq);
+       ret = nilfs_bmap_prepare_alloc_ptr(bmap, dreq, dat);
        if (ret < 0)
                return ret;
 
@@ -1629,7 +1564,7 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key,
        stats->bs_nblocks++;
        if (nreq != NULL) {
                nreq->bpr_ptr = dreq->bpr_ptr + 1;
-               ret = nilfs_bmap_prepare_alloc_ptr(bmap, nreq);
+               ret = nilfs_bmap_prepare_alloc_ptr(bmap, nreq, dat);
                if (ret < 0)
                        goto err_out_dreq;
 
@@ -1646,9 +1581,9 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key,
 
        /* error */
  err_out_nreq:
-       nilfs_bmap_abort_alloc_ptr(bmap, nreq);
+       nilfs_bmap_abort_alloc_ptr(bmap, nreq, dat);
  err_out_dreq:
-       nilfs_bmap_abort_alloc_ptr(bmap, dreq);
+       nilfs_bmap_abort_alloc_ptr(bmap, dreq, dat);
        stats->bs_nblocks = 0;
        return ret;
 
@@ -1663,8 +1598,9 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap,
                                      union nilfs_bmap_ptr_req *nreq,
                                      struct buffer_head *bh)
 {
-       struct nilfs_btree *btree;
+       struct nilfs_btree *btree = (struct nilfs_btree *)bmap;
        struct nilfs_btree_node *node;
+       struct inode *dat;
        __u64 tmpptr;
 
        /* free resources */
@@ -1675,14 +1611,13 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap,
        set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr));
 
        /* convert and insert */
-       btree = (struct nilfs_btree *)bmap;
+       dat = NILFS_BMAP_USE_VBN(bmap) ? nilfs_bmap_get_dat(bmap) : NULL;
        nilfs_btree_init(bmap);
        if (nreq != NULL) {
-               nilfs_bmap_commit_alloc_ptr(bmap, dreq);
-               nilfs_bmap_commit_alloc_ptr(bmap, nreq);
+               nilfs_bmap_commit_alloc_ptr(bmap, dreq, dat);
+               nilfs_bmap_commit_alloc_ptr(bmap, nreq, dat);
 
                /* create child node at level 1 */
-               lock_buffer(bh);
                node = (struct nilfs_btree_node *)bh->b_data;
                nilfs_btree_node_init(btree, node, 0, 1, n, keys, ptrs);
                nilfs_btree_node_insert(btree, node,
@@ -1692,7 +1627,6 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap,
                if (!nilfs_bmap_dirty(bmap))
                        nilfs_bmap_set_dirty(bmap);
 
-               unlock_buffer(bh);
                brelse(bh);
 
                /* create root node at level 2 */
@@ -1701,7 +1635,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap,
                nilfs_btree_node_init(btree, node, NILFS_BTREE_NODE_ROOT,
                                      2, 1, &keys[0], &tmpptr);
        } else {
-               nilfs_bmap_commit_alloc_ptr(bmap, dreq);
+               nilfs_bmap_commit_alloc_ptr(bmap, dreq, dat);
 
                /* create root node at level 1 */
                node = nilfs_btree_get_root(btree);
@@ -1772,7 +1706,7 @@ static int nilfs_btree_propagate_p(struct nilfs_btree *btree,
 
 static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree,
                                        struct nilfs_btree_path *path,
-                                       int level)
+                                       int level, struct inode *dat)
 {
        struct nilfs_btree_node *parent;
        int ret;
@@ -1782,9 +1716,8 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree,
                nilfs_btree_node_get_ptr(btree, parent,
                                         path[level + 1].bp_index);
        path[level].bp_newreq.bpr_ptr = path[level].bp_oldreq.bpr_ptr + 1;
-       ret = nilfs_bmap_prepare_update_v(&btree->bt_bmap,
-                                         &path[level].bp_oldreq,
-                                         &path[level].bp_newreq);
+       ret = nilfs_dat_prepare_update(dat, &path[level].bp_oldreq.bpr_req,
+                                      &path[level].bp_newreq.bpr_req);
        if (ret < 0)
                return ret;
 
@@ -1796,9 +1729,9 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree,
                        &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache,
                        &path[level].bp_ctxt);
                if (ret < 0) {
-                       nilfs_bmap_abort_update_v(&btree->bt_bmap,
-                                                 &path[level].bp_oldreq,
-                                                 &path[level].bp_newreq);
+                       nilfs_dat_abort_update(dat,
+                                              &path[level].bp_oldreq.bpr_req,
+                                              &path[level].bp_newreq.bpr_req);
                        return ret;
                }
        }
@@ -1808,13 +1741,13 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree,
 
 static void nilfs_btree_commit_update_v(struct nilfs_btree *btree,
                                        struct nilfs_btree_path *path,
-                                       int level)
+                                       int level, struct inode *dat)
 {
        struct nilfs_btree_node *parent;
 
-       nilfs_bmap_commit_update_v(&btree->bt_bmap,
-                                  &path[level].bp_oldreq,
-                                  &path[level].bp_newreq);
+       nilfs_dat_commit_update(dat, &path[level].bp_oldreq.bpr_req,
+                               &path[level].bp_newreq.bpr_req,
+                               btree->bt_bmap.b_ptr_type == NILFS_BMAP_PTR_VS);
 
        if (buffer_nilfs_node(path[level].bp_bh)) {
                nilfs_btnode_commit_change_key(
@@ -1831,11 +1764,10 @@ static void nilfs_btree_commit_update_v(struct nilfs_btree *btree,
 
 static void nilfs_btree_abort_update_v(struct nilfs_btree *btree,
                                       struct nilfs_btree_path *path,
-                                      int level)
+                                      int level, struct inode *dat)
 {
-       nilfs_bmap_abort_update_v(&btree->bt_bmap,
-                                 &path[level].bp_oldreq,
-                                 &path[level].bp_newreq);
+       nilfs_dat_abort_update(dat, &path[level].bp_oldreq.bpr_req,
+                              &path[level].bp_newreq.bpr_req);
        if (buffer_nilfs_node(path[level].bp_bh))
                nilfs_btnode_abort_change_key(
                        &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache,
@@ -1844,14 +1776,14 @@ static void nilfs_btree_abort_update_v(struct nilfs_btree *btree,
 
 static int nilfs_btree_prepare_propagate_v(struct nilfs_btree *btree,
                                           struct nilfs_btree_path *path,
-                                          int minlevel,
-                                          int *maxlevelp)
+                                          int minlevel, int *maxlevelp,
+                                          struct inode *dat)
 {
        int level, ret;
 
        level = minlevel;
        if (!buffer_nilfs_volatile(path[level].bp_bh)) {
-               ret = nilfs_btree_prepare_update_v(btree, path, level);
+               ret = nilfs_btree_prepare_update_v(btree, path, level, dat);
                if (ret < 0)
                        return ret;
        }
@@ -1859,7 +1791,7 @@ static int nilfs_btree_prepare_propagate_v(struct nilfs_btree *btree,
               !buffer_dirty(path[level].bp_bh)) {
 
                WARN_ON(buffer_nilfs_volatile(path[level].bp_bh));
-               ret = nilfs_btree_prepare_update_v(btree, path, level);
+               ret = nilfs_btree_prepare_update_v(btree, path, level, dat);
                if (ret < 0)
                        goto out;
        }
@@ -1871,39 +1803,40 @@ static int nilfs_btree_prepare_propagate_v(struct nilfs_btree *btree,
        /* error */
  out:
        while (--level > minlevel)
-               nilfs_btree_abort_update_v(btree, path, level);
+               nilfs_btree_abort_update_v(btree, path, level, dat);
        if (!buffer_nilfs_volatile(path[level].bp_bh))
-               nilfs_btree_abort_update_v(btree, path, level);
+               nilfs_btree_abort_update_v(btree, path, level, dat);
        return ret;
 }
 
 static void nilfs_btree_commit_propagate_v(struct nilfs_btree *btree,
                                           struct nilfs_btree_path *path,
-                                          int minlevel,
-                                          int maxlevel,
-                                          struct buffer_head *bh)
+                                          int minlevel, int maxlevel,
+                                          struct buffer_head *bh,
+                                          struct inode *dat)
 {
        int level;
 
        if (!buffer_nilfs_volatile(path[minlevel].bp_bh))
-               nilfs_btree_commit_update_v(btree, path, minlevel);
+               nilfs_btree_commit_update_v(btree, path, minlevel, dat);
 
        for (level = minlevel + 1; level <= maxlevel; level++)
-               nilfs_btree_commit_update_v(btree, path, level);
+               nilfs_btree_commit_update_v(btree, path, level, dat);
 }
 
 static int nilfs_btree_propagate_v(struct nilfs_btree *btree,
                                   struct nilfs_btree_path *path,
-                                  int level,
-                                  struct buffer_head *bh)
+                                  int level, struct buffer_head *bh)
 {
-       int maxlevel, ret;
+       int maxlevel = 0, ret;
        struct nilfs_btree_node *parent;
+       struct inode *dat = nilfs_bmap_get_dat(&btree->bt_bmap);
        __u64 ptr;
 
        get_bh(bh);
        path[level].bp_bh = bh;
-       ret = nilfs_btree_prepare_propagate_v(btree, path, level, &maxlevel);
+       ret = nilfs_btree_prepare_propagate_v(btree, path, level, &maxlevel,
+                                             dat);
        if (ret < 0)
                goto out;
 
@@ -1911,12 +1844,12 @@ static int nilfs_btree_propagate_v(struct nilfs_btree *btree,
                parent = nilfs_btree_get_node(btree, path, level + 1);
                ptr = nilfs_btree_node_get_ptr(btree, parent,
                                               path[level + 1].bp_index);
-               ret = nilfs_bmap_mark_dirty(&btree->bt_bmap, ptr);
+               ret = nilfs_dat_mark_dirty(dat, ptr);
                if (ret < 0)
                        goto out;
        }
 
-       nilfs_btree_commit_propagate_v(btree, path, level, maxlevel, bh);
+       nilfs_btree_commit_propagate_v(btree, path, level, maxlevel, bh, dat);
 
  out:
        brelse(path[level].bp_bh);
@@ -1939,7 +1872,6 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap,
        path = nilfs_btree_alloc_path();
        if (path == NULL)
                return -ENOMEM;
-       nilfs_btree_init_path(path);
 
        if (buffer_nilfs_node(bh)) {
                node = (struct nilfs_btree_node *)bh->b_data;
@@ -1963,7 +1895,6 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap,
                nilfs_btree_propagate_p(btree, path, level, bh);
 
  out:
-       nilfs_btree_release_path(path);
        nilfs_btree_free_path(path);
 
        return ret;
@@ -1972,7 +1903,7 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap,
 static int nilfs_btree_propagate_gc(const struct nilfs_bmap *bmap,
                                    struct buffer_head *bh)
 {
-       return nilfs_bmap_mark_dirty(bmap, bh->b_blocknr);
+       return nilfs_dat_mark_dirty(nilfs_bmap_get_dat(bmap), bh->b_blocknr);
 }
 
 static void nilfs_btree_add_dirty_buffer(struct nilfs_btree *btree,
@@ -2034,7 +1965,7 @@ static void nilfs_btree_lookup_dirty_buffers(struct nilfs_bmap *bmap,
        for (level = NILFS_BTREE_LEVEL_NODE_MIN;
             level < NILFS_BTREE_LEVEL_MAX;
             level++)
-               list_splice(&lists[level], listp->prev);
+               list_splice_tail(&lists[level], listp);
 }
 
 static int nilfs_btree_assign_p(struct nilfs_btree *btree,
@@ -2086,6 +2017,7 @@ static int nilfs_btree_assign_v(struct nilfs_btree *btree,
                                union nilfs_binfo *binfo)
 {
        struct nilfs_btree_node *parent;
+       struct inode *dat = nilfs_bmap_get_dat(&btree->bt_bmap);
        __u64 key;
        __u64 ptr;
        union nilfs_bmap_ptr_req req;
@@ -2095,9 +2027,10 @@ static int nilfs_btree_assign_v(struct nilfs_btree *btree,
        ptr = nilfs_btree_node_get_ptr(btree, parent,
                                       path[level + 1].bp_index);
        req.bpr_ptr = ptr;
-       ret = nilfs_bmap_start_v(&btree->bt_bmap, &req, blocknr);
-       if (unlikely(ret < 0))
+       ret = nilfs_dat_prepare_start(dat, &req.bpr_req);
+       if (ret < 0)
                return ret;
+       nilfs_dat_commit_start(dat, &req.bpr_req, blocknr);
 
        key = nilfs_btree_node_get_key(parent, path[level + 1].bp_index);
        /* on-disk format */
@@ -2122,7 +2055,6 @@ static int nilfs_btree_assign(struct nilfs_bmap *bmap,
        path = nilfs_btree_alloc_path();
        if (path == NULL)
                return -ENOMEM;
-       nilfs_btree_init_path(path);
 
        if (buffer_nilfs_node(*bh)) {
                node = (struct nilfs_btree_node *)(*bh)->b_data;
@@ -2144,7 +2076,6 @@ static int nilfs_btree_assign(struct nilfs_bmap *bmap,
                nilfs_btree_assign_p(btree, path, level, bh, blocknr, binfo);
 
  out:
-       nilfs_btree_release_path(path);
        nilfs_btree_free_path(path);
 
        return ret;
@@ -2155,13 +2086,12 @@ static int nilfs_btree_assign_gc(struct nilfs_bmap *bmap,
                                 sector_t blocknr,
                                 union nilfs_binfo *binfo)
 {
-       struct nilfs_btree *btree;
        struct nilfs_btree_node *node;
        __u64 key;
        int ret;
 
-       btree = (struct nilfs_btree *)bmap;
-       ret = nilfs_bmap_move_v(bmap, (*bh)->b_blocknr, blocknr);
+       ret = nilfs_dat_move(nilfs_bmap_get_dat(bmap), (*bh)->b_blocknr,
+                            blocknr);
        if (ret < 0)
                return ret;
 
@@ -2190,7 +2120,6 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level)
        path = nilfs_btree_alloc_path();
        if (path == NULL)
                return -ENOMEM;
-       nilfs_btree_init_path(path);
 
        ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level + 1);
        if (ret < 0) {
@@ -2210,7 +2139,6 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level)
                nilfs_bmap_set_dirty(&btree->bt_bmap);
 
  out:
-       nilfs_btree_release_path(path);
        nilfs_btree_free_path(path);
        return ret;
 }