if (ret)
return ret;
} else {
- WARN_ON(!root->ref_cows);
clean_tree_block(trans, root, buf);
}
int btrfs_realloc_node(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct buffer_head *parent,
- int cache_only)
+ int cache_only, u64 *last_ret)
{
struct btrfs_node *parent_node;
struct buffer_head *cur_bh;
struct buffer_head *tmp_bh;
u64 blocknr;
- u64 search_start = 0;
+ u64 search_start = *last_ret;
+ u64 last_block = 0;
u64 other;
u32 parent_nritems;
int start_slot;
for (i = start_slot; i < end_slot; i++) {
int close = 1;
blocknr = btrfs_node_blockptr(parent_node, 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_node, i + 1);
close = close_blocks(blocknr, other);
}
- if (close)
+ if (close) {
+ last_block = blocknr;
continue;
+ }
cur_bh = btrfs_find_tree_block(root, blocknr);
if (!cur_bh || !buffer_uptodate(cur_bh) ||
brelse(cur_bh);
cur_bh = read_tree_block(root, blocknr);
}
- if (search_start == 0) {
- search_start = bh_blocknr(cur_bh) & ~((u64)65535);
- }
+ if (search_start == 0)
+ search_start = last_block & ~((u64)65535);
+
err = __btrfs_cow_block(trans, root, cur_bh, parent, i,
&tmp_bh, search_start,
min(8, end_slot - i));
btrfs_item_offset((leaf)->items + (slot))))
/* extent-tree.c */
+int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root);
int btrfs_copy_pinned(struct btrfs_root *root, struct radix_tree_root *copy);
struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
btrfs_fs_info *info,
ins_len, int cow);
int btrfs_realloc_node(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct buffer_head *parent,
- int cache_only);
+ int cache_only, u64 *last_ret);
void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
struct btrfs_path *btrfs_alloc_path(void);
void btrfs_free_path(struct btrfs_path *p);
return 0;
}
+int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
+{
+ finish_current_insert(trans, root->fs_info->extent_root);
+ del_pending_extents(trans, root->fs_info->extent_root);
+ return 0;
+}
+
static int lookup_extent_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 blocknr,
u64 num_blocks, u32 *refs)
BUG_ON(ret);
continue;
}
- next = read_tree_block(root, blocknr);
+ next = btrfs_find_tree_block(root, blocknr);
+ if (!next || !buffer_uptodate(next)) {
+ brelse(next);
+ mutex_unlock(&root->fs_info->fs_mutex);
+ next = read_tree_block(root, blocknr);
+ mutex_lock(&root->fs_info->fs_mutex);
+
+ /* we dropped the lock, check one more time */
+ ret = lookup_extent_ref(trans, root, blocknr, 1, &refs);
+ BUG_ON(ret);
+ if (refs != 1) {
+ path->slots[*level]++;
+ brelse(next);
+ ret = btrfs_free_extent(trans, root,
+ blocknr, 1, 1);
+ BUG_ON(ret);
+ continue;
+ }
+ }
WARN_ON(*level <= 0);
if (path->nodes[*level-1])
btrfs_block_release(root, path->nodes[*level-1]);
{
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_ioctl_vol_args vol_args;
- struct btrfs_trans_handle *trans;
int ret = 0;
- int err;
struct btrfs_dir_item *di;
int namelen;
struct btrfs_path *path;
case BTRFS_IOC_DEFRAG:
mutex_lock(&root->fs_info->fs_mutex);
- trans = btrfs_start_transaction(root, 1);
- memset(&root->defrag_progress, 0,
- sizeof(root->defrag_progress));
- while (1) {
- root->defrag_running = 1;
- err = btrfs_defrag_leaves(trans, root, 0);
-
- btrfs_end_transaction(trans, root);
- mutex_unlock(&root->fs_info->fs_mutex);
-
- btrfs_btree_balance_dirty(root);
-
- mutex_lock(&root->fs_info->fs_mutex);
- trans = btrfs_start_transaction(root, 1);
- if (err != -EAGAIN)
- break;
- }
- root->defrag_running = 0;
- btrfs_end_transaction(trans, root);
+ btrfs_defrag_root(root, 0);
+ btrfs_defrag_root(root->fs_info->extent_root, 0);
mutex_unlock(&root->fs_info->fs_mutex);
ret = 0;
break;