Loading fs/btrfs/btrfs_inode.h +14 −2 Original line number Diff line number Diff line Loading @@ -34,6 +34,9 @@ struct btrfs_inode { */ struct btrfs_key location; /* Lock for counters */ spinlock_t lock; /* the extent_tree has caches of all the extent mappings to disk */ struct extent_map_tree extent_tree; Loading Loading @@ -134,8 +137,8 @@ struct btrfs_inode { * items we think we'll end up using, and reserved_extents is the number * of extent items we've reserved metadata for. */ atomic_t outstanding_extents; atomic_t reserved_extents; unsigned outstanding_extents; unsigned reserved_extents; /* * ordered_data_close is set by truncate when a file that used Loading Loading @@ -184,4 +187,13 @@ static inline void btrfs_i_size_write(struct inode *inode, u64 size) BTRFS_I(inode)->disk_i_size = size; } static inline bool btrfs_is_free_space_inode(struct btrfs_root *root, struct inode *inode) { if (root == root->fs_info->tree_root || BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID) return true; return false; } #endif fs/btrfs/ctree.c +198 −259 Original line number Diff line number Diff line Loading @@ -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; } } Loading @@ -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; Loading @@ -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 } Loading Loading @@ -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]); Loading Loading @@ -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. Loading Loading @@ -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; Loading @@ -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) Loading Loading @@ -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; } Loading Loading @@ -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; Loading @@ -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 - Loading @@ -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; } Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; } Loading @@ -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; } } /* Loading Loading @@ -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; } } Loading @@ -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; } } Loading Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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 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); Loading @@ -1644,10 +1696,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root * 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 Loading @@ -1659,6 +1707,16 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root 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); Loading @@ -1671,10 +1729,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root 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 Loading @@ -1700,7 +1755,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root } 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) { Loading @@ -1710,6 +1765,19 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root 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) { Loading @@ -1728,23 +1796,42 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root } if (!p->skip_locking) { btrfs_clear_path_blocking(p, NULL); err = btrfs_try_spin_lock(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_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) { Loading Loading @@ -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; } Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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) Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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) Loading Loading @@ -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); Loading Loading @@ -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) + Loading Loading @@ -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) + Loading Loading @@ -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), Loading Loading @@ -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), Loading Loading @@ -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) * Loading Loading @@ -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; Loading Loading @@ -4098,12 +4049,12 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_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) Loading Loading @@ -4218,29 +4169,20 @@ 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; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); Loading Loading @@ -4281,11 +4223,12 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) } 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) Loading @@ -4297,15 +4240,14 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) } 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; } Loading @@ -4314,14 +4256,13 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) 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; Loading @@ -4336,16 +4277,14 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) } 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; Loading fs/btrfs/ctree.h +8 −6 Original line number Diff line number Diff line Loading @@ -755,6 +755,8 @@ struct btrfs_space_info { chunks for this space */ unsigned int chunk_alloc:1; /* set if we are allocating a chunk */ unsigned int flush:1; /* set if we are trying to make space */ unsigned int force_alloc; /* set if we need to force a chunk alloc for this space */ Loading @@ -764,7 +766,7 @@ struct btrfs_space_info { struct list_head block_groups[BTRFS_NR_RAID_TYPES]; spinlock_t lock; struct rw_semaphore groups_sem; atomic_t caching_threads; wait_queue_head_t wait; }; struct btrfs_block_rsv { Loading Loading @@ -824,6 +826,7 @@ struct btrfs_caching_control { struct list_head list; struct mutex mutex; wait_queue_head_t wait; struct btrfs_work work; struct btrfs_block_group_cache *block_group; u64 progress; atomic_t count; Loading Loading @@ -1032,6 +1035,8 @@ struct btrfs_fs_info { struct btrfs_workers endio_write_workers; struct btrfs_workers endio_freespace_worker; struct btrfs_workers submit_workers; struct btrfs_workers caching_workers; /* * fixup workers take dirty pages that didn't properly go through * the cow mechanism and make them safe to write. It happens Loading Loading @@ -2128,7 +2133,7 @@ static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info) /* extent-tree.c */ static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root, int num_items) unsigned num_items) { return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) * 3 * num_items; Loading Loading @@ -2222,9 +2227,6 @@ void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde); void btrfs_clear_space_info_full(struct btrfs_fs_info *info); int btrfs_check_data_free_space(struct inode *inode, u64 bytes); void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes); int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans, struct btrfs_root *root, int num_items); void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, struct btrfs_root *root); int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans, Loading Loading @@ -2330,7 +2332,7 @@ struct btrfs_path *btrfs_alloc_path(void); void btrfs_free_path(struct btrfs_path *p); void btrfs_set_path_blocking(struct btrfs_path *p); void btrfs_clear_path_blocking(struct btrfs_path *p, struct extent_buffer *held); struct extent_buffer *held, int held_rw); void btrfs_unlock_up_safe(struct btrfs_path *p, int level); int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, Loading Loading
fs/btrfs/btrfs_inode.h +14 −2 Original line number Diff line number Diff line Loading @@ -34,6 +34,9 @@ struct btrfs_inode { */ struct btrfs_key location; /* Lock for counters */ spinlock_t lock; /* the extent_tree has caches of all the extent mappings to disk */ struct extent_map_tree extent_tree; Loading Loading @@ -134,8 +137,8 @@ struct btrfs_inode { * items we think we'll end up using, and reserved_extents is the number * of extent items we've reserved metadata for. */ atomic_t outstanding_extents; atomic_t reserved_extents; unsigned outstanding_extents; unsigned reserved_extents; /* * ordered_data_close is set by truncate when a file that used Loading Loading @@ -184,4 +187,13 @@ static inline void btrfs_i_size_write(struct inode *inode, u64 size) BTRFS_I(inode)->disk_i_size = size; } static inline bool btrfs_is_free_space_inode(struct btrfs_root *root, struct inode *inode) { if (root == root->fs_info->tree_root || BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID) return true; return false; } #endif
fs/btrfs/ctree.c +198 −259 Original line number Diff line number Diff line Loading @@ -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; } } Loading @@ -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; Loading @@ -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 } Loading Loading @@ -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]); Loading Loading @@ -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. Loading Loading @@ -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; Loading @@ -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) Loading Loading @@ -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; } Loading Loading @@ -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; Loading @@ -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 - Loading @@ -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; } Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; } Loading @@ -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; } } /* Loading Loading @@ -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; } } Loading @@ -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; } } Loading Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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 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); Loading @@ -1644,10 +1696,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root * 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 Loading @@ -1659,6 +1707,16 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root 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); Loading @@ -1671,10 +1729,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root 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 Loading @@ -1700,7 +1755,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root } 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) { Loading @@ -1710,6 +1765,19 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root 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) { Loading @@ -1728,23 +1796,42 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root } if (!p->skip_locking) { btrfs_clear_path_blocking(p, NULL); err = btrfs_try_spin_lock(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_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) { Loading Loading @@ -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; } Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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) Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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) Loading Loading @@ -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); Loading Loading @@ -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) + Loading Loading @@ -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) + Loading Loading @@ -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), Loading Loading @@ -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), Loading Loading @@ -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) * Loading Loading @@ -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; Loading Loading @@ -4098,12 +4049,12 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_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) Loading Loading @@ -4218,29 +4169,20 @@ 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; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); Loading Loading @@ -4281,11 +4223,12 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) } 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) Loading @@ -4297,15 +4240,14 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) } 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; } Loading @@ -4314,14 +4256,13 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) 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; Loading @@ -4336,16 +4277,14 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) } 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; Loading
fs/btrfs/ctree.h +8 −6 Original line number Diff line number Diff line Loading @@ -755,6 +755,8 @@ struct btrfs_space_info { chunks for this space */ unsigned int chunk_alloc:1; /* set if we are allocating a chunk */ unsigned int flush:1; /* set if we are trying to make space */ unsigned int force_alloc; /* set if we need to force a chunk alloc for this space */ Loading @@ -764,7 +766,7 @@ struct btrfs_space_info { struct list_head block_groups[BTRFS_NR_RAID_TYPES]; spinlock_t lock; struct rw_semaphore groups_sem; atomic_t caching_threads; wait_queue_head_t wait; }; struct btrfs_block_rsv { Loading Loading @@ -824,6 +826,7 @@ struct btrfs_caching_control { struct list_head list; struct mutex mutex; wait_queue_head_t wait; struct btrfs_work work; struct btrfs_block_group_cache *block_group; u64 progress; atomic_t count; Loading Loading @@ -1032,6 +1035,8 @@ struct btrfs_fs_info { struct btrfs_workers endio_write_workers; struct btrfs_workers endio_freespace_worker; struct btrfs_workers submit_workers; struct btrfs_workers caching_workers; /* * fixup workers take dirty pages that didn't properly go through * the cow mechanism and make them safe to write. It happens Loading Loading @@ -2128,7 +2133,7 @@ static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info) /* extent-tree.c */ static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root, int num_items) unsigned num_items) { return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) * 3 * num_items; Loading Loading @@ -2222,9 +2227,6 @@ void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde); void btrfs_clear_space_info_full(struct btrfs_fs_info *info); int btrfs_check_data_free_space(struct inode *inode, u64 bytes); void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes); int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans, struct btrfs_root *root, int num_items); void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, struct btrfs_root *root); int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans, Loading Loading @@ -2330,7 +2332,7 @@ struct btrfs_path *btrfs_alloc_path(void); void btrfs_free_path(struct btrfs_path *p); void btrfs_set_path_blocking(struct btrfs_path *p); void btrfs_clear_path_blocking(struct btrfs_path *p, struct extent_buffer *held); struct extent_buffer *held, int held_rw); void btrfs_unlock_up_safe(struct btrfs_path *p, int level); int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, Loading