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

Commit 28687b93 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs fixes from Chris Mason:
 "We've queued up a few different fixes in here.  These range from
  enospc corners to fsync and quota fixes, and a few targeted at error
  handling for corrupt metadata/fuzzing"

* 'for-linus-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: fix lockdep warning on deadlock against an inode's log mutex
  Btrfs: detect corruption when non-root leaf has zero item
  Btrfs: check btree node's nritems
  btrfs: don't create or leak aliased root while cleaning up orphans
  Btrfs: fix em leak in find_first_block_group
  btrfs: do not background blkdev_put()
  Btrfs: clarify do_chunk_alloc()'s return value
  btrfs: fix fsfreeze hang caused by delayed iputs deal
  btrfs: update btrfs_space_info's bytes_may_use timely
  btrfs: divide btrfs_update_reserved_bytes() into two functions
  btrfs: use correct offset for reloc_inode in prealloc_file_extent_cluster()
  btrfs: qgroup: Fix qgroup incorrectness caused by log replay
  btrfs: relocation: Fix leaking qgroups numbers on data extents
  btrfs: qgroup: Refactor btrfs_qgroup_insert_dirty_extent()
  btrfs: waiting on qgroup rescan should not always be interruptible
  btrfs: properly track when rescan worker is running
  btrfs: flush_space: treat return value of do_chunk_alloc properly
  Btrfs: add ASSERT for block group's memory leak
  btrfs: backref: Fix soft lockup in __merge_refs function
  Btrfs: fix memory leak of reloc_root
parents 370f6017 28a23593
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -589,6 +589,7 @@ static void __merge_refs(struct list_head *head, int mode)

			list_del(&ref2->list);
			kmem_cache_free(btrfs_prelim_ref_cache, ref2);
			cond_resched();
		}

	}
+4 −1
Original line number Diff line number Diff line
@@ -1028,6 +1028,7 @@ struct btrfs_fs_info {
	struct btrfs_workqueue *qgroup_rescan_workers;
	struct completion qgroup_rescan_completion;
	struct btrfs_work qgroup_rescan_work;
	bool qgroup_rescan_running;	/* protected by qgroup_rescan_lock */

	/* filesystem state */
	unsigned long fs_state;
@@ -1079,6 +1080,8 @@ struct btrfs_fs_info {
	struct list_head pinned_chunks;

	int creating_free_space_tree;
	/* Used to record internally whether fs has been frozen */
	int fs_frozen;
};

struct btrfs_subvolume_writers {
@@ -2578,7 +2581,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
				   struct btrfs_root *root,
				   u64 root_objectid, u64 owner, u64 offset,
				   struct btrfs_key *ins);
int btrfs_reserve_extent(struct btrfs_root *root, u64 num_bytes,
int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, u64 num_bytes,
			 u64 min_alloc_size, u64 empty_size, u64 hint_byte,
			 struct btrfs_key *ins, int is_data, int delalloc);
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+2 −5
Original line number Diff line number Diff line
@@ -541,7 +541,6 @@ add_delayed_ref_head(struct btrfs_fs_info *fs_info,
	struct btrfs_delayed_ref_head *existing;
	struct btrfs_delayed_ref_head *head_ref = NULL;
	struct btrfs_delayed_ref_root *delayed_refs;
	struct btrfs_qgroup_extent_record *qexisting;
	int count_mod = 1;
	int must_insert_reserved = 0;

@@ -606,10 +605,8 @@ add_delayed_ref_head(struct btrfs_fs_info *fs_info,
		qrecord->num_bytes = num_bytes;
		qrecord->old_roots = NULL;

		qexisting = btrfs_qgroup_insert_dirty_extent(fs_info,
							     delayed_refs,
							     qrecord);
		if (qexisting)
		if(btrfs_qgroup_insert_dirty_extent_nolock(fs_info,
					delayed_refs, qrecord))
			kfree(qrecord);
	}

+51 −5
Original line number Diff line number Diff line
@@ -559,8 +559,29 @@ static noinline int check_leaf(struct btrfs_root *root,
	u32 nritems = btrfs_header_nritems(leaf);
	int slot;

	if (nritems == 0)
	if (nritems == 0) {
		struct btrfs_root *check_root;

		key.objectid = btrfs_header_owner(leaf);
		key.type = BTRFS_ROOT_ITEM_KEY;
		key.offset = (u64)-1;

		check_root = btrfs_get_fs_root(root->fs_info, &key, false);
		/*
		 * The only reason we also check NULL here is that during
		 * open_ctree() some roots has not yet been set up.
		 */
		if (!IS_ERR_OR_NULL(check_root)) {
			/* if leaf is the root, then it's fine */
			if (leaf->start !=
			    btrfs_root_bytenr(&check_root->root_item)) {
				CORRUPT("non-root leaf's nritems is 0",
					leaf, root, 0);
				return -EIO;
			}
		}
		return 0;
	}

	/* Check the 0 item */
	if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) !=
@@ -612,6 +633,19 @@ static noinline int check_leaf(struct btrfs_root *root,
	return 0;
}

static int check_node(struct btrfs_root *root, struct extent_buffer *node)
{
	unsigned long nr = btrfs_header_nritems(node);

	if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) {
		btrfs_crit(root->fs_info,
			   "corrupt node: block %llu root %llu nritems %lu",
			   node->start, root->objectid, nr);
		return -EIO;
	}
	return 0;
}

static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
				      u64 phy_offset, struct page *page,
				      u64 start, u64 end, int mirror)
