|
@@ -54,8 +54,13 @@ noinline void btrfs_set_path_blocking(struct btrfs_path *p)
|
|
|
{
|
|
|
int i;
|
|
|
for (i = 0; i < BTRFS_MAX_LEVEL; i++) {
|
|
|
- if (p->nodes[i] && p->locks[i])
|
|
|
- btrfs_set_lock_blocking(p->nodes[i]);
|
|
|
+ if (!p->nodes[i] || !p->locks[i])
|
|
|
+ continue;
|
|
|
+ btrfs_set_lock_blocking_rw(p->nodes[i], p->locks[i]);
|
|
|
+ if (p->locks[i] == BTRFS_READ_LOCK)
|
|
|
+ p->locks[i] = BTRFS_READ_LOCK_BLOCKING;
|
|
|
+ else if (p->locks[i] == BTRFS_WRITE_LOCK)
|
|
|
+ p->locks[i] = BTRFS_WRITE_LOCK_BLOCKING;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -68,7 +73,7 @@ noinline void btrfs_set_path_blocking(struct btrfs_path *p)
|
|
|
* for held
|
|
|
*/
|
|
|
noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
|
|
|
- struct extent_buffer *held)
|
|
|
+ struct extent_buffer *held, int held_rw)
|
|
|
{
|
|
|
int i;
|
|
|
|
|
@@ -79,19 +84,29 @@ noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
|
|
|
* really sure by forcing the path to blocking before we clear
|
|
|
* the path blocking.
|
|
|
*/
|
|
|
- if (held)
|
|
|
- btrfs_set_lock_blocking(held);
|
|
|
+ if (held) {
|
|
|
+ btrfs_set_lock_blocking_rw(held, held_rw);
|
|
|
+ if (held_rw == BTRFS_WRITE_LOCK)
|
|
|
+ held_rw = BTRFS_WRITE_LOCK_BLOCKING;
|
|
|
+ else if (held_rw == BTRFS_READ_LOCK)
|
|
|
+ held_rw = BTRFS_READ_LOCK_BLOCKING;
|
|
|
+ }
|
|
|
btrfs_set_path_blocking(p);
|
|
|
#endif
|
|
|
|
|
|
for (i = BTRFS_MAX_LEVEL - 1; i >= 0; i--) {
|
|
|
- if (p->nodes[i] && p->locks[i])
|
|
|
- btrfs_clear_lock_blocking(p->nodes[i]);
|
|
|
+ if (p->nodes[i] && p->locks[i]) {
|
|
|
+ btrfs_clear_lock_blocking_rw(p->nodes[i], p->locks[i]);
|
|
|
+ if (p->locks[i] == BTRFS_WRITE_LOCK_BLOCKING)
|
|
|
+ p->locks[i] = BTRFS_WRITE_LOCK;
|
|
|
+ else if (p->locks[i] == BTRFS_READ_LOCK_BLOCKING)
|
|
|
+ p->locks[i] = BTRFS_READ_LOCK;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
|
if (held)
|
|
|
- btrfs_clear_lock_blocking(held);
|
|
|
+ btrfs_clear_lock_blocking_rw(held, held_rw);
|
|
|
#endif
|
|
|
}
|
|
|
|
|
@@ -119,7 +134,7 @@ noinline void btrfs_release_path(struct btrfs_path *p)
|
|
|
if (!p->nodes[i])
|
|
|
continue;
|
|
|
if (p->locks[i]) {
|
|
|
- btrfs_tree_unlock(p->nodes[i]);
|
|
|
+ btrfs_tree_unlock_rw(p->nodes[i], p->locks[i]);
|
|
|
p->locks[i] = 0;
|
|
|
}
|
|
|
free_extent_buffer(p->nodes[i]);
|
|
@@ -167,6 +182,25 @@ struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root)
|
|
|
return eb;
|
|
|
}
|
|
|
|
|
|
+/* loop around taking references on and locking the root node of the
|
|
|
+ * tree until you end up with a lock on the root. A locked buffer
|
|
|
+ * is returned, with a reference held.
|
|
|
+ */
|
|
|
+struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root)
|
|
|
+{
|
|
|
+ struct extent_buffer *eb;
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ eb = btrfs_root_node(root);
|
|
|
+ btrfs_tree_read_lock(eb);
|
|
|
+ if (eb == root->node)
|
|
|
+ break;
|
|
|
+ btrfs_tree_read_unlock(eb);
|
|
|
+ free_extent_buffer(eb);
|
|
|
+ }
|
|
|
+ return eb;
|
|
|
+}
|
|
|
+
|
|
|
/* cowonly root (everything not a reference counted cow subvolume), just get
|
|
|
* put onto a simple dirty list. transaction.c walks this to make sure they
|
|
|
* get properly updated on disk.
|
|
@@ -626,14 +660,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
|
|
|
for (i = start_slot; i < end_slot; i++) {
|
|
|
int close = 1;
|
|
|
|
|
|
- if (!parent->map_token) {
|
|
|
- map_extent_buffer(parent,
|
|
|
- btrfs_node_key_ptr_offset(i),
|
|
|
- sizeof(struct btrfs_key_ptr),
|
|
|
- &parent->map_token, &parent->kaddr,
|
|
|
- &parent->map_start, &parent->map_len,
|
|
|
- KM_USER1);
|
|
|
- }
|
|
|
btrfs_node_key(parent, &disk_key, i);
|
|
|
if (!progress_passed && comp_keys(&disk_key, progress) < 0)
|
|
|
continue;
|
|
@@ -656,11 +682,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
|
|
|
last_block = blocknr;
|
|
|
continue;
|
|
|
}
|
|
|
- if (parent->map_token) {
|
|
|
- unmap_extent_buffer(parent, parent->map_token,
|
|
|
- KM_USER1);
|
|
|
- parent->map_token = NULL;
|
|
|
- }
|
|
|
|
|
|
cur = btrfs_find_tree_block(root, blocknr, blocksize);
|
|
|
if (cur)
|
|
@@ -701,11 +722,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
|
|
|
btrfs_tree_unlock(cur);
|
|
|
free_extent_buffer(cur);
|
|
|
}
|
|
|
- if (parent->map_token) {
|
|
|
- unmap_extent_buffer(parent, parent->map_token,
|
|
|
- KM_USER1);
|
|
|
- parent->map_token = NULL;
|
|
|
- }
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -746,7 +762,6 @@ static noinline int generic_bin_search(struct extent_buffer *eb,
|
|
|
struct btrfs_disk_key *tmp = NULL;
|
|
|
struct btrfs_disk_key unaligned;
|
|
|
unsigned long offset;
|
|
|
- char *map_token = NULL;
|
|
|
char *kaddr = NULL;
|
|
|
unsigned long map_start = 0;
|
|
|
unsigned long map_len = 0;
|
|
@@ -756,18 +771,13 @@ static noinline int generic_bin_search(struct extent_buffer *eb,
|
|
|
mid = (low + high) / 2;
|
|
|
offset = p + mid * item_size;
|
|
|
|
|
|
- if (!map_token || offset < map_start ||
|
|
|
+ if (!kaddr || offset < map_start ||
|
|
|
(offset + sizeof(struct btrfs_disk_key)) >
|
|
|
map_start + map_len) {
|
|
|
- if (map_token) {
|
|
|
- unmap_extent_buffer(eb, map_token, KM_USER0);
|
|
|
- map_token = NULL;
|
|
|
- }
|
|
|
|
|
|
err = map_private_extent_buffer(eb, offset,
|
|
|
sizeof(struct btrfs_disk_key),
|
|
|
- &map_token, &kaddr,
|
|
|
- &map_start, &map_len, KM_USER0);
|
|
|
+ &kaddr, &map_start, &map_len);
|
|
|
|
|
|
if (!err) {
|
|
|
tmp = (struct btrfs_disk_key *)(kaddr + offset -
|
|
@@ -790,14 +800,10 @@ static noinline int generic_bin_search(struct extent_buffer *eb,
|
|
|
high = mid;
|
|
|
else {
|
|
|
*slot = mid;
|
|
|
- if (map_token)
|
|
|
- unmap_extent_buffer(eb, map_token, KM_USER0);
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
*slot = low;
|
|
|
- if (map_token)
|
|
|
- unmap_extent_buffer(eb, map_token, KM_USER0);
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
@@ -890,7 +896,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
mid = path->nodes[level];
|
|
|
|
|
|
- WARN_ON(!path->locks[level]);
|
|
|
+ WARN_ON(path->locks[level] != BTRFS_WRITE_LOCK &&
|
|
|
+ path->locks[level] != BTRFS_WRITE_LOCK_BLOCKING);
|
|
|
WARN_ON(btrfs_header_generation(mid) != trans->transid);
|
|
|
|
|
|
orig_ptr = btrfs_node_blockptr(mid, orig_slot);
|
|
@@ -1228,7 +1235,6 @@ static void reada_for_search(struct btrfs_root *root,
|
|
|
u32 nr;
|
|
|
u32 blocksize;
|
|
|
u32 nscan = 0;
|
|
|
- bool map = true;
|
|
|
|
|
|
if (level != 1)
|
|
|
return;
|
|
@@ -1250,19 +1256,8 @@ static void reada_for_search(struct btrfs_root *root,
|
|
|
|
|
|
nritems = btrfs_header_nritems(node);
|
|
|
nr = slot;
|
|
|
- if (node->map_token || path->skip_locking)
|
|
|
- map = false;
|
|
|
|
|
|
while (1) {
|
|
|
- if (map && !node->map_token) {
|
|
|
- unsigned long offset = btrfs_node_key_ptr_offset(nr);
|
|
|
- map_private_extent_buffer(node, offset,
|
|
|
- sizeof(struct btrfs_key_ptr),
|
|
|
- &node->map_token,
|
|
|
- &node->kaddr,
|
|
|
- &node->map_start,
|
|
|
- &node->map_len, KM_USER1);
|
|
|
- }
|
|
|
if (direction < 0) {
|
|
|
if (nr == 0)
|
|
|
break;
|
|
@@ -1281,11 +1276,6 @@ static void reada_for_search(struct btrfs_root *root,
|
|
|
if ((search <= target && target - search <= 65536) ||
|
|
|
(search > target && search - target <= 65536)) {
|
|
|
gen = btrfs_node_ptr_generation(node, nr);
|
|
|
- if (map && node->map_token) {
|
|
|
- unmap_extent_buffer(node, node->map_token,
|
|
|
- KM_USER1);
|
|
|
- node->map_token = NULL;
|
|
|
- }
|
|
|
readahead_tree_block(root, search, blocksize, gen);
|
|
|
nread += blocksize;
|
|
|
}
|
|
@@ -1293,10 +1283,6 @@ static void reada_for_search(struct btrfs_root *root,
|
|
|
if ((nread > 65536 || nscan > 32))
|
|
|
break;
|
|
|
}
|
|
|
- if (map && node->map_token) {
|
|
|
- unmap_extent_buffer(node, node->map_token, KM_USER1);
|
|
|
- node->map_token = NULL;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1409,7 +1395,7 @@ static noinline void unlock_up(struct btrfs_path *path, int level,
|
|
|
|
|
|
t = path->nodes[i];
|
|
|
if (i >= lowest_unlock && i > skip_level && path->locks[i]) {
|
|
|
- btrfs_tree_unlock(t);
|
|
|
+ btrfs_tree_unlock_rw(t, path->locks[i]);
|
|
|
path->locks[i] = 0;
|
|
|
}
|
|
|
}
|
|
@@ -1436,7 +1422,7 @@ noinline void btrfs_unlock_up_safe(struct btrfs_path *path, int level)
|
|
|
continue;
|
|
|
if (!path->locks[i])
|
|
|
continue;
|
|
|
- btrfs_tree_unlock(path->nodes[i]);
|
|
|
+ btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]);
|
|
|
path->locks[i] = 0;
|
|
|
}
|
|
|
}
|
|
@@ -1485,6 +1471,8 @@ read_block_for_search(struct btrfs_trans_handle *trans,
|
|
|
* we can trust our generation number
|
|
|
*/
|
|
|
free_extent_buffer(tmp);
|
|
|
+ btrfs_set_path_blocking(p);
|
|
|
+
|
|
|
tmp = read_tree_block(root, blocknr, blocksize, gen);
|
|
|
if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
|
|
|
*eb_ret = tmp;
|
|
@@ -1540,20 +1528,27 @@ read_block_for_search(struct btrfs_trans_handle *trans,
|
|
|
static int
|
|
|
setup_nodes_for_search(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root, struct btrfs_path *p,
|
|
|
- struct extent_buffer *b, int level, int ins_len)
|
|
|
+ struct extent_buffer *b, int level, int ins_len,
|
|
|
+ int *write_lock_level)
|
|
|
{
|
|
|
int ret;
|
|
|
if ((p->search_for_split || ins_len > 0) && btrfs_header_nritems(b) >=
|
|
|
BTRFS_NODEPTRS_PER_BLOCK(root) - 3) {
|
|
|
int sret;
|
|
|
|
|
|
+ if (*write_lock_level < level + 1) {
|
|
|
+ *write_lock_level = level + 1;
|
|
|
+ btrfs_release_path(p);
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
+
|
|
|
sret = reada_for_balance(root, p, level);
|
|
|
if (sret)
|
|
|
goto again;
|
|
|
|
|
|
btrfs_set_path_blocking(p);
|
|
|
sret = split_node(trans, root, p, level);
|
|
|
- btrfs_clear_path_blocking(p, NULL);
|
|
|
+ btrfs_clear_path_blocking(p, NULL, 0);
|
|
|
|
|
|
BUG_ON(sret > 0);
|
|
|
if (sret) {
|
|
@@ -1565,13 +1560,19 @@ setup_nodes_for_search(struct btrfs_trans_handle *trans,
|
|
|
BTRFS_NODEPTRS_PER_BLOCK(root) / 2) {
|
|
|
int sret;
|
|
|
|
|
|
+ if (*write_lock_level < level + 1) {
|
|
|
+ *write_lock_level = level + 1;
|
|
|
+ btrfs_release_path(p);
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
+
|
|
|
sret = reada_for_balance(root, p, level);
|
|
|
if (sret)
|
|
|
goto again;
|
|
|
|
|
|
btrfs_set_path_blocking(p);
|
|
|
sret = balance_level(trans, root, p, level);
|
|
|
- btrfs_clear_path_blocking(p, NULL);
|
|
|
+ btrfs_clear_path_blocking(p, NULL, 0);
|
|
|
|
|
|
if (sret) {
|
|
|
ret = sret;
|
|
@@ -1615,27 +1616,78 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
|
|
|
int err;
|
|
|
int level;
|
|
|
int lowest_unlock = 1;
|
|
|
+ int root_lock;
|
|
|
+ /* everything at write_lock_level or lower must be write locked */
|
|
|
+ int write_lock_level = 0;
|
|
|
u8 lowest_level = 0;
|
|
|
|
|
|
lowest_level = p->lowest_level;
|
|
|
WARN_ON(lowest_level && ins_len > 0);
|
|
|
WARN_ON(p->nodes[0] != NULL);
|
|
|
|
|
|
- if (ins_len < 0)
|
|
|
+ if (ins_len < 0) {
|
|
|
lowest_unlock = 2;
|
|
|
|
|
|
+ /* when we are removing items, we might have to go up to level
|
|
|
+ * two as we update tree pointers Make sure we keep write
|
|
|
+ * for those levels as well
|
|
|
+ */
|
|
|
+ write_lock_level = 2;
|
|
|
+ } else if (ins_len > 0) {
|
|
|
+ /*
|
|
|
+ * for inserting items, make sure we have a write lock on
|
|
|
+ * level 1 so we can update keys
|
|
|
+ */
|
|
|
+ write_lock_level = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!cow)
|
|
|
+ write_lock_level = -1;
|
|
|
+
|
|
|
+ if (cow && (p->keep_locks || p->lowest_level))
|
|
|
+ write_lock_level = BTRFS_MAX_LEVEL;
|
|
|
+
|
|
|
again:
|
|
|
+ /*
|
|
|
+ * we try very hard to do read locks on the root
|
|
|
+ */
|
|
|
+ root_lock = BTRFS_READ_LOCK;
|
|
|
+ level = 0;
|
|
|
if (p->search_commit_root) {
|
|
|
+ /*
|
|
|
+ * the commit roots are read only
|
|
|
+ * so we always do read locks
|
|
|
+ */
|
|
|
b = root->commit_root;
|
|
|
extent_buffer_get(b);
|
|
|
+ level = btrfs_header_level(b);
|
|
|
if (!p->skip_locking)
|
|
|
- btrfs_tree_lock(b);
|
|
|
+ btrfs_tree_read_lock(b);
|
|
|
} else {
|
|
|
- if (p->skip_locking)
|
|
|
+ if (p->skip_locking) {
|
|
|
b = btrfs_root_node(root);
|
|
|
- else
|
|
|
- b = btrfs_lock_root_node(root);
|
|
|
+ level = btrfs_header_level(b);
|
|
|
+ } else {
|
|
|
+ /* we don't know the level of the root node
|
|
|
+ * until we actually have it read locked
|
|
|
+ */
|
|
|
+ b = btrfs_read_lock_root_node(root);
|
|
|
+ level = btrfs_header_level(b);
|
|
|
+ if (level <= write_lock_level) {
|
|
|
+ /* whoops, must trade for write lock */
|
|
|
+ btrfs_tree_read_unlock(b);
|
|
|
+ free_extent_buffer(b);
|
|
|
+ b = btrfs_lock_root_node(root);
|
|
|
+ root_lock = BTRFS_WRITE_LOCK;
|
|
|
+
|
|
|
+ /* the level might have changed, check again */
|
|
|
+ level = btrfs_header_level(b);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+ p->nodes[level] = b;
|
|
|
+ if (!p->skip_locking)
|
|
|
+ p->locks[level] = root_lock;
|
|
|
|
|
|
while (b) {
|
|
|
level = btrfs_header_level(b);
|
|
@@ -1644,10 +1696,6 @@ again:
|
|
|
* setup the path here so we can release it under lock
|
|
|
* contention with the cow code
|
|
|
*/
|
|
|
- p->nodes[level] = b;
|
|
|
- if (!p->skip_locking)
|
|
|
- p->locks[level] = 1;
|
|
|
-
|
|
|
if (cow) {
|
|
|
/*
|
|
|
* if we don't really need to cow this block
|
|
@@ -1659,6 +1707,16 @@ again:
|
|
|
|
|
|
btrfs_set_path_blocking(p);
|
|
|
|
|
|
+ /*
|
|
|
+ * must have write locks on this node and the
|
|
|
+ * parent
|
|
|
+ */
|
|
|
+ if (level + 1 > write_lock_level) {
|
|
|
+ write_lock_level = level + 1;
|
|
|
+ btrfs_release_path(p);
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
+
|
|
|
err = btrfs_cow_block(trans, root, b,
|
|
|
p->nodes[level + 1],
|
|
|
p->slots[level + 1], &b);
|
|
@@ -1671,10 +1729,7 @@ cow_done:
|
|
|
BUG_ON(!cow && ins_len);
|
|
|
|
|
|
p->nodes[level] = b;
|
|
|
- if (!p->skip_locking)
|
|
|
- p->locks[level] = 1;
|
|
|
-
|
|
|
- btrfs_clear_path_blocking(p, NULL);
|
|
|
+ btrfs_clear_path_blocking(p, NULL, 0);
|
|
|
|
|
|
/*
|
|
|
* we have a lock on b and as long as we aren't changing
|
|
@@ -1700,7 +1755,7 @@ cow_done:
|
|
|
}
|
|
|
p->slots[level] = slot;
|
|
|
err = setup_nodes_for_search(trans, root, p, b, level,
|
|
|
- ins_len);
|
|
|
+ ins_len, &write_lock_level);
|
|
|
if (err == -EAGAIN)
|
|
|
goto again;
|
|
|
if (err) {
|
|
@@ -1710,6 +1765,19 @@ cow_done:
|
|
|
b = p->nodes[level];
|
|
|
slot = p->slots[level];
|
|
|
|
|
|
+ /*
|
|
|
+ * slot 0 is special, if we change the key
|
|
|
+ * we have to update the parent pointer
|
|
|
+ * which means we must have a write lock
|
|
|
+ * on the parent
|
|
|
+ */
|
|
|
+ if (slot == 0 && cow &&
|
|
|
+ write_lock_level < level + 1) {
|
|
|
+ write_lock_level = level + 1;
|
|
|
+ btrfs_release_path(p);
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
+
|
|
|
unlock_up(p, level, lowest_unlock);
|
|
|
|
|
|
if (level == lowest_level) {
|
|
@@ -1728,23 +1796,42 @@ cow_done:
|
|
|
}
|
|
|
|
|
|
if (!p->skip_locking) {
|
|
|
- btrfs_clear_path_blocking(p, NULL);
|
|
|
- err = btrfs_try_spin_lock(b);
|
|
|
-
|
|
|
- if (!err) {
|
|
|
- btrfs_set_path_blocking(p);
|
|
|
- btrfs_tree_lock(b);
|
|
|
- btrfs_clear_path_blocking(p, b);
|
|
|
+ level = btrfs_header_level(b);
|
|
|
+ if (level <= write_lock_level) {
|
|
|
+ err = btrfs_try_tree_write_lock(b);
|
|
|
+ if (!err) {
|
|
|
+ btrfs_set_path_blocking(p);
|
|
|
+ btrfs_tree_lock(b);
|
|
|
+ btrfs_clear_path_blocking(p, b,
|
|
|
+ BTRFS_WRITE_LOCK);
|
|
|
+ }
|
|
|
+ p->locks[level] = BTRFS_WRITE_LOCK;
|
|
|
+ } else {
|
|
|
+ err = btrfs_try_tree_read_lock(b);
|
|
|
+ if (!err) {
|
|
|
+ btrfs_set_path_blocking(p);
|
|
|
+ btrfs_tree_read_lock(b);
|
|
|
+ btrfs_clear_path_blocking(p, b,
|
|
|
+ BTRFS_READ_LOCK);
|
|
|
+ }
|
|
|
+ p->locks[level] = BTRFS_READ_LOCK;
|
|
|
}
|
|
|
+ p->nodes[level] = b;
|
|
|
}
|
|
|
} else {
|
|
|
p->slots[level] = slot;
|
|
|
if (ins_len > 0 &&
|
|
|
btrfs_leaf_free_space(root, b) < ins_len) {
|
|
|
+ if (write_lock_level < 1) {
|
|
|
+ write_lock_level = 1;
|
|
|
+ btrfs_release_path(p);
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
+
|
|
|
btrfs_set_path_blocking(p);
|
|
|
err = split_leaf(trans, root, key,
|
|
|
p, ins_len, ret == 0);
|
|
|
- btrfs_clear_path_blocking(p, NULL);
|
|
|
+ btrfs_clear_path_blocking(p, NULL, 0);
|
|
|
|
|
|
BUG_ON(err > 0);
|
|
|
if (err) {
|
|
@@ -2025,7 +2112,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
|
|
|
add_root_to_dirty_list(root);
|
|
|
extent_buffer_get(c);
|
|
|
path->nodes[level] = c;
|
|
|
- path->locks[level] = 1;
|
|
|
+ path->locks[level] = BTRFS_WRITE_LOCK;
|
|
|
path->slots[level] = 0;
|
|
|
return 0;
|
|
|
}
|
|
@@ -2253,14 +2340,6 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
|
|
|
if (path->slots[0] == i)
|
|
|
push_space += data_size;
|
|
|
|
|
|
- if (!left->map_token) {
|
|
|
- map_extent_buffer(left, (unsigned long)item,
|
|
|
- sizeof(struct btrfs_item),
|
|
|
- &left->map_token, &left->kaddr,
|
|
|
- &left->map_start, &left->map_len,
|
|
|
- KM_USER1);
|
|
|
- }
|
|
|
-
|
|
|
this_item_size = btrfs_item_size(left, item);
|
|
|
if (this_item_size + sizeof(*item) + push_space > free_space)
|
|
|
break;
|
|
@@ -2271,10 +2350,6 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
|
|
|
break;
|
|
|
i--;
|
|
|
}
|
|
|
- if (left->map_token) {
|
|
|
- unmap_extent_buffer(left, left->map_token, KM_USER1);
|
|
|
- left->map_token = NULL;
|
|
|
- }
|
|
|
|
|
|
if (push_items == 0)
|
|
|
goto out_unlock;
|
|
@@ -2316,21 +2391,10 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
|
|
|
push_space = BTRFS_LEAF_DATA_SIZE(root);
|
|
|
for (i = 0; i < right_nritems; i++) {
|
|
|
item = btrfs_item_nr(right, i);
|
|
|
- if (!right->map_token) {
|
|
|
- map_extent_buffer(right, (unsigned long)item,
|
|
|
- sizeof(struct btrfs_item),
|
|
|
- &right->map_token, &right->kaddr,
|
|
|
- &right->map_start, &right->map_len,
|
|
|
- KM_USER1);
|
|
|
- }
|
|
|
push_space -= btrfs_item_size(right, item);
|
|
|
btrfs_set_item_offset(right, item, push_space);
|
|
|
}
|
|
|
|
|
|
- if (right->map_token) {
|
|
|
- unmap_extent_buffer(right, right->map_token, KM_USER1);
|
|
|
- right->map_token = NULL;
|
|
|
- }
|
|
|
left_nritems -= push_items;
|
|
|
btrfs_set_header_nritems(left, left_nritems);
|
|
|
|
|
@@ -2467,13 +2531,6 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
for (i = 0; i < nr; i++) {
|
|
|
item = btrfs_item_nr(right, i);
|
|
|
- if (!right->map_token) {
|
|
|
- map_extent_buffer(right, (unsigned long)item,
|
|
|
- sizeof(struct btrfs_item),
|
|
|
- &right->map_token, &right->kaddr,
|
|
|
- &right->map_start, &right->map_len,
|
|
|
- KM_USER1);
|
|
|
- }
|
|
|
|
|
|
if (!empty && push_items > 0) {
|
|
|
if (path->slots[0] < i)
|
|
@@ -2496,11 +2553,6 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
|
|
|
push_space += this_item_size + sizeof(*item);
|
|
|
}
|
|
|
|
|
|
- if (right->map_token) {
|
|
|
- unmap_extent_buffer(right, right->map_token, KM_USER1);
|
|
|
- right->map_token = NULL;
|
|
|
- }
|
|
|
-
|
|
|
if (push_items == 0) {
|
|
|
ret = 1;
|
|
|
goto out;
|
|
@@ -2530,23 +2582,12 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
|
|
|
u32 ioff;
|
|
|
|
|
|
item = btrfs_item_nr(left, i);
|
|
|
- if (!left->map_token) {
|
|
|
- map_extent_buffer(left, (unsigned long)item,
|
|
|
- sizeof(struct btrfs_item),
|
|
|
- &left->map_token, &left->kaddr,
|
|
|
- &left->map_start, &left->map_len,
|
|
|
- KM_USER1);
|
|
|
- }
|
|
|
|
|
|
ioff = btrfs_item_offset(left, item);
|
|
|
btrfs_set_item_offset(left, item,
|
|
|
ioff - (BTRFS_LEAF_DATA_SIZE(root) - old_left_item_size));
|
|
|
}
|
|
|
btrfs_set_header_nritems(left, old_left_nritems + push_items);
|
|
|
- if (left->map_token) {
|
|
|
- unmap_extent_buffer(left, left->map_token, KM_USER1);
|
|
|
- left->map_token = NULL;
|
|
|
- }
|
|
|
|
|
|
/* fixup right node */
|
|
|
if (push_items > right_nritems) {
|
|
@@ -2574,21 +2615,9 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
|
|
|
for (i = 0; i < right_nritems; i++) {
|
|
|
item = btrfs_item_nr(right, i);
|
|
|
|
|
|
- if (!right->map_token) {
|
|
|
- map_extent_buffer(right, (unsigned long)item,
|
|
|
- sizeof(struct btrfs_item),
|
|
|
- &right->map_token, &right->kaddr,
|
|
|
- &right->map_start, &right->map_len,
|
|
|
- KM_USER1);
|
|
|
- }
|
|
|
-
|
|
|
push_space = push_space - btrfs_item_size(right, item);
|
|
|
btrfs_set_item_offset(right, item, push_space);
|
|
|
}
|
|
|
- if (right->map_token) {
|
|
|
- unmap_extent_buffer(right, right->map_token, KM_USER1);
|
|
|
- right->map_token = NULL;
|
|
|
- }
|
|
|
|
|
|
btrfs_mark_buffer_dirty(left);
|
|
|
if (right_nritems)
|
|
@@ -2729,23 +2758,10 @@ static noinline int copy_for_split(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_item *item = btrfs_item_nr(right, i);
|
|
|
u32 ioff;
|
|
|
|
|
|
- if (!right->map_token) {
|
|
|
- map_extent_buffer(right, (unsigned long)item,
|
|
|
- sizeof(struct btrfs_item),
|
|
|
- &right->map_token, &right->kaddr,
|
|
|
- &right->map_start, &right->map_len,
|
|
|
- KM_USER1);
|
|
|
- }
|
|
|
-
|
|
|
ioff = btrfs_item_offset(right, item);
|
|
|
btrfs_set_item_offset(right, item, ioff + rt_data_off);
|
|
|
}
|
|
|
|
|
|
- if (right->map_token) {
|
|
|
- unmap_extent_buffer(right, right->map_token, KM_USER1);
|
|
|
- right->map_token = NULL;
|
|
|
- }
|
|
|
-
|
|
|
btrfs_set_header_nritems(l, mid);
|
|
|
ret = 0;
|
|
|
btrfs_item_key(right, &disk_key, 0);
|
|
@@ -3264,23 +3280,10 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans,
|
|
|
u32 ioff;
|
|
|
item = btrfs_item_nr(leaf, i);
|
|
|
|
|
|
- if (!leaf->map_token) {
|
|
|
- map_extent_buffer(leaf, (unsigned long)item,
|
|
|
- sizeof(struct btrfs_item),
|
|
|
- &leaf->map_token, &leaf->kaddr,
|
|
|
- &leaf->map_start, &leaf->map_len,
|
|
|
- KM_USER1);
|
|
|
- }
|
|
|
-
|
|
|
ioff = btrfs_item_offset(leaf, item);
|
|
|
btrfs_set_item_offset(leaf, item, ioff + size_diff);
|
|
|
}
|
|
|
|
|
|
- if (leaf->map_token) {
|
|
|
- unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
|
|
|
- leaf->map_token = NULL;
|
|
|
- }
|
|
|
-
|
|
|
/* shift the data */
|
|
|
if (from_end) {
|
|
|
memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +
|
|
@@ -3377,22 +3380,10 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans,
|
|
|
u32 ioff;
|
|
|
item = btrfs_item_nr(leaf, i);
|
|
|
|
|
|
- if (!leaf->map_token) {
|
|
|
- map_extent_buffer(leaf, (unsigned long)item,
|
|
|
- sizeof(struct btrfs_item),
|
|
|
- &leaf->map_token, &leaf->kaddr,
|
|
|
- &leaf->map_start, &leaf->map_len,
|
|
|
- KM_USER1);
|
|
|
- }
|
|
|
ioff = btrfs_item_offset(leaf, item);
|
|
|
btrfs_set_item_offset(leaf, item, ioff - data_size);
|
|
|
}
|
|
|
|
|
|
- if (leaf->map_token) {
|
|
|
- unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
|
|
|
- leaf->map_token = NULL;
|
|
|
- }
|
|
|
-
|
|
|
/* shift the data */
|
|
|
memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +
|
|
|
data_end - data_size, btrfs_leaf_data(leaf) +
|
|
@@ -3494,27 +3485,13 @@ int btrfs_insert_some_items(struct btrfs_trans_handle *trans,
|
|
|
* item0..itemN ... dataN.offset..dataN.size .. data0.size
|
|
|
*/
|
|
|
/* first correct the data pointers */
|
|
|
- WARN_ON(leaf->map_token);
|
|
|
for (i = slot; i < nritems; i++) {
|
|
|
u32 ioff;
|
|
|
|
|
|
item = btrfs_item_nr(leaf, i);
|
|
|
- if (!leaf->map_token) {
|
|
|
- map_extent_buffer(leaf, (unsigned long)item,
|
|
|
- sizeof(struct btrfs_item),
|
|
|
- &leaf->map_token, &leaf->kaddr,
|
|
|
- &leaf->map_start, &leaf->map_len,
|
|
|
- KM_USER1);
|
|
|
- }
|
|
|
-
|
|
|
ioff = btrfs_item_offset(leaf, item);
|
|
|
btrfs_set_item_offset(leaf, item, ioff - total_data);
|
|
|
}
|
|
|
- if (leaf->map_token) {
|
|
|
- unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
|
|
|
- leaf->map_token = NULL;
|
|
|
- }
|
|
|
-
|
|
|
/* shift the items */
|
|
|
memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr),
|
|
|
btrfs_item_nr_offset(slot),
|
|
@@ -3608,27 +3585,13 @@ int setup_items_for_insert(struct btrfs_trans_handle *trans,
|
|
|
* item0..itemN ... dataN.offset..dataN.size .. data0.size
|
|
|
*/
|
|
|
/* first correct the data pointers */
|
|
|
- WARN_ON(leaf->map_token);
|
|
|
for (i = slot; i < nritems; i++) {
|
|
|
u32 ioff;
|
|
|
|
|
|
item = btrfs_item_nr(leaf, i);
|
|
|
- if (!leaf->map_token) {
|
|
|
- map_extent_buffer(leaf, (unsigned long)item,
|
|
|
- sizeof(struct btrfs_item),
|
|
|
- &leaf->map_token, &leaf->kaddr,
|
|
|
- &leaf->map_start, &leaf->map_len,
|
|
|
- KM_USER1);
|
|
|
- }
|
|
|
-
|
|
|
ioff = btrfs_item_offset(leaf, item);
|
|
|
btrfs_set_item_offset(leaf, item, ioff - total_data);
|
|
|
}
|
|
|
- if (leaf->map_token) {
|
|
|
- unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
|
|
|
- leaf->map_token = NULL;
|
|
|
- }
|
|
|
-
|
|
|
/* shift the items */
|
|
|
memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr),
|
|
|
btrfs_item_nr_offset(slot),
|
|
@@ -3840,22 +3803,10 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|
|
u32 ioff;
|
|
|
|
|
|
item = btrfs_item_nr(leaf, i);
|
|
|
- if (!leaf->map_token) {
|
|
|
- map_extent_buffer(leaf, (unsigned long)item,
|
|
|
- sizeof(struct btrfs_item),
|
|
|
- &leaf->map_token, &leaf->kaddr,
|
|
|
- &leaf->map_start, &leaf->map_len,
|
|
|
- KM_USER1);
|
|
|
- }
|
|
|
ioff = btrfs_item_offset(leaf, item);
|
|
|
btrfs_set_item_offset(leaf, item, ioff + dsize);
|
|
|
}
|
|
|
|
|
|
- if (leaf->map_token) {
|
|
|
- unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
|
|
|
- leaf->map_token = NULL;
|
|
|
- }
|
|
|
-
|
|
|
memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot),
|
|
|
btrfs_item_nr_offset(slot + nr),
|
|
|
sizeof(struct btrfs_item) *
|
|
@@ -4004,11 +3955,11 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
|
|
|
|
|
|
WARN_ON(!path->keep_locks);
|
|
|
again:
|
|
|
- cur = btrfs_lock_root_node(root);
|
|
|
+ cur = btrfs_read_lock_root_node(root);
|
|
|
level = btrfs_header_level(cur);
|
|
|
WARN_ON(path->nodes[level]);
|
|
|
path->nodes[level] = cur;
|
|
|
- path->locks[level] = 1;
|
|
|
+ path->locks[level] = BTRFS_READ_LOCK;
|
|
|
|
|
|
if (btrfs_header_generation(cur) < min_trans) {
|
|
|
ret = 1;
|
|
@@ -4098,12 +4049,12 @@ find_next_key:
|
|
|
cur = read_node_slot(root, cur, slot);
|
|
|
BUG_ON(!cur);
|
|
|
|
|
|
- btrfs_tree_lock(cur);
|
|
|
+ btrfs_tree_read_lock(cur);
|
|
|
|
|
|
- path->locks[level - 1] = 1;
|
|
|
+ path->locks[level - 1] = BTRFS_READ_LOCK;
|
|
|
path->nodes[level - 1] = cur;
|
|
|
unlock_up(path, level, 1);
|
|
|
- btrfs_clear_path_blocking(path, NULL);
|
|
|
+ btrfs_clear_path_blocking(path, NULL, 0);
|
|
|
}
|
|
|
out:
|
|
|
if (ret == 0)
|
|
@@ -4218,30 +4169,21 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
|
|
|
u32 nritems;
|
|
|
int ret;
|
|
|
int old_spinning = path->leave_spinning;
|
|
|
- int force_blocking = 0;
|
|
|
+ int next_rw_lock = 0;
|
|
|
|
|
|
nritems = btrfs_header_nritems(path->nodes[0]);
|
|
|
if (nritems == 0)
|
|
|
return 1;
|
|
|
|
|
|
- /*
|
|
|
- * we take the blocks in an order that upsets lockdep. Using
|
|
|
- * blocking mode is the only way around it.
|
|
|
- */
|
|
|
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
|
- force_blocking = 1;
|
|
|
-#endif
|
|
|
-
|
|
|
btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);
|
|
|
again:
|
|
|
level = 1;
|
|
|
next = NULL;
|
|
|
+ next_rw_lock = 0;
|
|
|
btrfs_release_path(path);
|
|
|
|
|
|
path->keep_locks = 1;
|
|
|
-
|
|
|
- if (!force_blocking)
|
|
|
- path->leave_spinning = 1;
|
|
|
+ path->leave_spinning = 1;
|
|
|
|
|
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
|
|
path->keep_locks = 0;
|
|
@@ -4281,11 +4223,12 @@ again:
|
|
|
}
|
|
|
|
|
|
if (next) {
|
|
|
- btrfs_tree_unlock(next);
|
|
|
+ btrfs_tree_unlock_rw(next, next_rw_lock);
|
|
|
free_extent_buffer(next);
|
|
|
}
|
|
|
|
|
|
next = c;
|
|
|
+ next_rw_lock = path->locks[level];
|
|
|
ret = read_block_for_search(NULL, root, path, &next, level,
|
|
|
slot, &key);
|
|
|
if (ret == -EAGAIN)
|
|
@@ -4297,15 +4240,14 @@ again:
|
|
|
}
|
|
|
|
|
|
if (!path->skip_locking) {
|
|
|
- ret = btrfs_try_spin_lock(next);
|
|
|
+ ret = btrfs_try_tree_read_lock(next);
|
|
|
if (!ret) {
|
|
|
btrfs_set_path_blocking(path);
|
|
|
- btrfs_tree_lock(next);
|
|
|
- if (!force_blocking)
|
|
|
- btrfs_clear_path_blocking(path, next);
|
|
|
+ btrfs_tree_read_lock(next);
|
|
|
+ btrfs_clear_path_blocking(path, next,
|
|
|
+ BTRFS_READ_LOCK);
|
|
|
}
|
|
|
- if (force_blocking)
|
|
|
- btrfs_set_lock_blocking(next);
|
|
|
+ next_rw_lock = BTRFS_READ_LOCK;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
@@ -4314,14 +4256,13 @@ again:
|
|
|
level--;
|
|
|
c = path->nodes[level];
|
|
|
if (path->locks[level])
|
|
|
- btrfs_tree_unlock(c);
|
|
|
+ btrfs_tree_unlock_rw(c, path->locks[level]);
|
|
|
|
|
|
free_extent_buffer(c);
|
|
|
path->nodes[level] = next;
|
|
|
path->slots[level] = 0;
|
|
|
if (!path->skip_locking)
|
|
|
- path->locks[level] = 1;
|
|
|
-
|
|
|
+ path->locks[level] = next_rw_lock;
|
|
|
if (!level)
|
|
|
break;
|
|
|
|
|
@@ -4336,16 +4277,14 @@ again:
|
|
|
}
|
|
|
|
|
|
if (!path->skip_locking) {
|
|
|
- btrfs_assert_tree_locked(path->nodes[level]);
|
|
|
- ret = btrfs_try_spin_lock(next);
|
|
|
+ ret = btrfs_try_tree_read_lock(next);
|
|
|
if (!ret) {
|
|
|
btrfs_set_path_blocking(path);
|
|
|
- btrfs_tree_lock(next);
|
|
|
- if (!force_blocking)
|
|
|
- btrfs_clear_path_blocking(path, next);
|
|
|
+ btrfs_tree_read_lock(next);
|
|
|
+ btrfs_clear_path_blocking(path, next,
|
|
|
+ BTRFS_READ_LOCK);
|
|
|
}
|
|
|
- if (force_blocking)
|
|
|
- btrfs_set_lock_blocking(next);
|
|
|
+ next_rw_lock = BTRFS_READ_LOCK;
|
|
|
}
|
|
|
}
|
|
|
ret = 0;
|