2018-04-03 19:23:33 +02:00
// SPDX-License-Identifier: GPL-2.0
2013-10-09 12:00:56 -04:00
/*
* Copyright ( C ) 2013 Fusion IO . All rights reserved .
*/
# include <linux/fs.h>
# include <linux/mount.h>
2019-03-25 16:38:25 +00:00
# include <linux/pseudo_fs.h>
2013-10-09 12:00:56 -04:00
# include <linux/magic.h>
# include "btrfs-tests.h"
# include "../ctree.h"
2015-09-29 20:50:36 -07:00
# include "../free-space-cache.h"
# include "../free-space-tree.h"
# include "../transaction.h"
2014-05-07 17:06:09 -04:00
# include "../volumes.h"
# include "../disk-io.h"
# include "../qgroup.h"
2019-06-20 15:37:44 -04:00
# include "../block-group.h"
2022-10-19 10:50:51 -04:00
# include "../fs.h"
2013-10-09 12:00:56 -04:00
static struct vfsmount * test_mnt = NULL ;
2019-03-15 17:23:30 +01: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-11 14:44:09 -04:00
static const struct super_operations btrfs_test_super_ops = {
. alloc_inode = btrfs_alloc_inode ,
. destroy_inode = btrfs_test_destroy_inode ,
} ;
2019-03-25 16:38:25 +00:00
static int btrfs_test_init_fs_context ( struct fs_context * fc )
2013-10-09 12:00:56 -04:00
{
2019-03-25 16:38:25 +00: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-09 12:00:56 -04:00
}
static struct file_system_type test_type = {
. name = " btrfs_test_fs " ,
2019-03-25 16:38:25 +00:00
. init_fs_context = btrfs_test_init_fs_context ,
2013-10-09 12:00:56 -04: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 13:08:52 +01:00
struct inode * inode ;
inode = new_inode ( test_mnt - > mnt_sb ) ;
2020-12-15 12:00:26 -05:00
if ( ! inode )
return NULL ;
inode - > i_mode = S_IFREG ;
2022-07-11 15:22:50 +01:00
inode - > i_ino = BTRFS_FIRST_FREE_OBJECTID ;
2020-12-15 12:00:26 -05:00
BTRFS_I ( inode ) - > location . type = BTRFS_INODE_ITEM_KEY ;
BTRFS_I ( inode ) - > location . objectid = BTRFS_FIRST_FREE_OBJECTID ;
BTRFS_I ( inode ) - > location . offset = 0 ;
2023-01-13 12:49:25 +01:00
inode_init_owner ( & nop_mnt_idmap , inode , NULL , S_IFREG ) ;
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 13:08:52 +01:00
return inode ;
2013-10-09 12:00:56 -04:00
}
2016-06-20 13:16:40 -04:00
static int btrfs_init_test_fs ( void )
2013-10-09 12:00:56 -04: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-17 17:20:40 +00:00
return PTR_ERR ( test_mnt ) ;
2013-10-09 12:00:56 -04:00
}
return 0 ;
}
2016-06-20 13:16:40 -04:00
static void btrfs_destroy_test_fs ( void )
2013-10-09 12:00:56 -04:00
{
kern_unmount ( test_mnt ) ;
unregister_filesystem ( & test_type ) ;
}
2014-05-07 17:06:09 -04:00
2019-11-19 14:05:51 +02: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 ) ;
2022-10-28 02:47:06 +02:00
extent_io_tree_init ( NULL , & dev - > alloc_state , 0 ) ;
2019-11-19 14:05:51 +02:00
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 09:22:56 -04:00
struct btrfs_fs_info * btrfs_alloc_dummy_fs_info ( u32 nodesize , u32 sectorsize )
2014-05-07 17:06:09 -04:00
{
struct btrfs_fs_info * fs_info = kzalloc ( sizeof ( struct btrfs_fs_info ) ,
2016-01-22 10:28:24 +01:00
GFP_KERNEL ) ;
2014-05-07 17:06:09 -04:00
if ( ! fs_info )
return fs_info ;
fs_info - > fs_devices = kzalloc ( sizeof ( struct btrfs_fs_devices ) ,
2016-01-22 10:28:24 +01:00
GFP_KERNEL ) ;
2014-05-07 17:06:09 -04:00
if ( ! fs_info - > fs_devices ) {
kfree ( fs_info ) ;
return NULL ;
}
2020-01-24 09:32:59 -05:00
INIT_LIST_HEAD ( & fs_info - > fs_devices - > devices ) ;
2014-05-07 17:06:09 -04:00
fs_info - > super_copy = kzalloc ( sizeof ( struct btrfs_super_block ) ,
2016-01-22 10:28:24 +01:00
GFP_KERNEL ) ;
2014-05-07 17:06:09 -04:00
if ( ! fs_info - > super_copy ) {
kfree ( fs_info - > fs_devices ) ;
kfree ( fs_info ) ;
return NULL ;
}
2020-01-24 09:32:59 -05:00
btrfs_init_fs_info ( fs_info ) ;
2016-06-15 09:22:56 -04:00
fs_info - > nodesize = nodesize ;
fs_info - > sectorsize = sectorsize ;
2020-07-01 20:45:04 +02:00
fs_info - > sectorsize_bits = ilog2 ( sectorsize ) ;
2016-06-20 14:14:09 -04:00
set_bit ( BTRFS_FS_STATE_DUMMY_FS_INFO , & fs_info - > fs_state ) ;
test_mnt - > mnt_sb - > s_fs_info = fs_info ;
2014-05-07 17:06:09 -04:00
return fs_info ;
}
2016-06-20 14:14:09 -04:00
void btrfs_free_dummy_fs_info ( struct btrfs_fs_info * fs_info )
2014-05-07 17:06:09 -04:00
{
2022-07-15 13:59:31 +02:00
struct radix_tree_iter iter ;
void * * slot ;
2019-11-19 14:05:51 +02:00
struct btrfs_device * dev , * tmp ;
2014-05-07 17:06:09 -04:00
2016-06-20 14:14:09 -04: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 ;
2022-07-15 13:59:31 +02:00
spin_lock ( & fs_info - > buffer_lock ) ;
radix_tree_for_each_slot ( slot , & fs_info - > buffer_radix , & iter , 0 ) {
struct extent_buffer * eb ;
eb = radix_tree_deref_slot_protected ( slot , & fs_info - > buffer_lock ) ;
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 ) )
slot = radix_tree_iter_retry ( & iter ) ;
continue ;
}
slot = radix_tree_iter_resume ( slot , & iter ) ;
spin_unlock ( & fs_info - > buffer_lock ) ;
2014-05-07 17:06:09 -04:00
free_extent_buffer_stale ( eb ) ;
2022-07-15 13:59:31 +02:00
spin_lock ( & fs_info - > buffer_lock ) ;
2014-05-07 17:06:09 -04:00
}
2022-07-15 13:59:31 +02:00
spin_unlock ( & fs_info - > buffer_lock ) ;
2014-05-07 17:06:09 -04:00
2019-11-19 14:05:51 +02: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-07 17:06:09 -04:00
btrfs_free_qgroup_config ( fs_info ) ;
btrfs_free_fs_roots ( fs_info ) ;
kfree ( fs_info - > super_copy ) ;
2020-01-24 09:33:00 -05:00
btrfs_check_leaked_roots ( fs_info ) ;
2020-02-14 16:11:42 -05:00
btrfs_extent_buffer_leak_debug_check ( fs_info ) ;
2014-05-07 17:06:09 -04:00
kfree ( fs_info - > fs_devices ) ;
kfree ( fs_info ) ;
}
void btrfs_free_dummy_root ( struct btrfs_root * root )
{
2022-11-01 10:53:54 +08:00
if ( IS_ERR_OR_NULL ( root ) )
2014-05-07 17:06:09 -04:00
return ;
2016-06-20 14:14:09 -04:00
/* Will be freed by btrfs_free_fs_roots */
2022-07-15 13:59:21 +02:00
if ( WARN_ON ( test_bit ( BTRFS_ROOT_IN_RADIX , & root - > state ) ) )
2016-06-20 14:14:09 -04:00
return ;
2021-11-05 16:45:51 -04:00
btrfs_global_root_delete ( root ) ;
2020-01-24 09:33:01 -05:00
btrfs_put_root ( root ) ;
2014-05-07 17:06:09 -04:00
}
2019-10-29 19:20:18 +01:00
struct btrfs_block_group *
2016-06-15 09:22:56 -04:00
btrfs_alloc_dummy_block_group ( struct btrfs_fs_info * fs_info ,
unsigned long length )
2015-09-29 20:50:36 -07:00
{
2019-10-29 19:20:18 +01:00
struct btrfs_block_group * cache ;
2015-09-29 20:50:36 -07:00
2016-01-22 10:28:24 +01:00
cache = kzalloc ( sizeof ( * cache ) , GFP_KERNEL ) ;
2015-09-29 20:50:36 -07:00
if ( ! cache )
return NULL ;
cache - > free_space_ctl = kzalloc ( sizeof ( * cache - > free_space_ctl ) ,
2016-01-22 10:28:24 +01:00
GFP_KERNEL ) ;
2015-09-29 20:50:36 -07:00
if ( ! cache - > free_space_ctl ) {
kfree ( cache ) ;
return NULL ;
}
2019-10-23 18:48:22 +02:00
cache - > start = 0 ;
cache - > length = length ;
2016-06-15 09:22:56 -04:00
cache - > full_stripe_len = fs_info - > sectorsize ;
cache - > fs_info = fs_info ;
2015-09-29 20:50:36 -07:00
INIT_LIST_HEAD ( & cache - > list ) ;
INIT_LIST_HEAD ( & cache - > cluster_list ) ;
INIT_LIST_HEAD ( & cache - > bg_list ) ;
2020-10-23 09:58:08 -04:00
btrfs_init_free_space_ctl ( cache , cache - > free_space_ctl ) ;
2015-09-29 20:50:36 -07:00
mutex_init ( & cache - > free_space_lock ) ;
return cache ;
}
2019-10-29 19:20:18 +01:00
void btrfs_free_dummy_block_group ( struct btrfs_block_group * cache )
2015-09-29 20:50:36 -07:00
{
if ( ! cache )
return ;
2022-08-08 16:10:27 -04:00
btrfs_remove_free_space_cache ( cache ) ;
2015-09-29 20:50:36 -07:00
kfree ( cache - > free_space_ctl ) ;
kfree ( cache ) ;
}
2018-05-10 15:44:40 +03:00
void btrfs_init_dummy_trans ( struct btrfs_trans_handle * trans ,
struct btrfs_fs_info * fs_info )
2015-09-29 20:50:36 -07:00
{
memset ( trans , 0 , sizeof ( * trans ) ) ;
trans - > transid = 1 ;
trans - > type = __TRANS_DUMMY ;
2018-05-10 15:44:40 +03:00
trans - > fs_info = fs_info ;
2015-09-29 20:50:36 -07:00
}
2016-06-20 13:16:40 -04: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-05 12:51:12 -07:00
ret = btrfs_test_extent_map ( ) ;
2018-01-12 16:52:58 +00:00
2016-06-20 13:16:40 -04:00
out :
btrfs_destroy_test_fs ( ) ;
return ret ;
}