|
@@ -1701,6 +1701,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
|
|
struct extent_buffer *b;
|
|
struct extent_buffer *b;
|
|
int slot;
|
|
int slot;
|
|
int ret;
|
|
int ret;
|
|
|
|
+ int err;
|
|
int level;
|
|
int level;
|
|
int lowest_unlock = 1;
|
|
int lowest_unlock = 1;
|
|
u8 lowest_level = 0;
|
|
u8 lowest_level = 0;
|
|
@@ -1737,8 +1738,6 @@ again:
|
|
p->locks[level] = 1;
|
|
p->locks[level] = 1;
|
|
|
|
|
|
if (cow) {
|
|
if (cow) {
|
|
- int wret;
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* if we don't really need to cow this block
|
|
* if we don't really need to cow this block
|
|
* then we don't want to set the path blocking,
|
|
* then we don't want to set the path blocking,
|
|
@@ -1749,12 +1748,12 @@ again:
|
|
|
|
|
|
btrfs_set_path_blocking(p);
|
|
btrfs_set_path_blocking(p);
|
|
|
|
|
|
- wret = btrfs_cow_block(trans, root, b,
|
|
|
|
- p->nodes[level + 1],
|
|
|
|
- p->slots[level + 1], &b);
|
|
|
|
- if (wret) {
|
|
|
|
|
|
+ err = btrfs_cow_block(trans, root, b,
|
|
|
|
+ p->nodes[level + 1],
|
|
|
|
+ p->slots[level + 1], &b);
|
|
|
|
+ if (err) {
|
|
free_extent_buffer(b);
|
|
free_extent_buffer(b);
|
|
- ret = wret;
|
|
|
|
|
|
+ ret = err;
|
|
goto done;
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1793,41 +1792,45 @@ cow_done:
|
|
ret = bin_search(b, key, level, &slot);
|
|
ret = bin_search(b, key, level, &slot);
|
|
|
|
|
|
if (level != 0) {
|
|
if (level != 0) {
|
|
- if (ret && slot > 0)
|
|
|
|
|
|
+ int dec = 0;
|
|
|
|
+ if (ret && slot > 0) {
|
|
|
|
+ dec = 1;
|
|
slot -= 1;
|
|
slot -= 1;
|
|
|
|
+ }
|
|
p->slots[level] = slot;
|
|
p->slots[level] = slot;
|
|
- ret = setup_nodes_for_search(trans, root, p, b, level,
|
|
|
|
|
|
+ err = setup_nodes_for_search(trans, root, p, b, level,
|
|
ins_len);
|
|
ins_len);
|
|
- if (ret == -EAGAIN)
|
|
|
|
|
|
+ if (err == -EAGAIN)
|
|
goto again;
|
|
goto again;
|
|
- else if (ret)
|
|
|
|
|
|
+ if (err) {
|
|
|
|
+ ret = err;
|
|
goto done;
|
|
goto done;
|
|
|
|
+ }
|
|
b = p->nodes[level];
|
|
b = p->nodes[level];
|
|
slot = p->slots[level];
|
|
slot = p->slots[level];
|
|
|
|
|
|
unlock_up(p, level, lowest_unlock);
|
|
unlock_up(p, level, lowest_unlock);
|
|
|
|
|
|
- /* this is only true while dropping a snapshot */
|
|
|
|
if (level == lowest_level) {
|
|
if (level == lowest_level) {
|
|
- ret = 0;
|
|
|
|
|
|
+ if (dec)
|
|
|
|
+ p->slots[level]++;
|
|
goto done;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
|
|
- ret = read_block_for_search(trans, root, p,
|
|
|
|
|
|
+ err = read_block_for_search(trans, root, p,
|
|
&b, level, slot, key);
|
|
&b, level, slot, key);
|
|
- if (ret == -EAGAIN)
|
|
|
|
|
|
+ if (err == -EAGAIN)
|
|
goto again;
|
|
goto again;
|
|
-
|
|
|
|
- if (ret == -EIO)
|
|
|
|
|
|
+ if (err) {
|
|
|
|
+ ret = err;
|
|
goto done;
|
|
goto done;
|
|
|
|
+ }
|
|
|
|
|
|
if (!p->skip_locking) {
|
|
if (!p->skip_locking) {
|
|
- int lret;
|
|
|
|
-
|
|
|
|
btrfs_clear_path_blocking(p, NULL);
|
|
btrfs_clear_path_blocking(p, NULL);
|
|
- lret = btrfs_try_spin_lock(b);
|
|
|
|
|
|
+ err = btrfs_try_spin_lock(b);
|
|
|
|
|
|
- if (!lret) {
|
|
|
|
|
|
+ if (!err) {
|
|
btrfs_set_path_blocking(p);
|
|
btrfs_set_path_blocking(p);
|
|
btrfs_tree_lock(b);
|
|
btrfs_tree_lock(b);
|
|
btrfs_clear_path_blocking(p, b);
|
|
btrfs_clear_path_blocking(p, b);
|
|
@@ -1837,16 +1840,14 @@ cow_done:
|
|
p->slots[level] = slot;
|
|
p->slots[level] = slot;
|
|
if (ins_len > 0 &&
|
|
if (ins_len > 0 &&
|
|
btrfs_leaf_free_space(root, b) < ins_len) {
|
|
btrfs_leaf_free_space(root, b) < ins_len) {
|
|
- int sret;
|
|
|
|
-
|
|
|
|
btrfs_set_path_blocking(p);
|
|
btrfs_set_path_blocking(p);
|
|
- sret = split_leaf(trans, root, key,
|
|
|
|
- p, ins_len, ret == 0);
|
|
|
|
|
|
+ err = split_leaf(trans, root, key,
|
|
|
|
+ p, ins_len, ret == 0);
|
|
btrfs_clear_path_blocking(p, NULL);
|
|
btrfs_clear_path_blocking(p, NULL);
|
|
|
|
|
|
- BUG_ON(sret > 0);
|
|
|
|
- if (sret) {
|
|
|
|
- ret = sret;
|
|
|
|
|
|
+ BUG_ON(err > 0);
|
|
|
|
+ if (err) {
|
|
|
|
+ ret = err;
|
|
goto done;
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -4042,10 +4043,9 @@ out:
|
|
* calling this function.
|
|
* calling this function.
|
|
*/
|
|
*/
|
|
int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
|
|
int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
|
|
- struct btrfs_key *key, int lowest_level,
|
|
|
|
|
|
+ struct btrfs_key *key, int level,
|
|
int cache_only, u64 min_trans)
|
|
int cache_only, u64 min_trans)
|
|
{
|
|
{
|
|
- int level = lowest_level;
|
|
|
|
int slot;
|
|
int slot;
|
|
struct extent_buffer *c;
|
|
struct extent_buffer *c;
|
|
|
|
|
|
@@ -4058,11 +4058,40 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
|
|
c = path->nodes[level];
|
|
c = path->nodes[level];
|
|
next:
|
|
next:
|
|
if (slot >= btrfs_header_nritems(c)) {
|
|
if (slot >= btrfs_header_nritems(c)) {
|
|
- level++;
|
|
|
|
- if (level == BTRFS_MAX_LEVEL)
|
|
|
|
|
|
+ int ret;
|
|
|
|
+ int orig_lowest;
|
|
|
|
+ struct btrfs_key cur_key;
|
|
|
|
+ if (level + 1 >= BTRFS_MAX_LEVEL ||
|
|
|
|
+ !path->nodes[level + 1])
|
|
return 1;
|
|
return 1;
|
|
- continue;
|
|
|
|
|
|
+
|
|
|
|
+ if (path->locks[level + 1]) {
|
|
|
|
+ level++;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ slot = btrfs_header_nritems(c) - 1;
|
|
|
|
+ if (level == 0)
|
|
|
|
+ btrfs_item_key_to_cpu(c, &cur_key, slot);
|
|
|
|
+ else
|
|
|
|
+ btrfs_node_key_to_cpu(c, &cur_key, slot);
|
|
|
|
+
|
|
|
|
+ orig_lowest = path->lowest_level;
|
|
|
|
+ btrfs_release_path(root, path);
|
|
|
|
+ path->lowest_level = level;
|
|
|
|
+ ret = btrfs_search_slot(NULL, root, &cur_key, path,
|
|
|
|
+ 0, 0);
|
|
|
|
+ path->lowest_level = orig_lowest;
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ c = path->nodes[level];
|
|
|
|
+ slot = path->slots[level];
|
|
|
|
+ if (ret == 0)
|
|
|
|
+ slot++;
|
|
|
|
+ goto next;
|
|
}
|
|
}
|
|
|
|
+
|
|
if (level == 0)
|
|
if (level == 0)
|
|
btrfs_item_key_to_cpu(c, key, slot);
|
|
btrfs_item_key_to_cpu(c, key, slot);
|
|
else {
|
|
else {
|