Btrfs: Add back the online defragging code
authorChris Mason <chris.mason@oracle.com>
Mon, 15 Oct 2007 20:17:34 +0000 (16:17 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:03:56 +0000 (11:03 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_map.h
fs/btrfs/transaction.c
fs/btrfs/tree-defrag.c

index 34de83630ae9011acb84c5406b9859daad02e9fd..08ddf1873ab1f0c55da018e116a5fae011253597 100644 (file)
@@ -155,55 +155,49 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
        return ret;
 }
 
-#if 0
-static int close_blocks(u64 blocknr, u64 other)
+static int close_blocks(u64 blocknr, u64 other, u32 blocksize)
 {
-       if (blocknr < other && other - blocknr < 8)
+       if (blocknr < other && other - (blocknr + blocksize) < 32768)
                return 1;
-       if (blocknr > other && blocknr - other < 8)
+       if (blocknr > other && blocknr - (other + blocksize) < 32768)
                return 1;
        return 0;
 }
 
-static int should_defrag_leaf(struct extent_buffer *eb)
+static int should_defrag_leaf(struct extent_buffer *leaf)
 {
-       return 0;
-       struct btrfs_leaf *leaf = btrfs_buffer_leaf(eb);
-       struct btrfs_disk_key *key;
+       struct btrfs_key key;
        u32 nritems;
 
-       if (buffer_defrag(bh))
+       if (btrfs_buffer_defrag(leaf))
                return 1;
 
-       nritems = btrfs_header_nritems(&leaf->header);
+       nritems = btrfs_header_nritems(leaf);
        if (nritems == 0)
                return 0;
 
-       key = &leaf->items[0].key;
-       if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY)
+       btrfs_item_key_to_cpu(leaf, &key, 0);
+       if (key.type == BTRFS_DIR_ITEM_KEY)
                return 1;
 
-       key = &leaf->items[nritems-1].key;
-       if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY)
+
+       btrfs_item_key_to_cpu(leaf, &key, nritems - 1);
+       if (key.type == BTRFS_DIR_ITEM_KEY)
                return 1;
        if (nritems > 4) {
-               key = &leaf->items[nritems/2].key;
-               if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY)
+               btrfs_item_key_to_cpu(leaf, &key, nritems / 2);
+               if (key.type == BTRFS_DIR_ITEM_KEY)
                        return 1;
        }
        return 0;
 }
-#endif
 
 int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                       struct btrfs_root *root, struct extent_buffer *parent,
                       int cache_only, u64 *last_ret)
 {
-       return 0;
-#if 0
-       struct btrfs_node *parent_node;
-       struct extent_buffer *cur_eb;
-       struct extent_buffer *tmp_eb;
+       struct extent_buffer *cur;
+       struct extent_buffer *tmp;
        u64 blocknr;
        u64 search_start = *last_ret;
        u64 last_block = 0;
@@ -214,6 +208,8 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
        int i;
        int err = 0;
        int parent_level;
+       int uptodate;
+       u32 blocksize;
 
        if (trans->transaction != root->fs_info->running_transaction) {
                printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid,
@@ -225,12 +221,12 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                       root->fs_info->generation);
                WARN_ON(1);
        }
-       if (buffer_defrag_done(parent))
+       if (btrfs_buffer_defrag_done(parent))
                return 0;
 
-       parent_node = btrfs_buffer_node(parent);
-       parent_nritems = btrfs_header_nritems(&parent_node->header);
-       parent_level = btrfs_header_level(&parent_node->header);
+       parent_nritems = btrfs_header_nritems(parent);
+       parent_level = btrfs_header_level(parent);
+       blocksize = btrfs_level_size(root, parent_level - 1);
 
        start_slot = 0;
        end_slot = parent_nritems;
