btrfs: Refactor btrfs_check_super_valid
[sfrench/cifs-2.6.git] / fs / btrfs / disk-io.c
index 60caa68c3618d5a072f332be97e7db4ea7ba67b0..eff8673700362bb4a3d679184612b382fbae0328 100644 (file)
@@ -55,7 +55,6 @@
 static const struct extent_io_ops btree_extent_io_ops;
 static void end_workqueue_fn(struct btrfs_work *work);
 static void free_fs_root(struct btrfs_root *root);
-static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info);
 static void btrfs_destroy_ordered_extents(struct btrfs_root *root);
 static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
                                      struct btrfs_fs_info *fs_info);
@@ -2164,7 +2163,6 @@ static void btrfs_init_balance(struct btrfs_fs_info *fs_info)
 {
        spin_lock_init(&fs_info->balance_lock);
        mutex_init(&fs_info->balance_mutex);
-       atomic_set(&fs_info->balance_running, 0);
        atomic_set(&fs_info->balance_pause_req, 0);
        atomic_set(&fs_info->balance_cancel_req, 0);
        fs_info->balance_ctl = NULL;
@@ -2442,6 +2440,176 @@ out:
        return ret;
 }
 
+/*
+ * Real super block validation
+ * NOTE: super csum type and incompat features will not be checked here.
+ *
+ * @sb:                super block to check
+ * @mirror_num:        the super block number to check its bytenr:
+ *             0       the primary (1st) sb
+ *             1, 2    2nd and 3rd backup copy
+ *            -1       skip bytenr check
+ */
+static int validate_super(struct btrfs_fs_info *fs_info,
+                           struct btrfs_super_block *sb, int mirror_num)
+{
+       u64 nodesize = btrfs_super_nodesize(sb);
+       u64 sectorsize = btrfs_super_sectorsize(sb);
+       int ret = 0;
+
+       if (btrfs_super_magic(sb) != BTRFS_MAGIC) {
+               btrfs_err(fs_info, "no valid FS found");
+               ret = -EINVAL;
+       }
+       if (btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP) {
+               btrfs_err(fs_info, "unrecognized or unsupported super flag: %llu",
+                               btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP);
+               ret = -EINVAL;
+       }
+       if (btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL) {
+               btrfs_err(fs_info, "tree_root level too big: %d >= %d",
+                               btrfs_super_root_level(sb), BTRFS_MAX_LEVEL);
+               ret = -EINVAL;
+       }
+       if (btrfs_super_chunk_root_level(sb) >= BTRFS_MAX_LEVEL) {
+               btrfs_err(fs_info, "chunk_root level too big: %d >= %d",
+                               btrfs_super_chunk_root_level(sb), BTRFS_MAX_LEVEL);
+               ret = -EINVAL;
+       }
+       if (btrfs_super_log_root_level(sb) >= BTRFS_MAX_LEVEL) {
+               btrfs_err(fs_info, "log_root level too big: %d >= %d",
+                               btrfs_super_log_root_level(sb), BTRFS_MAX_LEVEL);
+               ret = -EINVAL;
+       }
+
+       /*
+        * Check sectorsize and nodesize first, other check will need it.
+        * Check all possible sectorsize(4K, 8K, 16K, 32K, 64K) here.
+        */
+       if (!is_power_of_2(sectorsize) || sectorsize < 4096 ||
+           sectorsize > BTRFS_MAX_METADATA_BLOCKSIZE) {
+               btrfs_err(fs_info, "invalid sectorsize %llu", sectorsize);
+               ret = -EINVAL;
+       }
+       /* Only PAGE SIZE is supported yet */
+       if (sectorsize != PAGE_SIZE) {
+               btrfs_err(fs_info,
+                       "sectorsize %llu not supported yet, only support %lu",
+                       sectorsize, PAGE_SIZE);
+               ret = -EINVAL;
+       }
+       if (!is_power_of_2(nodesize) || nodesize < sectorsize ||
+           nodesize > BTRFS_MAX_METADATA_BLOCKSIZE) {
+               btrfs_err(fs_info, "invalid nodesize %llu", nodesize);
+               ret = -EINVAL;
+       }
+       if (nodesize != le32_to_cpu(sb->__unused_leafsize)) {
+               btrfs_err(fs_info, "invalid leafsize %u, should be %llu",
+                         le32_to_cpu(sb->__unused_leafsize), nodesize);
+               ret = -EINVAL;
+       }
+
+       /* Root alignment check */
+       if (!IS_ALIGNED(btrfs_super_root(sb), sectorsize)) {
+               btrfs_warn(fs_info, "tree_root block unaligned: %llu",
+                          btrfs_super_root(sb));
+               ret = -EINVAL;
+       }
+       if (!IS_ALIGNED(btrfs_super_chunk_root(sb), sectorsize)) {
+               btrfs_warn(fs_info, "chunk_root block unaligned: %llu",
+                          btrfs_super_chunk_root(sb));
+               ret = -EINVAL;
+       }
+       if (!IS_ALIGNED(btrfs_super_log_root(sb), sectorsize)) {
+               btrfs_warn(fs_info, "log_root block unaligned: %llu",
+                          btrfs_super_log_root(sb));
+               ret = -EINVAL;
+       }
+
+       if (memcmp(fs_info->fsid, sb->dev_item.fsid, BTRFS_FSID_SIZE) != 0) {
+               btrfs_err(fs_info,
+                          "dev_item UUID does not match fsid: %pU != %pU",
+                          fs_info->fsid, sb->dev_item.fsid);
+               ret = -EINVAL;
+       }
+
+       /*
+        * Hint to catch really bogus numbers, bitflips or so, more exact checks are
+        * done later
+        */
+       if (btrfs_super_bytes_used(sb) < 6 * btrfs_super_nodesize(sb)) {
+               btrfs_err(fs_info, "bytes_used is too small %llu",
+                         btrfs_super_bytes_used(sb));
+               ret = -EINVAL;
+       }
+       if (!is_power_of_2(btrfs_super_stripesize(sb))) {
+               btrfs_err(fs_info, "invalid stripesize %u",
+                         btrfs_super_stripesize(sb));
+               ret = -EINVAL;
+       }
+       if (btrfs_super_num_devices(sb) > (1UL << 31))
+               btrfs_warn(fs_info, "suspicious number of devices: %llu",
+                          btrfs_super_num_devices(sb));
+       if (btrfs_super_num_devices(sb) == 0) {
+               btrfs_err(fs_info, "number of devices is 0");
+               ret = -EINVAL;
+       }
+
+       if (mirror_num >= 0 &&
+           btrfs_super_bytenr(sb) != btrfs_sb_offset(mirror_num)) {
+               btrfs_err(fs_info, "super offset mismatch %llu != %u",
+                         btrfs_super_bytenr(sb), BTRFS_SUPER_INFO_OFFSET);
+               ret = -EINVAL;
+       }
+
+       /*
+        * Obvious sys_chunk_array corruptions, it must hold at least one key
+        * and one chunk
+        */
+       if (btrfs_super_sys_array_size(sb) > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) {
+               btrfs_err(fs_info, "system chunk array too big %u > %u",
+                         btrfs_super_sys_array_size(sb),
+                         BTRFS_SYSTEM_CHUNK_ARRAY_SIZE);
+               ret = -EINVAL;
+       }
+       if (btrfs_super_sys_array_size(sb) < sizeof(struct btrfs_disk_key)
+                       + sizeof(struct btrfs_chunk)) {
+               btrfs_err(fs_info, "system chunk array too small %u < %zu",
+                         btrfs_super_sys_array_size(sb),
+                         sizeof(struct btrfs_disk_key)
+                         + sizeof(struct btrfs_chunk));
+               ret = -EINVAL;
+       }
+
+       /*
+        * The generation is a global counter, we'll trust it more than the others
+        * but it's still possible that it's the one that's wrong.
+        */
+       if (btrfs_super_generation(sb) < btrfs_super_chunk_root_generation(sb))
+               btrfs_warn(fs_info,
+                       "suspicious: generation < chunk_root_generation: %llu < %llu",
+                       btrfs_super_generation(sb),
+                       btrfs_super_chunk_root_generation(sb));
+       if (btrfs_super_generation(sb) < btrfs_super_cache_generation(sb)
+           && btrfs_super_cache_generation(sb) != (u64)-1)
+               btrfs_warn(fs_info,
+                       "suspicious: generation < cache_generation: %llu < %llu",
+                       btrfs_super_generation(sb),
+                       btrfs_super_cache_generation(sb));
+
+       return ret;
+}
+
+/*
+ * Validation of super block at mount time.
+ * Some checks already done early at mount time, like csum type and incompat
+ * flags will be skipped.
+ */
+static int btrfs_validate_mount_super(struct btrfs_fs_info *fs_info)
+{
+       return validate_super(fs_info, fs_info->super_copy, 0);
+}
+
 int open_ctree(struct super_block *sb,
               struct btrfs_fs_devices *fs_devices,
               char *options)
