Commit 1dc3731d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs fixes from David Sterba:

 - fix backward leaf iteration which could possibly return the same key

 - fix assertion when device add and balance race for exclusive
   operation

 - fix regression when freeing device, state tree would leak after
   device replace

 - fix attempt to clear space cache v1 when block-group-tree is enabled

 - fix potential i_size corruption when encoded write races with send v2
   and enabled no-holes (the race is hard to hit though, the window is a
   few instructions wide)

 - fix wrong bitmap API use when checking empty zones, parameters were
   swapped but not causing a bug due to other code

 - prevent potential qgroup leak if subvolume create does not commit
   transaction (which is pending in the development queue)

 - error handling and reporting:
     - abort transaction when sibling keys check fails for leaves
     - print extent buffers when sibling keys check fails

* tag 'for-6.4-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: don't free qgroup space unless specified
  btrfs: fix encoded write i_size corruption with no-holes
  btrfs: zoned: fix wrong use of bitops API in btrfs_ensure_empty_zones
  btrfs: properly reject clear_cache and v1 cache for block-group-tree
  btrfs: print extent buffers when sibling keys check fails
  btrfs: abort transaction when sibling keys check fails for leaves
  btrfs: fix leak of source device allocation state after device replace
  btrfs: fix assertion of exclop condition when starting balance
  btrfs: fix btrfs_prev_leaf() to not return the same key twice
parents ba0ad6ed d246331b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -124,7 +124,8 @@ static u64 block_rsv_release_bytes(struct btrfs_fs_info *fs_info,
	} else {
		num_bytes = 0;
	}
	if (block_rsv->qgroup_rsv_reserved >= block_rsv->qgroup_rsv_size) {
	if (qgroup_to_release_ret &&
	    block_rsv->qgroup_rsv_reserved >= block_rsv->qgroup_rsv_size) {
		qgroup_to_release = block_rsv->qgroup_rsv_reserved -
				    block_rsv->qgroup_rsv_size;
		block_rsv->qgroup_rsv_reserved = block_rsv->qgroup_rsv_size;
+37 −1
Original line number Diff line number Diff line
@@ -2627,6 +2627,10 @@ static bool check_sibling_keys(struct extent_buffer *left,
	}

	if (btrfs_comp_cpu_keys(&left_last, &right_first) >= 0) {
		btrfs_crit(left->fs_info, "left extent buffer:");
		btrfs_print_tree(left, false);
		btrfs_crit(left->fs_info, "right extent buffer:");
		btrfs_print_tree(right, false);
		btrfs_crit(left->fs_info,
"bad key order, sibling blocks, left last (%llu %u %llu) right first (%llu %u %llu)",
			   left_last.objectid, left_last.type,
@@ -3215,6 +3219,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root

	if (check_sibling_keys(left, right)) {
		ret = -EUCLEAN;
		btrfs_abort_transaction(trans, ret);
		btrfs_tree_unlock(right);
		free_extent_buffer(right);
		return ret;
@@ -3433,6 +3438,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root

	if (check_sibling_keys(left, right)) {
		ret = -EUCLEAN;
		btrfs_abort_transaction(trans, ret);
		goto out;
	}
	return __push_leaf_left(trans, path, min_data_size, empty, left,
@@ -4478,10 +4484,12 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
{
	struct btrfs_key key;
	struct btrfs_key orig_key;
	struct btrfs_disk_key found_key;
	int ret;

	btrfs_item_key_to_cpu(path->nodes[0], &key, 0);
	orig_key = key;

	if (key.offset > 0) {
		key.offset--;
@@ -4498,8 +4506,36 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)

	btrfs_release_path(path);
	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
	if (ret < 0)
	if (ret <= 0)
		return ret;

	/*
	 * Previous key not found. Even if we were at slot 0 of the leaf we had
	 * before releasing the path and calling btrfs_search_slot(), we now may
	 * be in a slot pointing to the same original key - this can happen if
	 * after we released the path, one of more items were moved from a
	 * sibling leaf into the front of the leaf we had due to an insertion
	 * (see push_leaf_right()).
	 * If we hit this case and our slot is > 0 and just decrement the slot
	 * so that the caller does not process the same key again, which may or
	 * may not break the caller, depending on its logic.
	 */
	if (path->slots[0] < btrfs_header_nritems(path->nodes[0])) {
		btrfs_item_key(path->nodes[0], &found_key, path->slots[0]);
		ret = comp_keys(&found_key, &orig_key);
		if (ret == 0) {
			if (path->slots[0] > 0) {
				path->slots[0]--;
				return 0;
			}
			/*
			 * At slot 0, same key as before, it means orig_key is
			 * the lowest, leftmost, key in the tree. We're done.
			 */
			return 1;
		}
	}

	btrfs_item_key(path->nodes[0], &found_key, 0);
	ret = comp_keys(&found_key, &key);
	/*
+3 −2
Original line number Diff line number Diff line
@@ -52,13 +52,13 @@ void btrfs_inode_safe_disk_i_size_write(struct btrfs_inode *inode, u64 new_i_siz
	u64 start, end, i_size;
	int ret;

	spin_lock(&inode->lock);
	i_size = new_i_size ?: i_size_read(&inode->vfs_inode);
	if (btrfs_fs_incompat(fs_info, NO_HOLES)) {
		inode->disk_i_size = i_size;
		return;
		goto out_unlock;
	}

	spin_lock(&inode->lock);
	ret = find_contiguous_extent_bit(&inode->file_extent_tree, 0, &start,
					 &end, EXTENT_DIRTY);
	if (!ret && start == 0)
@@ -66,6 +66,7 @@ void btrfs_inode_safe_disk_i_size_write(struct btrfs_inode *inode, u64 new_i_siz
	else
		i_size = 0;
	inode->disk_i_size = i_size;
out_unlock:
	spin_unlock(&inode->lock);
}

+3 −1
Original line number Diff line number Diff line
@@ -454,7 +454,9 @@ void btrfs_exclop_balance(struct btrfs_fs_info *fs_info,
	case BTRFS_EXCLOP_BALANCE_PAUSED:
		spin_lock(&fs_info->super_lock);
		ASSERT(fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE ||
		       fs_info->exclusive_operation == BTRFS_EXCLOP_DEV_ADD);
		       fs_info->exclusive_operation == BTRFS_EXCLOP_DEV_ADD ||
		       fs_info->exclusive_operation == BTRFS_EXCLOP_NONE ||
		       fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE_PAUSED);
		fs_info->exclusive_operation = BTRFS_EXCLOP_BALANCE_PAUSED;
		spin_unlock(&fs_info->super_lock);
		break;
+6 −1
Original line number Diff line number Diff line
@@ -826,7 +826,12 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
	    !btrfs_test_opt(info, CLEAR_CACHE)) {
		btrfs_err(info, "cannot disable free space tree");
		ret = -EINVAL;

	}
	if (btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE) &&
	    (btrfs_test_opt(info, CLEAR_CACHE) ||
	     !btrfs_test_opt(info, FREE_SPACE_TREE))) {
		btrfs_err(info, "cannot disable free space tree with block-group-tree feature");
		ret = -EINVAL;
	}
	if (!ret)
		ret = btrfs_check_mountopts_zoned(info);
Loading