Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f48d4277 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs fixes from Chris Mason:
 "This has our series of fixes for the next rc.  The biggest batch is
  from Jan Schmidt, fixing up some problems in our subvolume quota code
  and fixing btrfs send/receive to work with the new extended inode
  refs."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: do not bug when we fail to commit the transaction
  Btrfs: fix memory leak when cloning root's node
  Btrfs: Use btrfs_update_inode_fallback when creating a snapshot
  Btrfs: Send: preserve ownership (uid and gid) also for symlinks.
  Btrfs: fix deadlock caused by the nested chunk allocation
  btrfs: Return EINVAL when length to trim is less than FSB
  Btrfs: fix memory leak in btrfs_quota_enable()
  Btrfs: send correct rdev and mode in btrfs-send
  Btrfs: extended inode refs support for send mechanism
  Btrfs: Fix wrong error handling code
  Fix a sign bug causing invalid memory access in the ino_paths ioctl.
  Btrfs: comment for loop in tree_mod_log_insert_move
  Btrfs: fix extent buffer reference for tree mod log roots
  Btrfs: determine level of old roots
  Btrfs: tree mod log's old roots could still be part of the tree
  Btrfs: fix a tree mod logging issue for root replacement operations
  Btrfs: don't put removals from push_node_left into tree mod log twice
parents b394209c c37b2b62
Loading
Loading
Loading
Loading
+12 −16
Original line number Diff line number Diff line
@@ -283,9 +283,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
		goto out;
	}

	rcu_read_lock();
	root_level = btrfs_header_level(root->node);
	rcu_read_unlock();
	root_level = btrfs_old_root_level(root, time_seq);

	if (root_level + 1 == level)
		goto out;
@@ -1177,8 +1175,7 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
	return ret;
}

static char *ref_to_path(struct btrfs_root *fs_root,
			 struct btrfs_path *path,
char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
			u32 name_len, unsigned long name_off,
			struct extent_buffer *eb_in, u64 parent,
			char *dest, u32 size)
@@ -1186,7 +1183,7 @@ static char *ref_to_path(struct btrfs_root *fs_root,
	int slot;
	u64 next_inum;
	int ret;
	s64 bytes_left = size - 1;
	s64 bytes_left = ((s64)size) - 1;
	struct extent_buffer *eb = eb_in;
	struct btrfs_key found_key;
	int leave_spinning = path->leave_spinning;
@@ -1266,7 +1263,7 @@ char *btrfs_iref_to_path(struct btrfs_root *fs_root,
			 struct extent_buffer *eb_in, u64 parent,
			 char *dest, u32 size)
{
	return ref_to_path(fs_root, path,
	return btrfs_ref_to_path(fs_root, path,
				 btrfs_inode_ref_name_len(eb_in, iref),
				 (unsigned long)(iref + 1),
				 eb_in, parent, dest, size);
@@ -1715,9 +1712,8 @@ static int inode_to_path(u64 inum, u32 name_len, unsigned long name_off,
					ipath->fspath->bytes_left - s_ptr : 0;

	fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr;
	fspath = ref_to_path(ipath->fs_root, ipath->btrfs_path, name_len,
			     name_off, eb, inum, fspath_min,
			     bytes_left);
	fspath = btrfs_ref_to_path(ipath->fs_root, ipath->btrfs_path, name_len,
				   name_off, eb, inum, fspath_min, bytes_left);
	if (IS_ERR(fspath))
		return PTR_ERR(fspath);

+4 −0
Original line number Diff line number Diff line
@@ -62,6 +62,10 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
			 struct btrfs_inode_ref *iref, struct extent_buffer *eb,
			 u64 parent, char *dest, u32 size);
char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
			u32 name_len, unsigned long name_off,
			struct extent_buffer *eb_in, u64 parent,
			char *dest, u32 size);

struct btrfs_data_container *init_data_container(u32 total_bytes);
struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
+55 −15
Original line number Diff line number Diff line
@@ -596,6 +596,11 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
	if (tree_mod_dont_log(fs_info, eb))
		return 0;

	/*
	 * When we override something during the move, we log these removals.
	 * This can only happen when we move towards the beginning of the
	 * buffer, i.e. dst_slot < src_slot.
	 */
	for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) {
		ret = tree_mod_log_insert_key_locked(fs_info, eb, i + dst_slot,
					      MOD_LOG_KEY_REMOVE_WHILE_MOVING);
@@ -647,8 +652,6 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
	if (tree_mod_dont_log(fs_info, NULL))
		return 0;

	__tree_mod_log_free_eb(fs_info, old_root);

	ret = tree_mod_alloc(fs_info, flags, &tm);
	if (ret < 0)
		goto out;
@@ -926,11 +929,6 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
			ret = btrfs_dec_ref(trans, root, buf, 1, 1);
			BUG_ON(ret); /* -ENOMEM */
		}
		/*
		 * don't log freeing in case we're freeing the root node, this
		 * is done by tree_mod_log_set_root_pointer later
		 */
		if (buf != root->node && btrfs_header_level(buf) != 0)
		tree_mod_log_free_eb(root->fs_info, buf);
		clean_tree_block(trans, root, buf);
		*last_ref = 1;
@@ -1225,6 +1223,8 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
	free_extent_buffer(eb);

	__tree_mod_log_rewind(eb_rewin, time_seq, tm);
	WARN_ON(btrfs_header_nritems(eb_rewin) >
		BTRFS_NODEPTRS_PER_BLOCK(fs_info->fs_root));

	return eb_rewin;
}
@@ -1241,9 +1241,11 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
{
	struct tree_mod_elem *tm;
	struct extent_buffer *eb;
	struct extent_buffer *old;
	struct tree_mod_root *old_root = NULL;
	u64 old_generation = 0;
	u64 logical;
	u32 blocksize;

	eb = btrfs_read_lock_root_node(root);
	tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq);