@@ -682,6 +716,9 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
		ret = -EIO;
	}

	if (found_level > 0 && check_node(root, eb))
		ret = -EIO;

	if (!ret)
		set_extent_buffer_uptodate(eb);
err:
@@ -1618,7 +1655,7 @@ int btrfs_init_fs_root(struct btrfs_root *root)
	return ret;
}

static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
					u64 root_id)
{
	struct btrfs_root *root;
@@ -2298,6 +2335,7 @@ static void btrfs_init_qgroup(struct btrfs_fs_info *fs_info)
	fs_info->quota_enabled = 0;
	fs_info->pending_quota_state = 0;
	fs_info->qgroup_ulist = NULL;
	fs_info->qgroup_rescan_running = false;
	mutex_init(&fs_info->qgroup_rescan_lock);
}

@@ -2624,6 +2662,7 @@ int open_ctree(struct super_block *sb,
	atomic_set(&fs_info->qgroup_op_seq, 0);
	atomic_set(&fs_info->reada_works_cnt, 0);
	atomic64_set(&fs_info->tree_mod_seq, 0);
	fs_info->fs_frozen = 0;
	fs_info->sb = sb;
	fs_info->max_inline = BTRFS_DEFAULT_MAX_INLINE;
	fs_info->metadata_ratio = 0;
@@ -3739,8 +3778,15 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
	if (btrfs_root_refs(&root->root_item) == 0)
		synchronize_srcu(&fs_info->subvol_srcu);

	if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
	if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) {
		btrfs_free_log(NULL, root);
		if (root->reloc_root) {
			free_extent_buffer(root->reloc_root->node);
			free_extent_buffer(root->reloc_root->commit_root);
			btrfs_put_fs_root(root->reloc_root);
			root->reloc_root = NULL;
		}
	}

	if (root->free_ino_pinned)
		__btrfs_remove_free_space_cache(root->free_ino_pinned);
@@ -3851,7 +3897,7 @@ void close_ctree(struct btrfs_root *root)
	smp_mb();

	/* wait for the qgroup rescan worker to stop */
	btrfs_qgroup_wait_for_completion(fs_info);
	btrfs_qgroup_wait_for_completion(fs_info, false);

	/* wait for the uuid_scan task to finish */
	down(&fs_info->uuid_tree_rescan_sem);
+2 −0
Original line number Diff line number Diff line
@@ -68,6 +68,8 @@ struct extent_buffer *btrfs_find_tree_block(struct btrfs_fs_info *fs_info,
struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root,
				      struct btrfs_key *location);
int btrfs_init_fs_root(struct btrfs_root *root);
struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
					u64 root_id);
int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
			 struct btrfs_root *root);
void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info);
Loading