]> git.ipfire.org Git - thirdparty/linux.git/blobdiff - fs/btrfs/disk-io.c
btrfs: stop reserving excessive space for block group item updates
[thirdparty/linux.git] / fs / btrfs / disk-io.c
index 68f60d50e1fd0c2fc1a643cf9d44bdcb5ae36036..178312c2efc8b27f78c38ba5ab4605356d112e8d 100644 (file)
@@ -29,7 +29,6 @@
 #include "tree-log.h"
 #include "free-space-cache.h"
 #include "free-space-tree.h"
-#include "check-integrity.h"
 #include "rcu-string.h"
 #include "dev-replace.h"
 #include "raid56.h"
@@ -318,9 +317,10 @@ static bool check_tree_block_fsid(struct extent_buffer *eb)
                           BTRFS_FSID_SIZE);
 
        /*
-        * alloc_fs_devices() copies the fsid into metadata_uuid if the
-        * metadata_uuid is unset in the superblock, including for a seed device.
-        * So, we can use fs_devices->metadata_uuid.
+        * alloc_fsid_devices() copies the fsid into fs_devices::metadata_uuid.
+        * This is then overwritten by metadata_uuid if it is present in the
+        * device_list_add(). The same true for a seed device as well. So use of
+        * fs_devices::metadata_uuid is appropriate here.
         */
        if (memcmp(fsid, fs_info->fs_devices->metadata_uuid, BTRFS_FSID_SIZE) == 0)
                return false;
@@ -859,7 +859,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
        root->root_key.offset = 0;
 
        leaf = btrfs_alloc_tree_block(trans, root, 0, objectid, NULL, 0, 0, 0,
-                                     BTRFS_NESTING_NORMAL);
+                                     0, BTRFS_NESTING_NORMAL);
        if (IS_ERR(leaf)) {
                ret = PTR_ERR(leaf);
                leaf = NULL;
@@ -867,7 +867,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
        }
 
        root->node = leaf;
-       btrfs_mark_buffer_dirty(leaf);
+       btrfs_mark_buffer_dirty(trans, leaf);
 
        root->commit_root = btrfs_root_node(root);
        set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state);
@@ -936,13 +936,13 @@ int btrfs_alloc_log_tree_node(struct btrfs_trans_handle *trans,
         */
 
        leaf = btrfs_alloc_tree_block(trans, root, 0, BTRFS_TREE_LOG_OBJECTID,
-                       NULL, 0, 0, 0, BTRFS_NESTING_NORMAL);
+                       NULL, 0, 0, 0, 0, BTRFS_NESTING_NORMAL);
        if (IS_ERR(leaf))
                return PTR_ERR(leaf);
 
        root->node = leaf;
 
-       btrfs_mark_buffer_dirty(root->node);
+       btrfs_mark_buffer_dirty(trans, root->node);
        btrfs_tree_unlock(root->node);
 
        return 0;
@@ -1179,6 +1179,8 @@ static struct btrfs_root *btrfs_get_global_root(struct btrfs_fs_info *fs_info,
                return btrfs_grab_root(fs_info->block_group_root);
        case BTRFS_FREE_SPACE_TREE_OBJECTID:
                return btrfs_grab_root(btrfs_global_root(fs_info, &key));
+       case BTRFS_RAID_STRIPE_TREE_OBJECTID:
+               return btrfs_grab_root(fs_info->stripe_root);
        default:
                return NULL;
        }
@@ -1259,6 +1261,7 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info)
        btrfs_put_root(fs_info->fs_root);
        btrfs_put_root(fs_info->data_reloc_root);
        btrfs_put_root(fs_info->block_group_root);
+       btrfs_put_root(fs_info->stripe_root);
        btrfs_check_leaked_roots(fs_info);
        btrfs_extent_buffer_leak_debug_check(fs_info);
        kfree(fs_info->super_copy);