@@ -1259,14 +1261,32 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
	}

	tm = tree_mod_log_search(root->fs_info, logical, time_seq);
	if (old_root)
	if (old_root && tm && tm->op != MOD_LOG_KEY_REMOVE_WHILE_FREEING) {
		btrfs_tree_read_unlock(root->node);
		free_extent_buffer(root->node);
		blocksize = btrfs_level_size(root, old_root->level);
		old = read_tree_block(root, logical, blocksize, 0);
		if (!old) {
			pr_warn("btrfs: failed to read tree block %llu from get_old_root\n",
				logical);
			WARN_ON(1);
		} else {
			eb = btrfs_clone_extent_buffer(old);
			free_extent_buffer(old);
		}
	} else if (old_root) {
		btrfs_tree_read_unlock(root->node);
		free_extent_buffer(root->node);
		eb = alloc_dummy_extent_buffer(logical, root->nodesize);
	else
	} else {
		eb = btrfs_clone_extent_buffer(root->node);
		btrfs_tree_read_unlock(root->node);
		free_extent_buffer(root->node);
	}

	if (!eb)
		return NULL;
	extent_buffer_get(eb);
	btrfs_tree_read_lock(eb);
	if (old_root) {
		btrfs_set_header_bytenr(eb, eb->start);
@@ -1279,11 +1299,28 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
		__tree_mod_log_rewind(eb, time_seq, tm);
	else
		WARN_ON(btrfs_header_level(eb) != 0);
	extent_buffer_get(eb);
	WARN_ON(btrfs_header_nritems(eb) > BTRFS_NODEPTRS_PER_BLOCK(root));

	return eb;
}

int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq)
{
	struct tree_mod_elem *tm;
	int level;

	tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq);
	if (tm && tm->op == MOD_LOG_ROOT_REPLACE) {
		level = tm->old_root.level;
	} else {
		rcu_read_lock();
		level = btrfs_header_level(root->node);
		rcu_read_unlock();
	}

	return level;
}

static inline int should_cow_block(struct btrfs_trans_handle *trans,
				   struct btrfs_root *root,
				   struct extent_buffer *buf)
@@ -1725,6 +1762,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
			goto enospc;
		}

		tree_mod_log_free_eb(root->fs_info, root->node);
		tree_mod_log_set_root_pointer(root, child);
		rcu_assign_pointer(root->node, child);

@@ -2970,8 +3008,10 @@ static int push_node_left(struct btrfs_trans_handle *trans,
			   push_items * sizeof(struct btrfs_key_ptr));

	if (push_items < src_nritems) {
		tree_mod_log_eb_move(root->fs_info, src, 0, push_items,
				     src_nritems - push_items);
		/*
		 * don't call tree_mod_log_eb_move here, key removal was already
		 * fully logged by tree_mod_log_eb_copy above.
		 */
		memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0),
				      btrfs_node_key_ptr_offset(push_items),
				      (src_nritems - push_items) *
+3 −0
Original line number Diff line number Diff line
@@ -3120,6 +3120,7 @@ static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info)
{
	return atomic_inc_return(&fs_info->tree_mod_seq);
}
int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq);

/* root-item.c */
int btrfs_find_root_ref(struct btrfs_root *tree_root,
@@ -3338,6 +3339,8 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
int btrfs_update_inode(struct btrfs_trans_handle *trans,
			      struct btrfs_root *root,
			      struct inode *inode);
int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
				struct btrfs_root *root, struct inode *inode);
int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode);
int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
int btrfs_orphan_cleanup(struct btrfs_root *root);
+2 −2
Original line number Diff line number Diff line
@@ -4110,8 +4110,8 @@ struct extent_buffer *alloc_dummy_extent_buffer(u64 start, unsigned long len)

	return eb;
err:
	for (i--; i >= 0; i--)
		__free_page(eb->pages[i]);
	for (; i > 0; i--)
		__free_page(eb->pages[i - 1]);
	__free_extent_buffer(eb);
	return NULL;
}
Loading