2018-04-04 01:23:33 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2013-10-10 00:00:56 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2013 Fusion IO. All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/mount.h>
|
2019-03-26 00:38:25 +08:00
|
|
|
#include <linux/pseudo_fs.h>
|
2013-10-10 00:00:56 +08:00
|
|
|
#include <linux/magic.h>
|
|
|
|
#include "btrfs-tests.h"
|
|
|
|
#include "../ctree.h"
|
2015-09-30 11:50:36 +08:00
|
|
|
#include "../free-space-cache.h"
|
|
|
|
#include "../free-space-tree.h"
|
|
|
|
#include "../transaction.h"
|
2014-05-08 05:06:09 +08:00
|
|
|
#include "../volumes.h"
|
|
|
|
#include "../disk-io.h"
|
|
|
|
#include "../qgroup.h"
|
2019-06-21 03:37:44 +08:00
|
|
|
#include "../block-group.h"
|
2013-10-10 00:00:56 +08:00
|
|
|
|
|
|
|
static struct vfsmount *test_mnt = NULL;
|
|
|
|
|
2019-03-16 00:23:30 +08:00
|
|
|
const char *test_error[] = {
|
|
|
|
[TEST_ALLOC_FS_INFO] = "cannot allocate fs_info",
|
|
|
|
[TEST_ALLOC_ROOT] = "cannot allocate root",
|
|
|
|
[TEST_ALLOC_EXTENT_BUFFER] = "cannot extent buffer",
|
|
|
|
[TEST_ALLOC_PATH] = "cannot allocate path",
|
|
|
|
[TEST_ALLOC_INODE] = "cannot allocate inode",
|
|
|
|
[TEST_ALLOC_BLOCK_GROUP] = "cannot allocate block group",
|
|
|
|
[TEST_ALLOC_EXTENT_MAP] = "cannot allocate extent map",
|
|
|
|
};
|
|
|
|
|
2013-10-12 02:44:09 +08:00
|
|
|
static const struct super_operations btrfs_test_super_ops = {
|
|
|
|
.alloc_inode = btrfs_alloc_inode,
|
|
|
|
.destroy_inode = btrfs_test_destroy_inode,
|
|
|
|
};
|
|
|
|
|
2019-03-26 00:38:25 +08:00
|
|
|
|
|
|
|
static int btrfs_test_init_fs_context(struct fs_context *fc)
|
2013-10-10 00:00:56 +08:00
|
|
|
{
|
2019-03-26 00:38:25 +08:00
|
|
|
struct pseudo_fs_context *ctx = init_pseudo(fc, BTRFS_TEST_MAGIC);
|
|
|
|
if (!ctx)
|
|
|
|
return -ENOMEM;
|
|
|
|
ctx->ops = &btrfs_test_super_ops;
|
|
|
|
return 0;
|
2013-10-10 00:00:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct file_system_type test_type = {
|
|
|
|
.name = "btrfs_test_fs",
|
2019-03-26 00:38:25 +08:00
|
|
|
.init_fs_context = btrfs_test_init_fs_context,
|
2013-10-10 00:00:56 +08:00
|
|
|
.kill_sb = kill_anon_super,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct inode *btrfs_new_test_inode(void)
|
|
|
|
{
|
Btrfs: fix selftests failure due to uninitialized i_mode in test inodes
Some of the self tests create a test inode, setup some extents and then do
calls to btrfs_get_extent() to test that the corresponding extent maps
exist and are correct. However btrfs_get_extent(), since the 5.2 merge
window, now errors out when it finds a regular or prealloc extent for an
inode that does not correspond to a regular file (its ->i_mode is not
S_IFREG). This causes the self tests to fail sometimes, specially when
KASAN, slub_debug and page poisoning are enabled:
$ modprobe btrfs
modprobe: ERROR: could not insert 'btrfs': Invalid argument
$ dmesg
[ 9414.691648] Btrfs loaded, crc32c=crc32c-intel, debug=on, assert=on, integrity-checker=on, ref-verify=on
[ 9414.692655] BTRFS: selftest: sectorsize: 4096 nodesize: 4096
[ 9414.692658] BTRFS: selftest: running btrfs free space cache tests
[ 9414.692918] BTRFS: selftest: running extent only tests
[ 9414.693061] BTRFS: selftest: running bitmap only tests
[ 9414.693366] BTRFS: selftest: running bitmap and extent tests
[ 9414.696455] BTRFS: selftest: running space stealing from bitmap to extent tests
[ 9414.697131] BTRFS: selftest: running extent buffer operation tests
[ 9414.697133] BTRFS: selftest: running btrfs_split_item tests
[ 9414.697564] BTRFS: selftest: running extent I/O tests
[ 9414.697583] BTRFS: selftest: running find delalloc tests
[ 9415.081125] BTRFS: selftest: running find_first_clear_extent_bit test
[ 9415.081278] BTRFS: selftest: running extent buffer bitmap tests
[ 9415.124192] BTRFS: selftest: running inode tests
[ 9415.124195] BTRFS: selftest: running btrfs_get_extent tests
[ 9415.127909] BTRFS: selftest: running hole first btrfs_get_extent test
[ 9415.128343] BTRFS critical (device (efault)): regular/prealloc extent found for non-regular inode 256
[ 9415.131428] BTRFS: selftest: fs/btrfs/tests/inode-tests.c:904 expected a real extent, got 0
This happens because the test inodes are created without ever initializing
the i_mode field of the inode, and neither VFS's new_inode() nor the btrfs
callback btrfs_alloc_inode() initialize the i_mode. Initialization of the
i_mode is done through the various callbacks used by the VFS to create
new inodes (regular files, directories, symlinks, tmpfiles, etc), which
all call btrfs_new_inode() which in turn calls inode_init_owner(), which
sets the inode's i_mode. Since the tests only uses new_inode() to create
the test inodes, the i_mode was never initialized.
This always happens on a VM I used with kasan, slub_debug and many other
debug facilities enabled. It also happened to someone who reported this
on bugzilla (on a 5.3-rc).
Fix this by setting i_mode to S_IFREG at btrfs_new_test_inode().
Fixes: 6bf9e4bd6a2778 ("btrfs: inode: Verify inode mode to avoid NULL pointer dereference")
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=204397
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2019-09-18 20:08:52 +08:00
|
|
|
struct inode *inode;
|
|
|
|
|
|
|
|
inode = new_inode(test_mnt->mnt_sb);
|
|
|
|
if (inode)
|
|
|
|
inode_init_owner(inode, NULL, S_IFREG);
|
|
|
|
|
|
|
|
return inode;
|
2013-10-10 00:00:56 +08:00
|
|
|
}
|
|
|
|
|
2016-06-21 01:16:40 +08:00
|
|
|
static int btrfs_init_test_fs(void)
|
2013-10-10 00:00:56 +08:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = register_filesystem(&test_type);
|
|
|
|
if (ret) {
|
|
|
|
printk(KERN_ERR "btrfs: cannot register test file system\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
test_mnt = kern_mount(&test_type);
|
|
|
|
if (IS_ERR(test_mnt)) {
|
|
|
|
printk(KERN_ERR "btrfs: cannot mount test file system\n");
|
|
|
|
unregister_filesystem(&test_type);
|
2016-06-18 01:20:40 +08:00
|
|
|
return PTR_ERR(test_mnt);
|
2013-10-10 00:00:56 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-21 01:16:40 +08:00
|
|
|
static void btrfs_destroy_test_fs(void)
|
2013-10-10 00:00:56 +08:00
|
|
|
{
|
|
|
|
kern_unmount(test_mnt);
|
|
|
|
unregister_filesystem(&test_type);
|
|
|
|
}
|
2014-05-08 05:06:09 +08:00
|
|
|
|
2019-11-19 20:05:51 +08:00
|
|
|
struct btrfs_device *btrfs_alloc_dummy_device(struct btrfs_fs_info *fs_info)
|
|
|
|
{
|
|
|
|
struct btrfs_device *dev;
|
|
|
|
|
|
|
|
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
|
|
|
if (!dev)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
extent_io_tree_init(NULL, &dev->alloc_state, 0, NULL);
|
|
|
|
INIT_LIST_HEAD(&dev->dev_list);
|
|
|
|
list_add(&dev->dev_list, &fs_info->fs_devices->devices);
|
|
|
|
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void btrfs_free_dummy_device(struct btrfs_device *dev)
|
|
|
|
{
|
|
|
|
extent_io_tree_release(&dev->alloc_state);
|
|
|
|
kfree(dev);
|
|
|
|
}
|
|
|
|
|
2016-06-15 21:22:56 +08:00
|
|
|
struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(u32 nodesize, u32 sectorsize)
|
2014-05-08 05:06:09 +08:00
|
|
|
{
|
|
|
|
struct btrfs_fs_info *fs_info = kzalloc(sizeof(struct btrfs_fs_info),
|
2016-01-22 17:28:24 +08:00
|
|
|
GFP_KERNEL);
|
2014-05-08 05:06:09 +08:00
|
|
|
|
|
|
|
if (!fs_info)
|
|
|
|
return fs_info;
|
|
|
|
fs_info->fs_devices = kzalloc(sizeof(struct btrfs_fs_devices),
|
2016-01-22 17:28:24 +08:00
|
|
|
GFP_KERNEL);
|
2014-05-08 05:06:09 +08:00
|
|
|
if (!fs_info->fs_devices) {
|
|
|
|
kfree(fs_info);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
fs_info->super_copy = kzalloc(sizeof(struct btrfs_super_block),
|
2016-01-22 17:28:24 +08:00
|
|
|
GFP_KERNEL);
|
2014-05-08 05:06:09 +08:00
|
|
|
if (!fs_info->super_copy) {
|
|
|
|
kfree(fs_info->fs_devices);
|
|
|
|
kfree(fs_info);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-15 21:22:56 +08:00
|
|
|
fs_info->nodesize = nodesize;
|
|
|
|
fs_info->sectorsize = sectorsize;
|
|
|
|
|
2014-05-08 05:06:09 +08:00
|
|
|
if (init_srcu_struct(&fs_info->subvol_srcu)) {
|
|
|
|
kfree(fs_info->fs_devices);
|
|
|
|
kfree(fs_info->super_copy);
|
|
|
|
kfree(fs_info);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock_init(&fs_info->buffer_lock);
|
|
|
|
spin_lock_init(&fs_info->qgroup_lock);
|
|
|
|
spin_lock_init(&fs_info->super_lock);
|
|
|
|
spin_lock_init(&fs_info->fs_roots_radix_lock);
|
|
|
|
mutex_init(&fs_info->qgroup_ioctl_lock);
|
|
|
|
mutex_init(&fs_info->qgroup_rescan_lock);
|
|
|
|
rwlock_init(&fs_info->tree_mod_log_lock);
|
|
|
|
fs_info->running_transaction = NULL;
|
|
|
|
fs_info->qgroup_tree = RB_ROOT;
|
|
|
|
fs_info->qgroup_ulist = NULL;
|
|
|
|
atomic64_set(&fs_info->tree_mod_seq, 0);
|
|
|
|
INIT_LIST_HEAD(&fs_info->dirty_qgroups);
|
|
|
|
INIT_LIST_HEAD(&fs_info->dead_roots);
|
|
|
|
INIT_LIST_HEAD(&fs_info->tree_mod_seq_list);
|
2019-11-19 20:05:51 +08:00
|
|
|
INIT_LIST_HEAD(&fs_info->fs_devices->devices);
|
2014-05-08 05:06:09 +08:00
|
|
|
INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC);
|
|
|
|
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
|
2019-03-01 10:47:59 +08:00
|
|
|
extent_io_tree_init(fs_info, &fs_info->freed_extents[0],
|
|
|
|
IO_TREE_FS_INFO_FREED_EXTENTS0, NULL);
|
|
|
|
extent_io_tree_init(fs_info, &fs_info->freed_extents[1],
|
|
|
|
IO_TREE_FS_INFO_FREED_EXTENTS1, NULL);
|
2019-11-19 20:05:51 +08:00
|
|
|
extent_map_tree_init(&fs_info->mapping_tree);
|
2015-09-30 11:50:36 +08:00
|
|
|
fs_info->pinned_extents = &fs_info->freed_extents[0];
|
2016-06-21 02:14:09 +08:00
|
|
|
set_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state);
|
|
|
|
|
|
|
|
test_mnt->mnt_sb->s_fs_info = fs_info;
|
|
|
|
|
2014-05-08 05:06:09 +08:00
|
|
|
return fs_info;
|
|
|
|
}
|
|
|
|
|
2016-06-21 02:14:09 +08:00
|
|
|
void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
|
2014-05-08 05:06:09 +08:00
|
|
|
{
|
|
|
|
struct radix_tree_iter iter;
|
|
|
|
void **slot;
|
2019-11-19 20:05:51 +08:00
|
|
|
struct btrfs_device *dev, *tmp;
|
2014-05-08 05:06:09 +08:00
|
|
|
|
2016-06-21 02:14:09 +08:00
|
|
|
if (!fs_info)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (WARN_ON(!test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO,
|
|
|
|
&fs_info->fs_state)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
test_mnt->mnt_sb->s_fs_info = NULL;
|
|
|
|
|
2014-05-08 05:06:09 +08:00
|
|
|
spin_lock(&fs_info->buffer_lock);
|
|
|
|
radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) {
|
|
|
|
struct extent_buffer *eb;
|
|
|
|
|
2014-06-12 00:00:25 +08:00
|
|
|
eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock);
|
2014-05-08 05:06:09 +08:00
|
|
|
if (!eb)
|
|
|
|
continue;
|
|
|
|
/* Shouldn't happen but that kind of thinking creates CVE's */
|
|
|
|
if (radix_tree_exception(eb)) {
|
|
|
|
if (radix_tree_deref_retry(eb))
|
2016-03-18 05:22:00 +08:00
|
|
|
slot = radix_tree_iter_retry(&iter);
|
2014-05-08 05:06:09 +08:00
|
|
|
continue;
|
|
|
|
}
|
2016-12-15 07:08:49 +08:00
|
|
|
slot = radix_tree_iter_resume(slot, &iter);
|
2014-05-08 05:06:09 +08:00
|
|
|
spin_unlock(&fs_info->buffer_lock);
|
|
|
|
free_extent_buffer_stale(eb);
|
|
|
|
spin_lock(&fs_info->buffer_lock);
|
|
|
|
}
|
|
|
|
spin_unlock(&fs_info->buffer_lock);
|
|
|
|
|
2019-11-19 20:05:51 +08:00
|
|
|
btrfs_mapping_tree_free(&fs_info->mapping_tree);
|
|
|
|
list_for_each_entry_safe(dev, tmp, &fs_info->fs_devices->devices,
|
|
|
|
dev_list) {
|
|
|
|
btrfs_free_dummy_device(dev);
|
|
|
|
}
|
2014-05-08 05:06:09 +08:00
|
|
|
btrfs_free_qgroup_config(fs_info);
|
|
|
|
btrfs_free_fs_roots(fs_info);
|
|
|
|
cleanup_srcu_struct(&fs_info->subvol_srcu);
|
|
|
|
kfree(fs_info->super_copy);
|
|
|
|
kfree(fs_info->fs_devices);
|
|
|
|
kfree(fs_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
void btrfs_free_dummy_root(struct btrfs_root *root)
|
|
|
|
{
|
|
|
|
if (!root)
|
|
|
|
return;
|
2016-06-21 02:14:09 +08:00
|
|
|
/* Will be freed by btrfs_free_fs_roots */
|
|
|
|
if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state)))
|
|
|
|
return;
|
2018-08-15 23:26:57 +08:00
|
|
|
if (root->node) {
|
|
|
|
/* One for allocate_extent_buffer */
|
2014-05-08 05:06:09 +08:00
|
|
|
free_extent_buffer(root->node);
|
2018-08-15 23:26:57 +08:00
|
|
|
}
|
2014-05-08 05:06:09 +08:00
|
|
|
kfree(root);
|
|
|
|
}
|
|
|
|
|
2019-10-30 02:20:18 +08:00
|
|
|
struct btrfs_block_group *
|
2016-06-15 21:22:56 +08:00
|
|
|
btrfs_alloc_dummy_block_group(struct btrfs_fs_info *fs_info,
|
|
|
|
unsigned long length)
|
2015-09-30 11:50:36 +08:00
|
|
|
{
|
2019-10-30 02:20:18 +08:00
|
|
|
struct btrfs_block_group *cache;
|
2015-09-30 11:50:36 +08:00
|
|
|
|
2016-01-22 17:28:24 +08:00
|
|
|
cache = kzalloc(sizeof(*cache), GFP_KERNEL);
|
2015-09-30 11:50:36 +08:00
|
|
|
if (!cache)
|
|
|
|
return NULL;
|
|
|
|
cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
|
2016-01-22 17:28:24 +08:00
|
|
|
GFP_KERNEL);
|
2015-09-30 11:50:36 +08:00
|
|
|
if (!cache->free_space_ctl) {
|
|
|
|
kfree(cache);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-10-24 00:48:22 +08:00
|
|
|
cache->start = 0;
|
|
|
|
cache->length = length;
|
2016-06-15 21:22:56 +08:00
|
|
|
cache->full_stripe_len = fs_info->sectorsize;
|
|
|
|
cache->fs_info = fs_info;
|
2015-09-30 11:50:36 +08:00
|
|
|
|
|
|
|
INIT_LIST_HEAD(&cache->list);
|
|
|
|
INIT_LIST_HEAD(&cache->cluster_list);
|
|
|
|
INIT_LIST_HEAD(&cache->bg_list);
|
|
|
|
btrfs_init_free_space_ctl(cache);
|
|
|
|
mutex_init(&cache->free_space_lock);
|
|
|
|
|
|
|
|
return cache;
|
|
|
|
}
|
|
|
|
|
2019-10-30 02:20:18 +08:00
|
|
|
void btrfs_free_dummy_block_group(struct btrfs_block_group *cache)
|
2015-09-30 11:50:36 +08:00
|
|
|
{
|
|
|
|
if (!cache)
|
|
|
|
return;
|
|
|
|
__btrfs_remove_free_space_cache(cache->free_space_ctl);
|
|
|
|
kfree(cache->free_space_ctl);
|
|
|
|
kfree(cache);
|
|
|
|
}
|
|
|
|
|
2018-05-10 20:44:40 +08:00
|
|
|
void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans,
|
|
|
|
struct btrfs_fs_info *fs_info)
|
2015-09-30 11:50:36 +08:00
|
|
|
{
|
|
|
|
memset(trans, 0, sizeof(*trans));
|
|
|
|
trans->transid = 1;
|
|
|
|
trans->type = __TRANS_DUMMY;
|
2018-05-10 20:44:40 +08:00
|
|
|
trans->fs_info = fs_info;
|
2015-09-30 11:50:36 +08:00
|
|
|
}
|
2016-06-21 01:16:40 +08:00
|
|
|
|
|
|
|
int btrfs_run_sanity_tests(void)
|
|
|
|
{
|
|
|
|
int ret, i;
|
|
|
|
u32 sectorsize, nodesize;
|
|
|
|
u32 test_sectorsize[] = {
|
|
|
|
PAGE_SIZE,
|
|
|
|
};
|
|
|
|
ret = btrfs_init_test_fs();
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(test_sectorsize); i++) {
|
|
|
|
sectorsize = test_sectorsize[i];
|
|
|
|
for (nodesize = sectorsize;
|
|
|
|
nodesize <= BTRFS_MAX_METADATA_BLOCKSIZE;
|
|
|
|
nodesize <<= 1) {
|
|
|
|
pr_info("BTRFS: selftest: sectorsize: %u nodesize: %u\n",
|
|
|
|
sectorsize, nodesize);
|
|
|
|
ret = btrfs_test_free_space_cache(sectorsize, nodesize);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
ret = btrfs_test_extent_buffer_operations(sectorsize,
|
|
|
|
nodesize);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
ret = btrfs_test_extent_io(sectorsize, nodesize);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
ret = btrfs_test_inodes(sectorsize, nodesize);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
ret = btrfs_test_qgroups(sectorsize, nodesize);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
ret = btrfs_test_free_space_tree(sectorsize, nodesize);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
2018-01-06 03:51:12 +08:00
|
|
|
ret = btrfs_test_extent_map();
|
2018-01-13 00:52:58 +08:00
|
|
|
|
2016-06-21 01:16:40 +08:00
|
|
|
out:
|
|
|
|
btrfs_destroy_test_fs();
|
|
|
|
return ret;
|
|
|
|
}
|