@@ -1402,7 +1405,8 @@ struct btrfs_root *btrfs_get_new_fs_root(struct btrfs_fs_info *fs_info,
 }
 
 /*
- * btrfs_get_fs_root_commit_root - return a root for the given objectid
+ * Return a root for the given objectid.
+ *
  * @fs_info:   the fs_info
  * @objectid:  the objectid we need to lookup
  *
@@ -1699,11 +1703,11 @@ static void backup_super_roots(struct btrfs_fs_info *info)
 }
 
 /*
- * read_backup_root - Reads a backup root based on the passed priority. Prio 0
- * is the newest, prio 1/2/3 are 2nd newest/3rd newest/4th (oldest) backup roots
+ * Reads a backup root based on the passed priority. Prio 0 is the newest, prio
+ * 1/2/3 are 2nd newest/3rd newest/4th (oldest) backup roots
  *
- * fs_info - filesystem whose backup roots need to be read
- * priority - priority of backup root required
+ * @fs_info:  filesystem whose backup roots need to be read
+ * @priority: priority of backup root required
  *
  * Returns backup root index on success and -EINVAL otherwise.
  */
@@ -1803,6 +1807,7 @@ static void free_root_pointers(struct btrfs_fs_info *info, bool free_chunk_root)
        free_root_extent_buffers(info->fs_root);
        free_root_extent_buffers(info->data_reloc_root);
        free_root_extent_buffers(info->block_group_root);
+       free_root_extent_buffers(info->stripe_root);
        if (free_chunk_root)
                free_root_extent_buffers(info->chunk_root);
 }
@@ -2262,7 +2267,6 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info)
        root = btrfs_read_tree_root(tree_root, &location);
        if (!IS_ERR(root)) {
                set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state);
-               set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
                fs_info->quota_root = root;
        }
 
@@ -2279,6 +2283,20 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info)
                fs_info->uuid_root = root;
        }
 
+       if (btrfs_fs_incompat(fs_info, RAID_STRIPE_TREE)) {
+               location.objectid = BTRFS_RAID_STRIPE_TREE_OBJECTID;
+               root = btrfs_read_tree_root(tree_root, &location);
+               if (IS_ERR(root)) {
+                       if (!btrfs_test_opt(fs_info, IGNOREBADROOTS)) {
+                               ret = PTR_ERR(root);
+                               goto out;
+                       }
+               } else {
+                       set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state);
+                       fs_info->stripe_root = root;
+               }
+       }
+
        return 0;
 out:
        btrfs_warn(fs_info, "failed to read root (objectid=%llu): %d",
@@ -2735,9 +2753,6 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
        spin_lock_init(&fs_info->ordered_root_lock);
 
        btrfs_init_scrub(fs_info);
-#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
-       fs_info->check_integrity_print_mask = 0;
-#endif
        btrfs_init_balance(fs_info);
        btrfs_init_async_reclaim_work(fs_info);
 
@@ -3157,7 +3172,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
        u32 nodesize;
        u32 stripesize;
        u64 generation;
-       u64 features;
        u16 csum_type;
        struct btrfs_super_block *disk_super;
        struct btrfs_fs_info *fs_info = btrfs_sb(sb);
@@ -3239,15 +3253,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
 
        disk_super = fs_info->super_copy;
 
-
-       features = btrfs_super_flags(disk_super);
-       if (features & BTRFS_SUPER_FLAG_CHANGING_FSID_V2) {
-               features &= ~BTRFS_SUPER_FLAG_CHANGING_FSID_V2;
-               btrfs_set_super_flags(disk_super, features);
-               btrfs_info(fs_info,
-                       "found metadata UUID change in progress flag, clearing");
-       }
-
        memcpy(fs_info->super_for_commit, fs_info->super_copy,
               sizeof(*fs_info->super_for_commit));
 
@@ -3509,18 +3514,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
                                   "auto enabling async discard");
        }
 
-#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
-       if (btrfs_test_opt(fs_info, CHECK_INTEGRITY)) {
-               ret = btrfsic_mount(fs_info, fs_devices,
-                                   btrfs_test_opt(fs_info,
-                                       CHECK_INTEGRITY_DATA) ? 1 : 0,
-                                   fs_info->check_integrity_print_mask);
-               if (ret)
-                       btrfs_warn(fs_info,
-                               "failed to initialize integrity check module: %d",
-                               ret);
-       }
-#endif
        ret = btrfs_read_qgroup_config(fs_info);
        if (ret)
                goto fail_trans_kthread;
