summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-10-15 16:17:34 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:56 -0400
commit6b80053d02be41886344b5007d04e345311ec0b5 (patch)
treec935b3f2f4a582697167c52f57b0985137a95206 /fs
parent09e71a326341f40111400c88aaf0498ef622824b (diff)
downloadlwn-6b80053d02be41886344b5007d04e345311ec0b5.tar.gz
lwn-6b80053d02be41886344b5007d04e345311ec0b5.zip
Btrfs: Add back the online defragging code
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.c177
-rw-r--r--fs/btrfs/disk-io.c60
-rw-r--r--fs/btrfs/disk-io.h7
-rw-r--r--fs/btrfs/extent-tree.c8
-rw-r--r--fs/btrfs/extent_map.h2
-rw-r--r--fs/btrfs/transaction.c4
-rw-r--r--fs/btrfs/tree-defrag.c14
7 files changed, 166 insertions, 106 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 34de83630ae9..08ddf1873ab1 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -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
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 0636f79672e9..8e606e6658aa 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -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);
+}
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index fd4db5f810cf..190b07bc642b 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -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
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 1be8f9f04a13..0b0c947194ae 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -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;
}
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index d74a2b3e3b5d..8409b5cbeda7 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -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)
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 60f61345a8d0..87456ab74275 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -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;
}
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c
index 3feac2f28628..d23216aa4ab5 100644
--- a/fs/btrfs/tree-defrag.c
+++ b/fs/btrfs/tree-defrag.c
@@ -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;