@@ -240,56 +236,60 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 
        for (i = start_slot; i < end_slot; i++) {
                int close = 1;
-               blocknr = btrfs_node_blockptr(parent_node, i);
+               blocknr = btrfs_node_blockptr(parent, i);
                if (last_block == 0)
                        last_block = blocknr;
                if (i > 0) {
-                       other = btrfs_node_blockptr(parent_node, i - 1);
-                       close = close_blocks(blocknr, other);
+                       other = btrfs_node_blockptr(parent, i - 1);
+                       close = close_blocks(blocknr, other, blocksize);
                }
                if (close && i < end_slot - 1) {
-                       other = btrfs_node_blockptr(parent_node, i + 1);
-                       close = close_blocks(blocknr, other);
+                       other = btrfs_node_blockptr(parent, i + 1);
+                       close = close_blocks(blocknr, other, blocksize);
                }
                if (close) {
                        last_block = blocknr;
                        continue;
                }
 
-               cur_bh = btrfs_find_tree_block(root, blocknr);
-               if (!cur_bh || !buffer_uptodate(cur_bh) ||
-                   buffer_locked(cur_bh) ||
-                   (parent_level != 1 && !buffer_defrag(cur_bh)) ||
-                   (parent_level == 1 && !should_defrag_leaf(cur_bh))) {
+               cur = btrfs_find_tree_block(root, blocknr, blocksize);
+               if (cur)
+                       uptodate = btrfs_buffer_uptodate(cur);
+               else
+                       uptodate = 0;
+               if (!cur || !uptodate ||
+                   (parent_level != 1 && !btrfs_buffer_defrag(cur)) ||
+                   (parent_level == 1 && !should_defrag_leaf(cur))) {
                        if (cache_only) {
-                               brelse(cur_bh);
+                               free_extent_buffer(cur);
                                continue;
                        }
-                       if (!cur_bh || !buffer_uptodate(cur_bh) ||
-                           buffer_locked(cur_bh)) {
-                               brelse(cur_bh);
-                               cur_bh = read_tree_block(root, blocknr);
+                       if (!cur) {
+                               cur = read_tree_block(root, blocknr,
+                                                        blocksize);
+                       } else if (!uptodate) {
+                               btrfs_read_buffer(cur);
                        }
                }
                if (search_start == 0)
-                       search_start = last_block & ~((u64)65535);
+                       search_start = last_block;
 
-               err = __btrfs_cow_block(trans, root, cur_bh, parent, i,
-                                       &tmp_bh, search_start,
-                                       min(8, end_slot - i));
+               err = __btrfs_cow_block(trans, root, cur, parent, i,
+                                       &tmp, search_start,
+                                       min(16 * blocksize,
+                                           (end_slot - i) * blocksize));
                if (err) {
-                       brelse(cur_bh);
+                       free_extent_buffer(cur);
                        break;
                }
-               search_start = bh_blocknr(tmp_bh);
+               search_start = tmp->start;
                *last_ret = search_start;
                if (parent_level == 1)
-                       clear_buffer_defrag(tmp_bh);
-               set_buffer_defrag_done(tmp_bh);
-               brelse(tmp_bh);
+                       btrfs_clear_buffer_defrag(tmp);
+               btrfs_set_buffer_defrag_done(tmp);
+               free_extent_buffer(tmp);
        }
        return err;
-#endif
 }
 
 /*
@@ -892,22 +892,17 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans,
 static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
                             int level, int slot)
 {
-       return;
-#if 0
        struct extent_buffer *node;
-       int i;
        u32 nritems;
-       u64 bytenr;
        u64 search;
-       u64 cluster_start;
-       int ret;
-       int nread = 0;
+       u64 lowest_read;
+       u64 highest_read;
+       u64 nread = 0;
        int direction = path->reada;
-       int level;
-       struct radix_tree_root found;
-       unsigned long gang[8];
        struct extent_buffer *eb;
-
+       u32 nr;
+       u32 blocksize;
+       u32 nscan = 0;
 
        if (level == 0)
                return;
@@ -917,42 +912,46 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
 
        node = path->nodes[level];
        search = btrfs_node_blockptr(node, slot);
-       eb = btrfs_find_tree_block(root, search);
+       blocksize = btrfs_level_size(root, level - 1);
+       eb = btrfs_find_tree_block(root, search, blocksize);
        if (eb) {
                free_extent_buffer(eb);
                return;
        }
 
-       init_bit_radix(&found);
+       highest_read = search;
+       lowest_read = search;
+
        nritems = btrfs_header_nritems(node);
-       level = btrfs_header_level(node) - 1;
-       for (i = slot; i < nritems; i++) {
-               bytenr = btrfs_node_blockptr(node, i);
-               set_radix_bit(&found, blocknr);
-       }
-       if (direction > 0) {
-               cluster_start = search - 4;
-               if (cluster_start > search)
-                       cluster_start = 0;
-       } else
-               cluster_start = search + 4;
+       nr = slot;
        while(1) {
-               ret = find_first_radix_bit(&found, gang, 0, ARRAY_SIZE(gang));
-               if (!ret)
-                       break;
-               for (i = 0; i < ret; i++) {
-                       blocknr = gang[i];
-                       clear_radix_bit(&found, blocknr);
-                       if (path->reada == 1 && nread > 16)
-                               continue;
-                       if (close_blocks(cluster_start, blocknr)) {
-                               readahead_tree_block(root, blocknr);
-                               nread++;
-                               cluster_start = blocknr;
-                       }
+               if (direction < 0) {
+                       if (nr == 0)
+                               break;
+                       nr--;
+               } else if (direction > 0) {
+                       nr++;
+                       if (nr >= nritems)
+                               break;
                }
+               search = btrfs_node_blockptr(node, nr);
+               if ((search >= lowest_read && search <= highest_read) ||
+                   (search < lowest_read && lowest_read - search <= 32768) ||
+                   (search > highest_read && search - highest_read <= 32768)) {
+                       readahead_tree_block(root, search, blocksize);
+                       nread += blocksize;
+               }
+               nscan++;
+               if (path->reada < 2 && (nread > (256 * 1024) || nscan > 32))
+                       break;
+               if(nread > (1024 * 1024) || nscan > 128)
+                       break;
+
+               if (search < lowest_read)
+                       lowest_read = search;
+               if (search > highest_read)
+                       highest_read = search;
        }
-#endif
 }
 /*
  * look for key in the tree.  path is filled in with nodes along the way
index 0636f79672e9ad409aa0702782ff9f95c32e7fbe..8e606e6658aa7374f388a1933c088a7bf9eef5b7 100644 (file)
@@ -678,3 +678,63 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
        balance_dirty_pages_ratelimited_nr(
                        root->fs_info->btree_inode->i_mapping, nr);
 }
+
+void btrfs_set_buffer_defrag(struct extent_buffer *buf)
+{
+       struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
+       struct inode *btree_inode = root->fs_info->btree_inode;
+       set_extent_bits(&BTRFS_I(btree_inode)->extent_tree, buf->start,
+                       buf->start + buf->len - 1, EXTENT_DEFRAG, GFP_NOFS);
+}
+
+void btrfs_set_buffer_defrag_done(struct extent_buffer *buf)
+{
+       struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
+       struct inode *btree_inode = root->fs_info->btree_inode;
+       set_extent_bits(&BTRFS_I(btree_inode)->extent_tree, buf->start,
+                       buf->start + buf->len - 1, EXTENT_DEFRAG_DONE,
+                       GFP_NOFS);
+}
+
+int btrfs_buffer_defrag(struct extent_buffer *buf)
+{
+       struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
+       struct inode *btree_inode = root->fs_info->btree_inode;
+       return test_range_bit(&BTRFS_I(btree_inode)->extent_tree,
+                    buf->start, buf->start + buf->len - 1, EXTENT_DEFRAG, 0);
+}
+
+int btrfs_buffer_defrag_done(struct extent_buffer *buf)
+{
+       struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
+       struct inode *btree_inode = root->fs_info->btree_inode;
+       return test_range_bit(&BTRFS_I(btree_inode)->extent_tree,
+                    buf->start, buf->start + buf->len - 1,
+                    EXTENT_DEFRAG_DONE, 0);
+}
+
+int btrfs_clear_buffer_defrag_done(struct extent_buffer *buf)
+{
+       struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
+       struct inode *btree_inode = root->fs_info->btree_inode;
+       return clear_extent_bits(&BTRFS_I(btree_inode)->extent_tree,
+                    buf->start, buf->start + buf->len - 1,
+                    EXTENT_DEFRAG_DONE, GFP_NOFS);
+}
+
+int btrfs_clear_buffer_defrag(struct extent_buffer *buf)
+{
+       struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
+       struct inode *btree_inode = root->fs_info->btree_inode;
+       return clear_extent_bits(&BTRFS_I(btree_inode)->extent_tree,
+                    buf->start, buf->start + buf->len - 1,
+                    EXTENT_DEFRAG, GFP_NOFS);
+}
+
+int btrfs_read_buffer(struct extent_buffer *buf)
+{
+       struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
+       struct inode *btree_inode = root->fs_info->btree_inode;
+       return read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree,
+                                       buf, 1);
+}
index fd4db5f810cf2474d6dbde84d6608068059e9824..190b07bc642b9157fdb49a9019ec3342e825d22a 100644 (file)
@@ -51,4 +51,11 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf);
 int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
 int wait_on_tree_block_writeback(struct btrfs_root *root,
                                 struct extent_buffer *buf);
+void btrfs_set_buffer_defrag(struct extent_buffer *buf);
+void btrfs_set_buffer_defrag_done(struct extent_buffer *buf);
+int btrfs_buffer_defrag(struct extent_buffer *buf);
+int btrfs_buffer_defrag_done(struct extent_buffer *buf);
+int btrfs_clear_buffer_defrag(struct extent_buffer *buf);
+int btrfs_clear_buffer_defrag_done(struct extent_buffer *buf);
+int btrfs_read_buffer(struct extent_buffer *buf);
 #endif
index 1be8f9f04a13b47c17a992b366ec458d6dd3f7e9..0b0c947194ae42f4316b6b86577d9eb8654c8723 100644 (file)
@@ -1173,13 +1173,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
        buf->alloc_addr = (unsigned long)__builtin_return_address(0);
        set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
                         buf->start + buf->len - 1, GFP_NOFS);
-       /*
-       set_buffer_checked(buf);
-       set_buffer_defrag(buf);
-       */
-       /* FIXME!!!!!!!!!!!!!!!!
-       set_radix_bit(&trans->transaction->dirty_pages, buf->pages[0]->index);
-       */
+       btrfs_set_buffer_defrag(buf);
        trans->blocks_used++;
        return buf;
 }