@@ -3820,8 +3813,6 @@ static int write_dev_supers(struct btrfs_device *device,
                 */
                if (i == 0 && !btrfs_test_opt(device->fs_info, NOBARRIER))
                        bio->bi_opf |= REQ_FUA;
-
-               btrfsic_check_bio(bio);
                submit_bio(bio);
 
                if (btrfs_advance_sb_log(device, i))
@@ -3917,28 +3908,11 @@ static void write_dev_flush(struct btrfs_device *device)
 
        device->last_flush_error = BLK_STS_OK;
 
-#ifndef CONFIG_BTRFS_FS_CHECK_INTEGRITY
-       /*
-        * When a disk has write caching disabled, we skip submission of a bio
-        * with flush and sync requests before writing the superblock, since
-        * it's not needed. However when the integrity checker is enabled, this
-        * results in reports that there are metadata blocks referred by a
-        * superblock that were not properly flushed. So don't skip the bio
-        * submission only when the integrity checker is enabled for the sake
-        * of simplicity, since this is a debug tool and not meant for use in
-        * non-debug builds.
-        */
-       if (!bdev_write_cache(device->bdev))
-               return;
-#endif
-
        bio_init(bio, device->bdev, NULL, 0,
                 REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH);
        bio->bi_end_io = btrfs_end_empty_barrier;
        init_completion(&device->flush_wait);
        bio->bi_private = &device->flush_wait;
-
-       btrfsic_check_bio(bio);
        submit_bio(bio);
        set_bit(BTRFS_DEV_STATE_FLUSH_SENT, &device->dev_state);
 }
@@ -4414,16 +4388,12 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
 
        iput(fs_info->btree_inode);
 
-#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
-       if (btrfs_test_opt(fs_info, CHECK_INTEGRITY))
-               btrfsic_unmount(fs_info->fs_devices);
-#endif
-
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
        btrfs_close_devices(fs_info->fs_devices);
 }
 
-void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
+void btrfs_mark_buffer_dirty(struct btrfs_trans_handle *trans,
+                            struct extent_buffer *buf)
 {
        struct btrfs_fs_info *fs_info = buf->fs_info;
        u64 transid = btrfs_header_generation(buf);
@@ -4437,21 +4407,16 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
        if (unlikely(test_bit(EXTENT_BUFFER_UNMAPPED, &buf->bflags)))
                return;
 #endif
+       /* This is an active transaction (its state < TRANS_STATE_UNBLOCKED). */
+       ASSERT(trans->transid == fs_info->generation);
        btrfs_assert_tree_write_locked(buf);
-       if (transid != fs_info->generation)
-               WARN(1, KERN_CRIT "btrfs transid mismatch buffer %llu, found %llu running %llu\n",
-                       buf->start, transid, fs_info->generation);
-       set_extent_buffer_dirty(buf);
-#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
-       /*
-        * btrfs_check_leaf() won't check item data if we don't have WRITTEN
-        * set, so this will only validate the basic structure of the items.
-        */
-       if (btrfs_header_level(buf) == 0 && btrfs_check_leaf(buf)) {
-               btrfs_print_leaf(buf);
-               ASSERT(0);
+       if (unlikely(transid != fs_info->generation)) {
+               btrfs_abort_transaction(trans, -EUCLEAN);
+               btrfs_crit(fs_info,
+"dirty buffer transid mismatch, logical %llu found transid %llu running transid %llu",
+                          buf->start, transid, fs_info->generation);
        }
-#endif
+       set_extent_buffer_dirty(buf);
 }
 
 static void __btrfs_btree_balance_dirty(struct btrfs_fs_info *fs_info,
@@ -4611,6 +4576,7 @@ static void btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
                                list_del(&ref->add_list);
                        atomic_dec(&delayed_refs->num_entries);
                        btrfs_put_delayed_ref(ref);
+                       btrfs_delayed_refs_rsv_release(fs_info, 1, 0);
                }
                if (head->must_insert_reserved)
                        pin_bytes = true;
@@ -4808,7 +4774,7 @@ void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans,
 
                spin_unlock(&cur_trans->dirty_bgs_lock);
                btrfs_put_block_group(cache);
-               btrfs_delayed_refs_rsv_release(fs_info, 1);
+               btrfs_dec_delayed_refs_rsv_bg_updates(fs_info);
                spin_lock(&cur_trans->dirty_bgs_lock);
        }
        spin_unlock(&cur_trans->dirty_bgs_lock);