linux/fs/btrfs/tests/btrfs-tests.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2013 Fusion IO.  All rights reserved.
   4 */
   5
   6#include <linux/fs.h>
   7#include <linux/mount.h>
   8#include <linux/pseudo_fs.h>
   9#include <linux/magic.h>
  10#include "btrfs-tests.h"
  11#include "../ctree.h"
  12#include "../free-space-cache.h"
  13#include "../free-space-tree.h"
  14#include "../transaction.h"
  15#include "../volumes.h"
  16#include "../disk-io.h"
  17#include "../qgroup.h"
  18#include "../block-group.h"
  19
  20static struct vfsmount *test_mnt = NULL;
  21
  22const char *test_error[] = {
  23        [TEST_ALLOC_FS_INFO]         = "cannot allocate fs_info",
  24        [TEST_ALLOC_ROOT]            = "cannot allocate root",
  25        [TEST_ALLOC_EXTENT_BUFFER]   = "cannot extent buffer",
  26        [TEST_ALLOC_PATH]            = "cannot allocate path",
  27        [TEST_ALLOC_INODE]           = "cannot allocate inode",
  28        [TEST_ALLOC_BLOCK_GROUP]     = "cannot allocate block group",
  29        [TEST_ALLOC_EXTENT_MAP]      = "cannot allocate extent map",
  30};
  31
  32static const struct super_operations btrfs_test_super_ops = {
  33        .alloc_inode    = btrfs_alloc_inode,
  34        .destroy_inode  = btrfs_test_destroy_inode,
  35};
  36
  37
  38static int btrfs_test_init_fs_context(struct fs_context *fc)
  39{
  40        struct pseudo_fs_context *ctx = init_pseudo(fc, BTRFS_TEST_MAGIC);
  41        if (!ctx)
  42                return -ENOMEM;
  43        ctx->ops = &btrfs_test_super_ops;
  44        return 0;
  45}
  46
  47static struct file_system_type test_type = {
  48        .name           = "btrfs_test_fs",
  49        .init_fs_context = btrfs_test_init_fs_context,
  50        .kill_sb        = kill_anon_super,
  51};
  52
  53struct inode *btrfs_new_test_inode(void)
  54{
  55        struct inode *inode;
  56
  57        inode = new_inode(test_mnt->mnt_sb);
  58        if (inode)
  59                inode_init_owner(inode, NULL, S_IFREG);
  60
  61        return inode;
  62}
  63
  64static int btrfs_init_test_fs(void)
  65{
  66        int ret;
  67
  68        ret = register_filesystem(&test_type);
  69        if (ret) {
  70                printk(KERN_ERR "btrfs: cannot register test file system\n");
  71                return ret;
  72        }
  73
  74        test_mnt = kern_mount(&test_type);
  75        if (IS_ERR(test_mnt)) {
  76                printk(KERN_ERR "btrfs: cannot mount test file system\n");
  77                unregister_filesystem(&test_type);
  78                return PTR_ERR(test_mnt);
  79        }
  80        return 0;
  81}
  82
  83static void btrfs_destroy_test_fs(void)
  84{
  85        kern_unmount(test_mnt);
  86        unregister_filesystem(&test_type);
  87}
  88
  89struct btrfs_device *btrfs_alloc_dummy_device(struct btrfs_fs_info *fs_info)
  90{
  91        struct btrfs_device *dev;
  92
  93        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  94        if (!dev)
  95                return ERR_PTR(-ENOMEM);
  96
  97        extent_io_tree_init(NULL, &dev->alloc_state, 0, NULL);
  98        INIT_LIST_HEAD(&dev->dev_list);
  99        list_add(&dev->dev_list, &fs_info->fs_devices->devices);
 100
 101        return dev;
 102}
 103
 104static void btrfs_free_dummy_device(struct btrfs_device *dev)
 105{
 106        extent_io_tree_release(&dev->alloc_state);
 107        kfree(dev);
 108}
 109
 110struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(u32 nodesize, u32 sectorsize)
 111{
 112        struct btrfs_fs_info *fs_info = kzalloc(sizeof(struct btrfs_fs_info),
 113                                                GFP_KERNEL);
 114
 115        if (!fs_info)
 116                return fs_info;
 117        fs_info->fs_devices = kzalloc(sizeof(struct btrfs_fs_devices),
 118                                      GFP_KERNEL);
 119        if (!fs_info->fs_devices) {
 120                kfree(fs_info);
 121                return NULL;
 122        }
 123        INIT_LIST_HEAD(&fs_info->fs_devices->devices);
 124
 125        fs_info->super_copy = kzalloc(sizeof(struct btrfs_super_block),
 126                                      GFP_KERNEL);
 127        if (!fs_info->super_copy) {
 128                kfree(fs_info->fs_devices);
 129                kfree(fs_info);
 130                return NULL;
 131        }
 132
 133        btrfs_init_fs_info(fs_info);
 134
 135        fs_info->nodesize = nodesize;
 136        fs_info->sectorsize = sectorsize;
 137        set_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state);
 138
 139        test_mnt->mnt_sb->s_fs_info = fs_info;
 140
 141        return fs_info;
 142}
 143
 144void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
 145{
 146        struct radix_tree_iter iter;
 147        void **slot;
 148        struct btrfs_device *dev, *tmp;
 149
 150        if (!fs_info)
 151                return;
 152
 153        if (WARN_ON(!test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO,
 154                              &fs_info->fs_state)))
 155                return;
 156
 157        test_mnt->mnt_sb->s_fs_info = NULL;
 158
 159        spin_lock(&fs_info->buffer_lock);
 160        radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) {
 161                struct extent_buffer *eb;
 162
 163                eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock);
 164                if (!eb)
 165                        continue;
 166                /* Shouldn't happen but that kind of thinking creates CVE's */
 167                if (radix_tree_exception(eb)) {
 168                        if (radix_tree_deref_retry(eb))
 169                                slot = radix_tree_iter_retry(&iter);
 170                        continue;
 171                }
 172                slot = radix_tree_iter_resume(slot, &iter);
 173                spin_unlock(&fs_info->buffer_lock);
 174                free_extent_buffer_stale(eb);
 175                spin_lock(&fs_info->buffer_lock);
 176        }
 177        spin_unlock(&fs_info->buffer_lock);
 178
 179        btrfs_mapping_tree_free(&fs_info->mapping_tree);
 180        list_for_each_entry_safe(dev, tmp, &fs_info->fs_devices->devices,
 181                                 dev_list) {
 182                btrfs_free_dummy_device(dev);
 183        }
 184        btrfs_free_qgroup_config(fs_info);
 185        btrfs_free_fs_roots(fs_info);
 186        kfree(fs_info->super_copy);
 187        btrfs_check_leaked_roots(fs_info);
 188        btrfs_extent_buffer_leak_debug_check(fs_info);
 189        kfree(fs_info->fs_devices);
 190        kfree(fs_info);
 191}
 192
 193void btrfs_free_dummy_root(struct btrfs_root *root)
 194{
 195        if (!root)
 196                return;
 197        /* Will be freed by btrfs_free_fs_roots */
 198        if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state)))
 199                return;
 200        btrfs_put_root(root);
 201}
 202
 203struct btrfs_block_group *
 204btrfs_alloc_dummy_block_group(struct btrfs_fs_info *fs_info,
 205                              unsigned long length)
 206{
 207        struct btrfs_block_group *cache;
 208
 209        cache = kzalloc(sizeof(*cache), GFP_KERNEL);
 210        if (!cache)
 211                return NULL;
 212        cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
 213                                        GFP_KERNEL);
 214        if (!cache->free_space_ctl) {
 215                kfree(cache);
 216                return NULL;
 217        }
 218
 219        cache->start = 0;
 220        cache->length = length;
 221        cache->full_stripe_len = fs_info->sectorsize;
 222        cache->fs_info = fs_info;
 223
 224        INIT_LIST_HEAD(&cache->list);
 225        INIT_LIST_HEAD(&cache->cluster_list);
 226        INIT_LIST_HEAD(&cache->bg_list);
 227        btrfs_init_free_space_ctl(cache);
 228        mutex_init(&cache->free_space_lock);
 229
 230        return cache;
 231}
 232
 233void btrfs_free_dummy_block_group(struct btrfs_block_group *cache)
 234{
 235        if (!cache)
 236                return;
 237        __btrfs_remove_free_space_cache(cache->free_space_ctl);
 238        kfree(cache->free_space_ctl);
 239        kfree(cache);
 240}
 241
 242void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans,
 243                            struct btrfs_fs_info *fs_info)
 244{
 245        memset(trans, 0, sizeof(*trans));
 246        trans->transid = 1;
 247        trans->type = __TRANS_DUMMY;
 248        trans->fs_info = fs_info;
 249}
 250
 251int btrfs_run_sanity_tests(void)
 252{
 253        int ret, i;
 254        u32 sectorsize, nodesize;
 255        u32 test_sectorsize[] = {
 256                PAGE_SIZE,
 257        };
 258        ret = btrfs_init_test_fs();
 259        if (ret)
 260                return ret;
 261        for (i = 0; i < ARRAY_SIZE(test_sectorsize); i++) {
 262                sectorsize = test_sectorsize[i];
 263                for (nodesize = sectorsize;
 264                     nodesize <= BTRFS_MAX_METADATA_BLOCKSIZE;
 265                     nodesize <<= 1) {
 266                        pr_info("BTRFS: selftest: sectorsize: %u  nodesize: %u\n",
 267                                sectorsize, nodesize);
 268                        ret = btrfs_test_free_space_cache(sectorsize, nodesize);
 269                        if (ret)
 270                                goto out;
 271                        ret = btrfs_test_extent_buffer_operations(sectorsize,
 272                                nodesize);
 273                        if (ret)
 274                                goto out;
 275                        ret = btrfs_test_extent_io(sectorsize, nodesize);
 276                        if (ret)
 277                                goto out;
 278                        ret = btrfs_test_inodes(sectorsize, nodesize);
 279                        if (ret)
 280                                goto out;
 281                        ret = btrfs_test_qgroups(sectorsize, nodesize);
 282                        if (ret)
 283                                goto out;
 284                        ret = btrfs_test_free_space_tree(sectorsize, nodesize);
 285                        if (ret)
 286                                goto out;
 287                }
 288        }
 289        ret = btrfs_test_extent_map();
 290
 291out:
 292        btrfs_destroy_test_fs();
 293        return ret;
 294}
 295