index d74a2b3e3b5dd3271ed2df7e3eec2e8b2619d2a3..8409b5cbeda7ef83fc3248fc501b7341dc6e7f1b 100644 (file)
@@ -14,6 +14,8 @@
 #define EXTENT_LOCKED (1 << 3)
 #define EXTENT_NEW (1 << 4)
 #define EXTENT_DELALLOC (1 << 5)
+#define EXTENT_DEFRAG (1 << 6)
+#define EXTENT_DEFRAG_DONE (1 << 7)
 #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
 
 
index 60f61345a8d03a6a3302652bf7a562181132ed72..87456ab742757bc5643b2a3d24bb46e2f6a272ff 100644 (file)
@@ -355,7 +355,7 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly)
                return 0;
 
        trans = btrfs_start_transaction(root, 1);
-       while (0) {
+       while (1) {
                root->defrag_running = 1;
                ret = btrfs_defrag_leaves(trans, root, cacheonly);
                nr = trans->blocks_used;
@@ -400,7 +400,7 @@ int btrfs_defrag_dirty_roots(struct btrfs_fs_info *info)
                        btrfs_defrag_root(root, 1);
                }
        }
-       // btrfs_defrag_root(info->extent_root, 1);
+       btrfs_defrag_root(info->extent_root, 1);
        return err;
 }
 