@@ -2601,7 +2769,6 @@ int open_ctree(struct super_block *sb,
        mutex_init(&fs_info->chunk_mutex);
        mutex_init(&fs_info->transaction_kthread_mutex);
        mutex_init(&fs_info->cleaner_mutex);
-       mutex_init(&fs_info->volume_mutex);
        mutex_init(&fs_info->ro_block_group_mutex);
        init_rwsem(&fs_info->commit_root_sem);
        init_rwsem(&fs_info->cleanup_work_sem);
@@ -2668,7 +2835,7 @@ int open_ctree(struct super_block *sb,
 
        memcpy(fs_info->fsid, fs_info->super_copy->fsid, BTRFS_FSID_SIZE);
 
-       ret = btrfs_check_super_valid(fs_info);
+       ret = btrfs_validate_mount_super(fs_info);
        if (ret) {
                btrfs_err(fs_info, "superblock contains fatal errors");
                err = -EINVAL;
@@ -3523,7 +3690,7 @@ int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags)
        for (raid_type = 0; raid_type < BTRFS_NR_RAID_TYPES; raid_type++) {
                if (raid_type == BTRFS_RAID_SINGLE)
                        continue;
-               if (!(flags & btrfs_raid_group[raid_type]))
+               if (!(flags & btrfs_raid_array[raid_type].bg_flag))
                        continue;
                min_tolerated = min(min_tolerated,
                                    btrfs_raid_array[raid_type].
@@ -3818,6 +3985,7 @@ void close_ctree(struct btrfs_fs_info *fs_info)
        set_bit(BTRFS_FS_CLOSING_DONE, &fs_info->flags);
 
        btrfs_free_qgroup_config(fs_info);
+       ASSERT(list_empty(&fs_info->delalloc_roots));
 
        if (percpu_counter_sum(&fs_info->delalloc_bytes)) {
                btrfs_info(fs_info, "at unmount delalloc count %lld",
@@ -3974,166 +4142,17 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid, int level,
                                              level, first_key);
 }
 
-static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info)
-{
-       struct btrfs_super_block *sb = fs_info->super_copy;
-       u64 nodesize = btrfs_super_nodesize(sb);
-       u64 sectorsize = btrfs_super_sectorsize(sb);
-       int ret = 0;
-
-       if (btrfs_super_magic(sb) != BTRFS_MAGIC) {
-               btrfs_err(fs_info, "no valid FS found");
-               ret = -EINVAL;
-       }
-       if (btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP) {
-               btrfs_err(fs_info, "unrecognized or unsupported super flag: %llu",
-                               btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP);
-               ret = -EINVAL;
-       }
-       if (btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL) {
-               btrfs_err(fs_info, "tree_root level too big: %d >= %d",
-                               btrfs_super_root_level(sb), BTRFS_MAX_LEVEL);
-               ret = -EINVAL;
-       }
-       if (btrfs_super_chunk_root_level(sb) >= BTRFS_MAX_LEVEL) {
-               btrfs_err(fs_info, "chunk_root level too big: %d >= %d",
-                               btrfs_super_chunk_root_level(sb), BTRFS_MAX_LEVEL);
-               ret = -EINVAL;
-       }
-       if (btrfs_super_log_root_level(sb) >= BTRFS_MAX_LEVEL) {
-               btrfs_err(fs_info, "log_root level too big: %d >= %d",
-                               btrfs_super_log_root_level(sb), BTRFS_MAX_LEVEL);
-               ret = -EINVAL;
-       }
-
-       /*
-        * Check sectorsize and nodesize first, other check will need it.
-        * Check all possible sectorsize(4K, 8K, 16K, 32K, 64K) here.
-        */
-       if (!is_power_of_2(sectorsize) || sectorsize < 4096 ||
-           sectorsize > BTRFS_MAX_METADATA_BLOCKSIZE) {
-               btrfs_err(fs_info, "invalid sectorsize %llu", sectorsize);
-               ret = -EINVAL;
-       }
-       /* Only PAGE SIZE is supported yet */
-       if (sectorsize != PAGE_SIZE) {
-               btrfs_err(fs_info,
-                       "sectorsize %llu not supported yet, only support %lu",
-                       sectorsize, PAGE_SIZE);
-               ret = -EINVAL;
-       }
-       if (!is_power_of_2(nodesize) || nodesize < sectorsize ||
-           nodesize > BTRFS_MAX_METADATA_BLOCKSIZE) {
-               btrfs_err(fs_info, "invalid nodesize %llu", nodesize);
-               ret = -EINVAL;
-       }
-       if (nodesize != le32_to_cpu(sb->__unused_leafsize)) {
-               btrfs_err(fs_info, "invalid leafsize %u, should be %llu",
-                         le32_to_cpu(sb->__unused_leafsize), nodesize);
-               ret = -EINVAL;
-       }
-
-       /* Root alignment check */
-       if (!IS_ALIGNED(btrfs_super_root(sb), sectorsize)) {
-               btrfs_warn(fs_info, "tree_root block unaligned: %llu",
-                          btrfs_super_root(sb));
-               ret = -EINVAL;
-       }
-       if (!IS_ALIGNED(btrfs_super_chunk_root(sb), sectorsize)) {
-               btrfs_warn(fs_info, "chunk_root block unaligned: %llu",
-                          btrfs_super_chunk_root(sb));
-               ret = -EINVAL;
-       }
-       if (!IS_ALIGNED(btrfs_super_log_root(sb), sectorsize)) {
-               btrfs_warn(fs_info, "log_root block unaligned: %llu",
-                          btrfs_super_log_root(sb));
-               ret = -EINVAL;
-       }
-
-       if (memcmp(fs_info->fsid, sb->dev_item.fsid, BTRFS_FSID_SIZE) != 0) {
-               btrfs_err(fs_info,
-                          "dev_item UUID does not match fsid: %pU != %pU",
-                          fs_info->fsid, sb->dev_item.fsid);
-               ret = -EINVAL;
-       }
-
-       /*
-        * Hint to catch really bogus numbers, bitflips or so, more exact checks are
-        * done later
-        */
-       if (btrfs_super_bytes_used(sb) < 6 * btrfs_super_nodesize(sb)) {
-               btrfs_err(fs_info, "bytes_used is too small %llu",
-                         btrfs_super_bytes_used(sb));
-               ret = -EINVAL;
-       }
-       if (!is_power_of_2(btrfs_super_stripesize(sb))) {
-               btrfs_err(fs_info, "invalid stripesize %u",
-                         btrfs_super_stripesize(sb));
-               ret = -EINVAL;
-       }
-       if (btrfs_super_num_devices(sb) > (1UL << 31))
-               btrfs_warn(fs_info, "suspicious number of devices: %llu",
-                          btrfs_super_num_devices(sb));
-       if (btrfs_super_num_devices(sb) == 0) {
-               btrfs_err(fs_info, "number of devices is 0");
-               ret = -EINVAL;
-       }
-
-       if (btrfs_super_bytenr(sb) != BTRFS_SUPER_INFO_OFFSET) {
-               btrfs_err(fs_info, "super offset mismatch %llu != %u",
-                         btrfs_super_bytenr(sb), BTRFS_SUPER_INFO_OFFSET);
-               ret = -EINVAL;
-       }
-
-       /*
-        * Obvious sys_chunk_array corruptions, it must hold at least one key
-        * and one chunk
-        */
-       if (btrfs_super_sys_array_size(sb) > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) {
-               btrfs_err(fs_info, "system chunk array too big %u > %u",
-                         btrfs_super_sys_array_size(sb),
-                         BTRFS_SYSTEM_CHUNK_ARRAY_SIZE);
-               ret = -EINVAL;
-       }
-       if (btrfs_super_sys_array_size(sb) < sizeof(struct btrfs_disk_key)
-                       + sizeof(struct btrfs_chunk)) {
-               btrfs_err(fs_info, "system chunk array too small %u < %zu",
-                         btrfs_super_sys_array_size(sb),
-                         sizeof(struct btrfs_disk_key)
-                         + sizeof(struct btrfs_chunk));
-               ret = -EINVAL;
-       }
-
-       /*
-        * The generation is a global counter, we'll trust it more than the others
-        * but it's still possible that it's the one that's wrong.
-        */
-       if (btrfs_super_generation(sb) < btrfs_super_chunk_root_generation(sb))
-               btrfs_warn(fs_info,
-                       "suspicious: generation < chunk_root_generation: %llu < %llu",
-                       btrfs_super_generation(sb),
-                       btrfs_super_chunk_root_generation(sb));
-       if (btrfs_super_generation(sb) < btrfs_super_cache_generation(sb)
-           && btrfs_super_cache_generation(sb) != (u64)-1)
-               btrfs_warn(fs_info,
-                       "suspicious: generation < cache_generation: %llu < %llu",
-                       btrfs_super_generation(sb),
-                       btrfs_super_cache_generation(sb));
-
-       return ret;
-}
-
 static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info)
 {
+       /* cleanup FS via transaction */
+       btrfs_cleanup_transaction(fs_info);
+
        mutex_lock(&fs_info->cleaner_mutex);
        btrfs_run_delayed_iputs(fs_info);
        mutex_unlock(&fs_info->cleaner_mutex);
 
        down_write(&fs_info->cleanup_work_sem);
        up_write(&fs_info->cleanup_work_sem);
-
-       /* cleanup FS via transaction */
-       btrfs_cleanup_transaction(fs_info);
 }
 
 static void btrfs_destroy_ordered_extents(struct btrfs_root *root)
@@ -4258,19 +4277,23 @@ static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
        list_splice_init(&root->delalloc_inodes, &splice);
 
        while (!list_empty(&splice)) {
+               struct inode *inode = NULL;
                btrfs_inode = list_first_entry(&splice, struct btrfs_inode,
                                               delalloc_inodes);
-
-               list_del_init(&btrfs_inode->delalloc_inodes);
-               clear_bit(BTRFS_INODE_IN_DELALLOC_LIST,
-                         &btrfs_inode->runtime_flags);
+               __btrfs_del_delalloc_inode(root, btrfs_inode);
                spin_unlock(&root->delalloc_lock);
 
-               btrfs_invalidate_inodes(btrfs_inode->root);
-
+               /*
+                * Make sure we get a live inode and that it'll not disappear
+                * meanwhile.
+                */
+               inode = igrab(&btrfs_inode->vfs_inode);
+               if (inode) {
+                       invalidate_inode_pages2(inode->i_mapping);
+                       iput(inode);
+               }
                spin_lock(&root->delalloc_lock);
        }
-
        spin_unlock(&root->delalloc_lock);
 }
 
@@ -4286,7 +4309,6 @@ static void btrfs_destroy_all_delalloc_inodes(struct btrfs_fs_info *fs_info)
        while (!list_empty(&splice)) {
                root = list_first_entry(&splice, struct btrfs_root,
                                         delalloc_root);
-               list_del_init(&root->delalloc_root);
                root = btrfs_grab_fs_root(root);
                BUG_ON(!root);
                spin_unlock(&fs_info->delalloc_root_lock);