#include "transaction.h"
#include "locking.h"
+/* defrag all the leaves in a given btree. If cache_only == 1, don't read
+ * things from disk, otherwise read all the leaves and try to get key order to
+ * better reflect disk order
+ */
+
int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
struct btrfs_root *root, int cache_only)
{
int wret;
int level;
int orig_level;
- int i;
int is_extent = 0;
int next_key_ret = 0;
u64 last_ret = 0;
+ u64 min_trans = 0;
+
+ if (cache_only)
+ goto out;
if (root->fs_info->extent_root == root) {
- mutex_lock(&root->fs_info->alloc_mutex);
- is_extent = 1;
+ /*
+ * there's recursion here right now in the tree locking,
+ * we can't defrag the extent root without deadlock
+ */
+ goto out;
}
if (root->ref_cows == 0 && !is_extent)
level = btrfs_header_level(root->node);
orig_level = level;
- if (level == 0) {
+ if (level == 0)
goto out;
- }
+
if (root->defrag_progress.objectid == 0) {
struct extent_buffer *root_node;
u32 nritems;
root_node = btrfs_lock_root_node(root);
+ btrfs_set_lock_blocking(root_node);
nritems = btrfs_header_nritems(root_node);
root->defrag_max.objectid = 0;
/* from above we know this is not a leaf */
memcpy(&key, &root->defrag_progress, sizeof(key));
}
- path->lowest_level = 1;
path->keep_locks = 1;
+ if (cache_only)
+ min_trans = root->defrag_trans_start;
+
+ ret = btrfs_search_forward(root, &key, NULL, path,
+ cache_only, min_trans);
+ if (ret < 0)
+ goto out;
+ if (ret > 0) {
+ ret = 0;
+ goto out;
+ }
+ btrfs_release_path(root, path);
wret = btrfs_search_slot(trans, root, &key, path, 0, 1);
if (wret < 0) {
goto out;
}
path->slots[1] = btrfs_header_nritems(path->nodes[1]);
- next_key_ret = btrfs_find_next_key(root, path, &key, 1);
+ next_key_ret = btrfs_find_next_key(root, path, &key, 1, cache_only,
+ min_trans);
ret = btrfs_realloc_node(trans, root,
path->nodes[1], 0,
cache_only, &last_ret,
ret = -EAGAIN;
}
- for (i = 1; i < BTRFS_MAX_LEVEL; i++) {
- if (path->locks[i]) {
- btrfs_tree_unlock(path->nodes[i]);
- path->locks[i] = 0;
- }
- if (path->nodes[i]) {
- free_extent_buffer(path->nodes[i]);
- path->nodes[i] = NULL;
- }
- }
- if (is_extent)
- btrfs_extent_post_op(trans, root);
-
+ btrfs_release_path(root, path);
out:
- if (is_extent)
- mutex_unlock(&root->fs_info->alloc_mutex);
-
if (path)
btrfs_free_path(path);
if (ret == -EAGAIN) {
if (ret != -EAGAIN) {
memset(&root->defrag_progress, 0,
sizeof(root->defrag_progress));
+ root->defrag_trans_start = trans->transid;
}
return ret;
}