index 3feac2f28628fc1503baf5bd82bc64d42a42da48..d23216aa4ab5a4b2e4a2e8c62a6eeaef8c458c62 100644 (file)
@@ -116,10 +116,10 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans,
        }
        WARN_ON(*level < 0);
        WARN_ON(*level >= BTRFS_MAX_LEVEL);
-#if 0
-       clear_buffer_defrag(path->nodes[*level]);
-       clear_buffer_defrag_done(path->nodes[*level]);
-#endif
+
+       btrfs_clear_buffer_defrag(path->nodes[*level]);
+       btrfs_clear_buffer_defrag_done(path->nodes[*level]);
+
        free_extent_buffer(path->nodes[*level]);
        path->nodes[*level] = NULL;
        *level += 1;
@@ -148,10 +148,8 @@ static int defrag_walk_up(struct btrfs_trans_handle *trans,
                        root->defrag_level = i;
                        return 0;
                } else {
-                       /*
-                       clear_buffer_defrag(path->nodes[*level]);
-                       clear_buffer_defrag_done(path->nodes[*level]);
-                       */
+                       btrfs_clear_buffer_defrag(path->nodes[*level]);
+                       btrfs_clear_buffer_defrag_done(path->nodes[*level]);
                        free_extent_buffer(path->nodes[*level]);
                        path->nodes[*level] = NULL;
                        *level = i + 1;