Commit 88fd146c authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse

Btrfs: pin freed blocks from the FS tree too

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent a8a2ee0c
...@@ -55,13 +55,13 @@ static int btrfs_cow_block(struct btrfs_root *root, ...@@ -55,13 +55,13 @@ static int btrfs_cow_block(struct btrfs_root *root,
root->node = cow; root->node = cow;
cow->count++; cow->count++;
if (buf != root->commit_root) if (buf != root->commit_root)
btrfs_free_extent(root, buf->blocknr, 1); btrfs_free_extent(root, buf->blocknr, 1, 1);
btrfs_block_release(root, buf); btrfs_block_release(root, buf);
} else { } else {
btrfs_set_node_blockptr(&parent->node, parent_slot, btrfs_set_node_blockptr(&parent->node, parent_slot,
cow->blocknr); cow->blocknr);
BUG_ON(list_empty(&parent->dirty)); BUG_ON(list_empty(&parent->dirty));
btrfs_free_extent(root, buf->blocknr, 1); btrfs_free_extent(root, buf->blocknr, 1, 1);
} }
btrfs_block_release(root, buf); btrfs_block_release(root, buf);
return 0; return 0;
...@@ -311,7 +311,7 @@ static int balance_level(struct btrfs_root *root, struct btrfs_path *path, ...@@ -311,7 +311,7 @@ static int balance_level(struct btrfs_root *root, struct btrfs_path *path,
/* once for the root ptr */ /* once for the root ptr */
btrfs_block_release(root, mid_buf); btrfs_block_release(root, mid_buf);
clean_tree_block(root, mid_buf); clean_tree_block(root, mid_buf);
return btrfs_free_extent(root, blocknr, 1); return btrfs_free_extent(root, blocknr, 1, 1);
} }
parent = &parent_buf->node; parent = &parent_buf->node;
...@@ -352,7 +352,7 @@ static int balance_level(struct btrfs_root *root, struct btrfs_path *path, ...@@ -352,7 +352,7 @@ static int balance_level(struct btrfs_root *root, struct btrfs_path *path,
wret = del_ptr(root, path, level + 1, pslot + 1); wret = del_ptr(root, path, level + 1, pslot + 1);
if (wret) if (wret)
ret = wret; ret = wret;
wret = btrfs_free_extent(root, blocknr, 1); wret = btrfs_free_extent(root, blocknr, 1, 1);
if (wret) if (wret)
ret = wret; ret = wret;
} else { } else {
...@@ -388,7 +388,7 @@ static int balance_level(struct btrfs_root *root, struct btrfs_path *path, ...@@ -388,7 +388,7 @@ static int balance_level(struct btrfs_root *root, struct btrfs_path *path,
wret = del_ptr(root, path, level + 1, pslot); wret = del_ptr(root, path, level + 1, pslot);
if (wret) if (wret)
ret = wret; ret = wret;
wret = btrfs_free_extent(root, blocknr, 1); wret = btrfs_free_extent(root, blocknr, 1, 1);
if (wret) if (wret)
ret = wret; ret = wret;
} else { } else {
...@@ -1310,7 +1310,7 @@ int btrfs_del_item(struct btrfs_root *root, struct btrfs_path *path) ...@@ -1310,7 +1310,7 @@ int btrfs_del_item(struct btrfs_root *root, struct btrfs_path *path)
wret = del_ptr(root, path, 1, path->slots[1]); wret = del_ptr(root, path, 1, path->slots[1]);
if (wret) if (wret)
ret = wret; ret = wret;
wret = btrfs_free_extent(root, leaf_buf->blocknr, 1); wret = btrfs_free_extent(root, leaf_buf->blocknr, 1, 1);
if (wret) if (wret)
ret = wret; ret = wret;
} }
...@@ -1348,7 +1348,7 @@ int btrfs_del_item(struct btrfs_root *root, struct btrfs_path *path) ...@@ -1348,7 +1348,7 @@ int btrfs_del_item(struct btrfs_root *root, struct btrfs_path *path)
if (wret) if (wret)
ret = wret; ret = wret;
btrfs_block_release(root, leaf_buf); btrfs_block_release(root, leaf_buf);
wret = btrfs_free_extent(root, blocknr, 1); wret = btrfs_free_extent(root, blocknr, 1, 1);
if (wret) if (wret)
ret = wret; ret = wret;
} else { } else {
......
...@@ -658,7 +658,8 @@ static inline u8 *btrfs_leaf_data(struct btrfs_leaf *l) ...@@ -658,7 +658,8 @@ static inline u8 *btrfs_leaf_data(struct btrfs_leaf *l)
struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_root *root); struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_root *root);
int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf); int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf);
int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks); int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks,
int pin);
int btrfs_search_slot(struct btrfs_root *root, struct btrfs_key *key, int btrfs_search_slot(struct btrfs_root *root, struct btrfs_key *key,
struct btrfs_path *p, int ins_len, int cow); struct btrfs_path *p, int ins_len, int cow);
void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p); void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
......
...@@ -95,6 +95,7 @@ int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf) ...@@ -95,6 +95,7 @@ int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf)
int btrfs_finish_extent_commit(struct btrfs_root *root) int btrfs_finish_extent_commit(struct btrfs_root *root)
{ {
unsigned long gang[8]; unsigned long gang[8];
u64 first = 0;
int ret; int ret;
int i; int i;
...@@ -104,11 +105,13 @@ int btrfs_finish_extent_commit(struct btrfs_root *root) ...@@ -104,11 +105,13 @@ int btrfs_finish_extent_commit(struct btrfs_root *root)
ARRAY_SIZE(gang)); ARRAY_SIZE(gang));
if (!ret) if (!ret)
break; break;
if (!first)
first = gang[0];
for (i = 0; i < ret; i++) { for (i = 0; i < ret; i++) {
radix_tree_delete(&root->pinned_radix, gang[i]); radix_tree_delete(&root->pinned_radix, gang[i]);
} }
} }
root->last_insert.objectid = 0; root->last_insert.objectid = first;
root->last_insert.offset = 0; root->last_insert.offset = 0;
return 0; return 0;
} }
...@@ -140,7 +143,8 @@ static int finish_current_insert(struct btrfs_root *extent_root) ...@@ -140,7 +143,8 @@ static int finish_current_insert(struct btrfs_root *extent_root)
/* /*
* remove an extent from the root, returns 0 on success * remove an extent from the root, returns 0 on success
*/ */
static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks,
int pin)
{ {
struct btrfs_path path; struct btrfs_path path;
struct btrfs_key key; struct btrfs_key key;
...@@ -150,6 +154,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) ...@@ -150,6 +154,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks)
struct btrfs_key ins; struct btrfs_key ins;
u32 refs; u32 refs;
BUG_ON(pin && num_blocks != 1);
key.objectid = blocknr; key.objectid = blocknr;
key.flags = 0; key.flags = 0;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
...@@ -170,7 +175,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) ...@@ -170,7 +175,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks)
refs = btrfs_extent_refs(ei) - 1; refs = btrfs_extent_refs(ei) - 1;
btrfs_set_extent_refs(ei, refs); btrfs_set_extent_refs(ei, refs);
if (refs == 0) { if (refs == 0) {
if (!root->ref_cows) { if (pin) {
int err; int err;
radix_tree_preload(GFP_KERNEL); radix_tree_preload(GFP_KERNEL);
err = radix_tree_insert(&extent_root->pinned_radix, err = radix_tree_insert(&extent_root->pinned_radix,
...@@ -179,8 +184,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) ...@@ -179,8 +184,7 @@ static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks)
radix_tree_preload_end(); radix_tree_preload_end();
} }
ret = btrfs_del_item(extent_root, &path); ret = btrfs_del_item(extent_root, &path);
if (root != extent_root && if (!pin && extent_root->last_insert.objectid > blocknr)
extent_root->last_insert.objectid > blocknr)
extent_root->last_insert.objectid = blocknr; extent_root->last_insert.objectid = blocknr;
if (ret) if (ret)
BUG(); BUG();
...@@ -208,7 +212,8 @@ static int del_pending_extents(struct btrfs_root *extent_root) ...@@ -208,7 +212,8 @@ static int del_pending_extents(struct btrfs_root *extent_root)
if (!ret) if (!ret)
break; break;
for (i = 0; i < ret; i++) { for (i = 0; i < ret; i++) {
ret = __free_extent(extent_root, gang[i]->blocknr, 1); ret = __free_extent(extent_root,
gang[i]->blocknr, 1, 1);
radix_tree_tag_clear(&extent_root->cache_radix, radix_tree_tag_clear(&extent_root->cache_radix,
gang[i]->blocknr, gang[i]->blocknr,
CTREE_EXTENT_PENDING_DEL); CTREE_EXTENT_PENDING_DEL);
...@@ -230,7 +235,8 @@ static int run_pending(struct btrfs_root *extent_root) ...@@ -230,7 +235,8 @@ static int run_pending(struct btrfs_root *extent_root)
/* /*
* remove an extent from the root, returns 0 on success * remove an extent from the root, returns 0 on success
*/ */
int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks,
int pin)
{ {
struct btrfs_root *extent_root = root->extent_root; struct btrfs_root *extent_root = root->extent_root;
struct btrfs_buffer *t; struct btrfs_buffer *t;
...@@ -243,7 +249,7 @@ int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks) ...@@ -243,7 +249,7 @@ int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks)
CTREE_EXTENT_PENDING_DEL); CTREE_EXTENT_PENDING_DEL);
return 0; return 0;
} }
ret = __free_extent(root, blocknr, num_blocks); ret = __free_extent(root, blocknr, num_blocks, pin);
pending_ret = run_pending(root->extent_root); pending_ret = run_pending(root->extent_root);
return ret ? ret : pending_ret; return ret ? ret : pending_ret;
} }
...@@ -451,7 +457,7 @@ static int walk_down_tree(struct btrfs_root *root, ...@@ -451,7 +457,7 @@ static int walk_down_tree(struct btrfs_root *root,
ret = lookup_block_ref(root, blocknr, &refs); ret = lookup_block_ref(root, blocknr, &refs);
if (refs != 1 || *level == 1) { if (refs != 1 || *level == 1) {
path->slots[*level]++; path->slots[*level]++;
ret = btrfs_free_extent(root, blocknr, 1); ret = btrfs_free_extent(root, blocknr, 1, 1);
BUG_ON(ret); BUG_ON(ret);
continue; continue;
} }
...@@ -464,7 +470,7 @@ static int walk_down_tree(struct btrfs_root *root, ...@@ -464,7 +470,7 @@ static int walk_down_tree(struct btrfs_root *root,
path->slots[*level] = 0; path->slots[*level] = 0;
} }
out: out:
ret = btrfs_free_extent(root, path->nodes[*level]->blocknr, 1); ret = btrfs_free_extent(root, path->nodes[*level]->blocknr, 1, 1);
btrfs_block_release(root, path->nodes[*level]); btrfs_block_release(root, path->nodes[*level]);
path->nodes[*level] = NULL; path->nodes[*level] = NULL;
*level += 1; *level += 1;
...@@ -492,7 +498,7 @@ static int walk_up_tree(struct btrfs_root *root, struct btrfs_path *path, ...@@ -492,7 +498,7 @@ static int walk_up_tree(struct btrfs_root *root, struct btrfs_path *path,
return 0; return 0;
} else { } else {
ret = btrfs_free_extent(root, ret = btrfs_free_extent(root,
path->nodes[*level]->blocknr, 1); path->nodes[*level]->blocknr, 1, 1);
btrfs_block_release(root, path->nodes[*level]); btrfs_block_release(root, path->nodes[*level]);
path->nodes[*level] = NULL; path->nodes[*level] = NULL;
*level = i + 1; *level = i + 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment