mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	btrfs: selftests: add delayed ref self test cases
The recent fix for a stupid mistake I made uncovered the fact that we don't have adequate testing in the delayed refs code, as it took a pretty extensive and long running stress test to uncover something that a unit test would have uncovered right away. Fix this by adding a delayed refs self test suite. This will validate that the btrfs_ref transformation does the correct thing, that we do the correct thing when merging delayed refs, and that we get the delayed refs in the order that we expect. These are all crucial to how the delayed refs operate. I introduced various bugs (including the original bug) into the delayed refs code to validate that these tests caught all of the shenanigans that I could think of. Reviewed-by: Boris Burkov <boris@bur.io> Signed-off-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
		
							parent
							
								
									5473aeedff
								
							
						
					
					
						commit
						2b34879d97
					
				
					 5 changed files with 1050 additions and 4 deletions
				
			
		|  | @ -44,4 +44,4 @@ btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \ | |||
| 	tests/extent-buffer-tests.o tests/btrfs-tests.o \
 | ||||
| 	tests/extent-io-tests.o tests/inode-tests.o tests/qgroup-tests.o \
 | ||||
| 	tests/free-space-tree-tests.o tests/extent-map-tests.o \
 | ||||
| 	tests/raid-stripe-tree-tests.o | ||||
| 	tests/raid-stripe-tree-tests.o tests/delayed-refs-tests.o | ||||
|  |  | |||
|  | @ -93,6 +93,9 @@ void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans) | |||
| 	u64 num_bytes; | ||||
| 	u64 reserved_bytes; | ||||
| 
 | ||||
| 	if (btrfs_is_testing(fs_info)) | ||||
| 		return; | ||||
| 
 | ||||
| 	num_bytes = btrfs_calc_delayed_ref_bytes(fs_info, trans->delayed_ref_updates); | ||||
| 	num_bytes += btrfs_calc_delayed_ref_csum_bytes(fs_info, | ||||
| 						       trans->delayed_ref_csum_deletions); | ||||
|  | @ -1260,6 +1263,7 @@ void btrfs_destroy_delayed_refs(struct btrfs_transaction *trans) | |||
| { | ||||
| 	struct btrfs_delayed_ref_root *delayed_refs = &trans->delayed_refs; | ||||
| 	struct btrfs_fs_info *fs_info = trans->fs_info; | ||||
| 	bool testing = btrfs_is_testing(fs_info); | ||||
| 
 | ||||
| 	spin_lock(&delayed_refs->lock); | ||||
| 	while (true) { | ||||
|  | @ -1289,7 +1293,7 @@ void btrfs_destroy_delayed_refs(struct btrfs_transaction *trans) | |||
| 		spin_unlock(&delayed_refs->lock); | ||||
| 		mutex_unlock(&head->mutex); | ||||
| 
 | ||||
| 		if (pin_bytes) { | ||||
| 		if (!testing && pin_bytes) { | ||||
| 			struct btrfs_block_group *bg; | ||||
| 
 | ||||
| 			bg = btrfs_lookup_block_group(fs_info, head->bytenr); | ||||
|  | @ -1321,12 +1325,15 @@ void btrfs_destroy_delayed_refs(struct btrfs_transaction *trans) | |||
| 			btrfs_error_unpin_extent_range(fs_info, head->bytenr, | ||||
| 				head->bytenr + head->num_bytes - 1); | ||||
| 		} | ||||
| 		btrfs_cleanup_ref_head_accounting(fs_info, delayed_refs, head); | ||||
| 		if (!testing) | ||||
| 			btrfs_cleanup_ref_head_accounting(fs_info, delayed_refs, head); | ||||
| 		btrfs_put_delayed_ref_head(head); | ||||
| 		cond_resched(); | ||||
| 		spin_lock(&delayed_refs->lock); | ||||
| 	} | ||||
| 	btrfs_qgroup_destroy_extent_records(trans); | ||||
| 
 | ||||
| 	if (!testing) | ||||
| 		btrfs_qgroup_destroy_extent_records(trans); | ||||
| 
 | ||||
| 	spin_unlock(&delayed_refs->lock); | ||||
| } | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ const char *test_error[] = { | |||
| 	[TEST_ALLOC_EXTENT_MAP]      = "cannot allocate extent map", | ||||
| 	[TEST_ALLOC_CHUNK_MAP]       = "cannot allocate chunk map", | ||||
| 	[TEST_ALLOC_IO_CONTEXT]	     = "cannot allocate io context", | ||||
| 	[TEST_ALLOC_TRANSACTION]     = "cannot allocate transaction", | ||||
| }; | ||||
| 
 | ||||
| static const struct super_operations btrfs_test_super_ops = { | ||||
|  | @ -142,6 +143,11 @@ struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(u32 nodesize, u32 sectorsize) | |||
| 	fs_info->nodesize = nodesize; | ||||
| 	fs_info->sectorsize = sectorsize; | ||||
| 	fs_info->sectorsize_bits = ilog2(sectorsize); | ||||
| 
 | ||||
| 	/* CRC32C csum size. */ | ||||
| 	fs_info->csum_size = 4; | ||||
| 	fs_info->csums_per_leaf = BTRFS_MAX_ITEM_SIZE(fs_info) / | ||||
| 		fs_info->csum_size; | ||||
| 	set_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state); | ||||
| 
 | ||||
| 	test_mnt->mnt_sb->s_fs_info = fs_info; | ||||
|  | @ -247,6 +253,15 @@ void btrfs_free_dummy_block_group(struct btrfs_block_group *cache) | |||
| 	kfree(cache); | ||||
| } | ||||
| 
 | ||||
| void btrfs_init_dummy_transaction(struct btrfs_transaction *trans, struct btrfs_fs_info *fs_info) | ||||
| { | ||||
| 	memset(trans, 0, sizeof(*trans)); | ||||
| 	trans->fs_info = fs_info; | ||||
| 	xa_init(&trans->delayed_refs.head_refs); | ||||
| 	xa_init(&trans->delayed_refs.dirty_extents); | ||||
| 	spin_lock_init(&trans->delayed_refs.lock); | ||||
| } | ||||
| 
 | ||||
| void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans, | ||||
| 			    struct btrfs_fs_info *fs_info) | ||||
| { | ||||
|  | @ -295,6 +310,9 @@ int btrfs_run_sanity_tests(void) | |||
| 			ret = btrfs_test_raid_stripe_tree(sectorsize, nodesize); | ||||
| 			if (ret) | ||||
| 				goto out; | ||||
| 			ret = btrfs_test_delayed_refs(sectorsize, nodesize); | ||||
| 			if (ret) | ||||
| 				goto out; | ||||
| 		} | ||||
| 	} | ||||
| 	ret = btrfs_test_extent_map(); | ||||
|  |  | |||
|  | @ -6,6 +6,8 @@ | |||
| #ifndef BTRFS_TESTS_H | ||||
| #define BTRFS_TESTS_H | ||||
| 
 | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS | ||||
| int btrfs_run_sanity_tests(void); | ||||
| 
 | ||||
|  | @ -25,12 +27,14 @@ enum { | |||
| 	TEST_ALLOC_EXTENT_MAP, | ||||
| 	TEST_ALLOC_CHUNK_MAP, | ||||
| 	TEST_ALLOC_IO_CONTEXT, | ||||
| 	TEST_ALLOC_TRANSACTION, | ||||
| }; | ||||
| 
 | ||||
| extern const char *test_error[]; | ||||
| 
 | ||||
| struct btrfs_root; | ||||
| struct btrfs_trans_handle; | ||||
| struct btrfs_transaction; | ||||
| 
 | ||||
| int btrfs_test_extent_buffer_operations(u32 sectorsize, u32 nodesize); | ||||
| int btrfs_test_free_space_cache(u32 sectorsize, u32 nodesize); | ||||
|  | @ -40,6 +44,7 @@ int btrfs_test_qgroups(u32 sectorsize, u32 nodesize); | |||
| int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize); | ||||
| int btrfs_test_raid_stripe_tree(u32 sectorsize, u32 nodesize); | ||||
| int btrfs_test_extent_map(void); | ||||
| int btrfs_test_delayed_refs(u32 sectorsize, u32 nodesize); | ||||
| struct inode *btrfs_new_test_inode(void); | ||||
| struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(u32 nodesize, u32 sectorsize); | ||||
| void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info); | ||||
|  | @ -49,6 +54,7 @@ btrfs_alloc_dummy_block_group(struct btrfs_fs_info *fs_info, unsigned long lengt | |||
| void btrfs_free_dummy_block_group(struct btrfs_block_group *cache); | ||||
| void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans, | ||||
| 			    struct btrfs_fs_info *fs_info); | ||||
| void btrfs_init_dummy_transaction(struct btrfs_transaction *trans, struct btrfs_fs_info *fs_info); | ||||
| struct btrfs_device *btrfs_alloc_dummy_device(struct btrfs_fs_info *fs_info); | ||||
| #else | ||||
| static inline int btrfs_run_sanity_tests(void) | ||||
|  |  | |||
							
								
								
									
										1015
									
								
								fs/btrfs/tests/delayed-refs-tests.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1015
									
								
								fs/btrfs/tests/delayed-refs-tests.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
		Reference in a new issue
	
	 Josef Bacik
						Josef Bacik