Skip to content

Commit

Permalink
Merge branch 'for-linus-4.8' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/mason/linux-btrfs

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
  • Loading branch information
Linus Torvalds committed Aug 27, 2016
2 parents 370f601 + 28a2359 commit 28687b9
Show file tree
Hide file tree
Showing 20 changed files with 473 additions and 181 deletions.
1 change: 1 addition & 0 deletions fs/btrfs/backref.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

}
Expand Down
5 changes: 4 additions & 1 deletion fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
7 changes: 2 additions & 5 deletions fs/btrfs/delayed-ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}

Expand Down
56 changes: 51 additions & 5 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) !=
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -1618,8 +1655,8 @@ 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,
u64 root_id)
struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
u64 root_id)
{
struct btrfs_root *root;

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions fs/btrfs/disk-io.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 28687b9

Please sign in to comment.