Commit bb48a591 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-5.4-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux

Pull btrfs fixes from David Sterba:
 "A bunch of fixes that accumulated in recent weeks, mostly material for
  stable.

  Summary:

   - fix for regression from 5.3 that prevents to use balance convert
     with single profile

   - qgroup fixes: rescan race, accounting leak with multiple writers,
     potential leak after io failure recovery

   - fix for use after free in relocation (reported by KASAN)

   - other error handling fixups"

* tag 'for-5.4-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: qgroup: Fix reserved data space leak if we have multiple reserve calls
  btrfs: qgroup: Fix the wrong target io_tree when freeing reserved data space
  btrfs: Fix a regression which we can't convert to SINGLE profile
  btrfs: relocation: fix use-after-free on dead relocation roots
  Btrfs: fix race setting up and completing qgroup rescan workers
  Btrfs: fix missing error return if writeback for extent buffer never started
  btrfs: adjust dirty_metadata_bytes after writeback failure of extent buffer
  Btrfs: fix selftests failure due to uninitialized i_mode in test inodes
parents 80b29b6b d4e20494
...@@ -3745,11 +3745,20 @@ static noinline_for_stack int lock_extent_buffer_for_io(struct extent_buffer *eb ...@@ -3745,11 +3745,20 @@ static noinline_for_stack int lock_extent_buffer_for_io(struct extent_buffer *eb
static void set_btree_ioerr(struct page *page) static void set_btree_ioerr(struct page *page)
{ {
struct extent_buffer *eb = (struct extent_buffer *)page->private; struct extent_buffer *eb = (struct extent_buffer *)page->private;
struct btrfs_fs_info *fs_info;
SetPageError(page); SetPageError(page);
if (test_and_set_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) if (test_and_set_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags))
return; return;
/*
* If we error out, we should add back the dirty_metadata_bytes
* to make it consistent.
*/
fs_info = eb->fs_info;
percpu_counter_add_batch(&fs_info->dirty_metadata_bytes,
eb->len, fs_info->dirty_metadata_batch);
/* /*
* If writeback for a btree extent that doesn't belong to a log tree * If writeback for a btree extent that doesn't belong to a log tree
* failed, increment the counter transaction->eb_write_errors. * failed, increment the counter transaction->eb_write_errors.
...@@ -3986,6 +3995,10 @@ int btree_write_cache_pages(struct address_space *mapping, ...@@ -3986,6 +3995,10 @@ int btree_write_cache_pages(struct address_space *mapping,
if (!ret) { if (!ret) {
free_extent_buffer(eb); free_extent_buffer(eb);
continue; continue;
} else if (ret < 0) {
done = 1;
free_extent_buffer(eb);
break;
} }
ret = write_one_eb(eb, wbc, &epd); ret = write_one_eb(eb, wbc, &epd);
......
...@@ -3166,9 +3166,6 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) ...@@ -3166,9 +3166,6 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
btrfs_free_path(path); btrfs_free_path(path);
mutex_lock(&fs_info->qgroup_rescan_lock); mutex_lock(&fs_info->qgroup_rescan_lock);
if (!btrfs_fs_closing(fs_info))
fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN;
if (err > 0 && if (err > 0 &&
fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) { fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) {
fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
...@@ -3184,16 +3181,30 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) ...@@ -3184,16 +3181,30 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
trans = btrfs_start_transaction(fs_info->quota_root, 1); trans = btrfs_start_transaction(fs_info->quota_root, 1);
if (IS_ERR(trans)) { if (IS_ERR(trans)) {
err = PTR_ERR(trans); err = PTR_ERR(trans);
trans = NULL;
btrfs_err(fs_info, btrfs_err(fs_info,
"fail to start transaction for status update: %d", "fail to start transaction for status update: %d",
err); err);
goto done;
} }
mutex_lock(&fs_info->qgroup_rescan_lock);
if (!btrfs_fs_closing(fs_info))
fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN;
if (trans) {
ret = update_qgroup_status_item(trans); ret = update_qgroup_status_item(trans);
if (ret < 0) { if (ret < 0) {
err = ret; err = ret;
btrfs_err(fs_info, "fail to update qgroup status: %d", err); btrfs_err(fs_info, "fail to update qgroup status: %d",
err);
} }
}
fs_info->qgroup_rescan_running = false;
complete_all(&fs_info->qgroup_rescan_completion);
mutex_unlock(&fs_info->qgroup_rescan_lock);
if (!trans)
return;
btrfs_end_transaction(trans); btrfs_end_transaction(trans);
if (btrfs_fs_closing(fs_info)) { if (btrfs_fs_closing(fs_info)) {
...@@ -3204,12 +3215,6 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) ...@@ -3204,12 +3215,6 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
} else { } else {
btrfs_err(fs_info, "qgroup scan failed with %d", err); btrfs_err(fs_info, "qgroup scan failed with %d", err);
} }
done:
mutex_lock(&fs_info->qgroup_rescan_lock);
fs_info->qgroup_rescan_running = false;
mutex_unlock(&fs_info->qgroup_rescan_lock);
complete_all(&fs_info->qgroup_rescan_completion);
} }
/* /*
...@@ -3437,6 +3442,9 @@ int btrfs_qgroup_reserve_data(struct inode *inode, ...@@ -3437,6 +3442,9 @@ int btrfs_qgroup_reserve_data(struct inode *inode,
while ((unode = ulist_next(&reserved->range_changed, &uiter))) while ((unode = ulist_next(&reserved->range_changed, &uiter)))
clear_extent_bit(&BTRFS_I(inode)->io_tree, unode->val, clear_extent_bit(&BTRFS_I(inode)->io_tree, unode->val,
unode->aux, EXTENT_QGROUP_RESERVED, 0, 0, NULL); unode->aux, EXTENT_QGROUP_RESERVED, 0, 0, NULL);
/* Also free data bytes of already reserved one */
btrfs_qgroup_free_refroot(root->fs_info, root->root_key.objectid,
orig_reserved, BTRFS_QGROUP_RSV_DATA);
extent_changeset_release(reserved); extent_changeset_release(reserved);
return ret; return ret;
} }
...@@ -3481,7 +3489,7 @@ static int qgroup_free_reserved_data(struct inode *inode, ...@@ -3481,7 +3489,7 @@ static int qgroup_free_reserved_data(struct inode *inode,
* EXTENT_QGROUP_RESERVED, we won't double free. * EXTENT_QGROUP_RESERVED, we won't double free.
* So not need to rush. * So not need to rush.
*/ */
ret = clear_record_extent_bits(&BTRFS_I(inode)->io_failure_tree, ret = clear_record_extent_bits(&BTRFS_I(inode)->io_tree,
free_start, free_start + free_len - 1, free_start, free_start + free_len - 1,
EXTENT_QGROUP_RESERVED, &changeset); EXTENT_QGROUP_RESERVED, &changeset);
if (ret < 0) if (ret < 0)
......
...@@ -1435,6 +1435,13 @@ int btrfs_init_reloc_root(struct btrfs_trans_handle *trans, ...@@ -1435,6 +1435,13 @@ int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,
int clear_rsv = 0; int clear_rsv = 0;
int ret; int ret;
/*
* The subvolume has reloc tree but the swap is finished, no need to
* create/update the dead reloc tree
*/
if (test_bit(BTRFS_ROOT_DEAD_RELOC_TREE, &root->state))
return 0;
if (root->reloc_root) { if (root->reloc_root) {
reloc_root = root->reloc_root; reloc_root = root->reloc_root;
reloc_root->last_trans = trans->transid; reloc_root->last_trans = trans->transid;
...@@ -2187,7 +2194,6 @@ static int clean_dirty_subvols(struct reloc_control *rc) ...@@ -2187,7 +2194,6 @@ static int clean_dirty_subvols(struct reloc_control *rc)
/* Merged subvolume, cleanup its reloc root */ /* Merged subvolume, cleanup its reloc root */
struct btrfs_root *reloc_root = root->reloc_root; struct btrfs_root *reloc_root = root->reloc_root;
clear_bit(BTRFS_ROOT_DEAD_RELOC_TREE, &root->state);
list_del_init(&root->reloc_dirty_list); list_del_init(&root->reloc_dirty_list);
root->reloc_root = NULL; root->reloc_root = NULL;
if (reloc_root) { if (reloc_root) {
...@@ -2196,6 +2202,7 @@ static int clean_dirty_subvols(struct reloc_control *rc) ...@@ -2196,6 +2202,7 @@ static int clean_dirty_subvols(struct reloc_control *rc)
if (ret2 < 0 && !ret) if (ret2 < 0 && !ret)
ret = ret2; ret = ret2;
} }
clear_bit(BTRFS_ROOT_DEAD_RELOC_TREE, &root->state);
btrfs_put_fs_root(root); btrfs_put_fs_root(root);
} else { } else {
/* Orphan reloc tree, just clean it up */ /* Orphan reloc tree, just clean it up */
......
...@@ -52,7 +52,13 @@ static struct file_system_type test_type = { ...@@ -52,7 +52,13 @@ static struct file_system_type test_type = {
struct inode *btrfs_new_test_inode(void) struct inode *btrfs_new_test_inode(void)
{ {
return new_inode(test_mnt->mnt_sb); struct inode *inode;
inode = new_inode(test_mnt->mnt_sb);
if (inode)
inode_init_owner(inode, NULL, S_IFREG);
return inode;
} }
static int btrfs_init_test_fs(void) static int btrfs_init_test_fs(void)
......
...@@ -4063,7 +4063,13 @@ int btrfs_balance(struct btrfs_fs_info *fs_info, ...@@ -4063,7 +4063,13 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
} }
num_devices = btrfs_num_devices(fs_info); num_devices = btrfs_num_devices(fs_info);
allowed = 0;
/*
* SINGLE profile on-disk has no profile bit, but in-memory we have a
* special bit for it, to make it easier to distinguish. Thus we need
* to set it manually, or balance would refuse the profile.
*/
allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
for (i = 0; i < ARRAY_SIZE(btrfs_raid_array); i++) for (i = 0; i < ARRAY_SIZE(btrfs_raid_array); i++)
if (num_devices >= btrfs_raid_array[i].devs_min) if (num_devices >= btrfs_raid_array[i].devs_min)
allowed |= btrfs_raid_array[i].bg_flag; allowed |= btrfs_raid_array[i].bg_flag;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment