Btrfs: Add back the online defragging code

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 34de836..08ddf18 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -155,55 +155,49 @@
 	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 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 @@
 		       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 @@
 
 	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 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 @@
 
 	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 0636f79..8e606e6 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -678,3 +678,63 @@
 	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 fd4db5f..190b07b 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -51,4 +51,11 @@
 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 1be8f9f..0b0c947 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1173,13 +1173,7 @@
 	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 d74a2b3..8409b5c 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 60f6134..87456ab 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -355,7 +355,7 @@
 		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 @@
 			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 3feac2f..d23216a 100644
--- a/fs/btrfs/tree-defrag.c
+++ b/fs/btrfs/tree-defrag.c
@@ -116,10 +116,10 @@
 	}
 	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 @@
 			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;