Merge tag 'for-5.4-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 30 Sep 2019 17:25:24 +0000 (10:25 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 30 Sep 2019 17:25:24 +0000 (10:25 -0700)
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

fs/btrfs/extent_io.c
fs/btrfs/qgroup.c
fs/btrfs/relocation.c
fs/btrfs/tests/btrfs-tests.c
fs/btrfs/volumes.c

index 7b32b6af322d6ca2b9a4bb8e77b1f8c7daf579ef..cceaf05aada269ef659cba385a984459f2e5f911 100644 (file)
@@ -3745,11 +3745,20 @@ err_unlock:
 static void set_btree_ioerr(struct page *page)
 {
        struct extent_buffer *eb = (struct extent_buffer *)page->private;
+       struct btrfs_fs_info *fs_info;
 
        SetPageError(page);
        if (test_and_set_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags))
                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
         * failed, increment the counter transaction->eb_write_errors.
@@ -3986,6 +3995,10 @@ retry:
                        if (!ret) {
                                free_extent_buffer(eb);
                                continue;
+                       } else if (ret < 0) {
+                               done = 1;
+                               free_extent_buffer(eb);
+                               break;
                        }
 
                        ret = write_one_eb(eb, wbc, &epd);
index 8d3bd799ac7dadb06a42dff8799c886b758f048d..c4bb69941c77c721a7b6c69bb11d83938bfb69d2 100644 (file)
@@ -3166,9 +3166,6 @@ out:
        btrfs_free_path(path);
 
        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 &&
            fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) {
                fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
@@ -3184,16 +3181,30 @@ out:
        trans = btrfs_start_transaction(fs_info->quota_root, 1);
        if (IS_ERR(trans)) {
                err = PTR_ERR(trans);
+               trans = NULL;
                btrfs_err(fs_info,
                          "fail to start transaction for status update: %d",
                          err);
-               goto done;
        }
-       ret = update_qgroup_status_item(trans);
-       if (ret < 0) {
-               err = ret;
-               btrfs_err(fs_info, "fail to update qgroup status: %d", err);
+
+       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);
+               if (ret < 0) {
+                       err = ret;
+                       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);
 
        if (btrfs_fs_closing(fs_info)) {
@@ -3204,12 +3215,6 @@ out:
        } else {
                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 @@ cleanup:
        while ((unode = ulist_next(&reserved->range_changed, &uiter)))
                clear_extent_bit(&BTRFS_I(inode)->io_tree, unode->val,
                                 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);
        return ret;
 }
@@ -3481,7 +3489,7 @@ static int qgroup_free_reserved_data(struct inode *inode,
                 * EXTENT_QGROUP_RESERVED, we won't double free.
                 * 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,
                                EXTENT_QGROUP_RESERVED, &changeset);
                if (ret < 0)
index 2f0e25afa48605f1ff0938271c18f3f49cc95ce2..00504657b60225f5c00346f16098609db679f90e 100644 (file)
@@ -1435,6 +1435,13 @@ int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,
        int clear_rsv = 0;
        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) {
                reloc_root = root->reloc_root;
                reloc_root->last_trans = trans->transid;
@@ -2187,7 +2194,6 @@ static int clean_dirty_subvols(struct reloc_control *rc)
                        /* Merged subvolume, cleanup its 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);
                        root->reloc_root = NULL;
                        if (reloc_root) {
@@ -2196,6 +2202,7 @@ static int clean_dirty_subvols(struct reloc_control *rc)
                                if (ret2 < 0 && !ret)
                                        ret = ret2;
                        }
+                       clear_bit(BTRFS_ROOT_DEAD_RELOC_TREE, &root->state);
                        btrfs_put_fs_root(root);
                } else {
                        /* Orphan reloc tree, just clean it up */
index b5e80563efaa4fd616e6a1927dd35592e1bac118..99fe9bf3fdac097f5a807ff1f48378e9720196d0 100644 (file)
@@ -52,7 +52,13 @@ static struct file_system_type test_type = {
 
 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)
index a324480bc88b9827f13f72d94beb76a9d7b3fb61..cdd7af424033c22bbc3932d49674c2d907c4def0 100644 (file)
@@ -4063,7 +4063,13 @@ int btrfs_balance(struct btrfs_fs_info *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++)
                if (num_devices >= btrfs_raid_array[i].devs_min)
                        allowed |= btrfs_raid_array[i].bg_flag;