mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	btrfs: Factor out tree roots initialization during mount
The code responsible for reading and initializing tree roots is scattered in open_ctree among 2 labels, emulating a loop. This is rather confusing to reason about. Instead, factor the code to a new function, init_tree_roots which implements the same logical flow. There are a couple of notable differences, namely: * Instead of using next_backup_root it's using the newly introduced read_backup_root. * If read_backup_root returns an error init_tree_roots propagates the error and there is no special handling of that case e.g. the code jumps straight to 'fail_tree_roots' label. The old code, however, was (erroneously) jumping to 'fail_block_groups' label if next_backup_root did fail, this was unnecessary since the tree roots init logic doesn't modify the state of block groups. Signed-off-by: Nikolay Borisov <nborisov@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
		
							parent
							
								
									bd2336b2ac
								
							
						
					
					
						commit
						b8522a1e5f
					
				
					 1 changed files with 85 additions and 57 deletions
				
			
		| 
						 | 
					@ -2610,6 +2610,89 @@ static int btrfs_validate_write_super(struct btrfs_fs_info *fs_info,
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __cold init_tree_roots(struct btrfs_fs_info *fs_info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct btrfs_super_block *sb = fs_info->super_copy;
 | 
				
			||||||
 | 
						struct btrfs_root *tree_root = fs_info->tree_root;
 | 
				
			||||||
 | 
						bool handle_error = false;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; i++) {
 | 
				
			||||||
 | 
							u64 generation;
 | 
				
			||||||
 | 
							int level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (handle_error) {
 | 
				
			||||||
 | 
								if (!IS_ERR(tree_root->node))
 | 
				
			||||||
 | 
									free_extent_buffer(tree_root->node);
 | 
				
			||||||
 | 
								tree_root->node = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!btrfs_test_opt(fs_info, USEBACKUPROOT))
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								free_root_pointers(fs_info, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * Don't use the log in recovery mode, it won't be
 | 
				
			||||||
 | 
								 * valid
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								btrfs_set_super_log_root(sb, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* We can't trust the free space cache either */
 | 
				
			||||||
 | 
								btrfs_set_opt(fs_info->mount_opt, CLEAR_CACHE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ret = read_backup_root(fs_info, i);
 | 
				
			||||||
 | 
								if (ret < 0)
 | 
				
			||||||
 | 
									return ret;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							generation = btrfs_super_generation(sb);
 | 
				
			||||||
 | 
							level = btrfs_super_root_level(sb);
 | 
				
			||||||
 | 
							tree_root->node = read_tree_block(fs_info, btrfs_super_root(sb),
 | 
				
			||||||
 | 
											  generation, level, NULL);
 | 
				
			||||||
 | 
							if (IS_ERR(tree_root->node) ||
 | 
				
			||||||
 | 
							    !extent_buffer_uptodate(tree_root->node)) {
 | 
				
			||||||
 | 
								handle_error = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (IS_ERR(tree_root->node))
 | 
				
			||||||
 | 
									ret = PTR_ERR(tree_root->node);
 | 
				
			||||||
 | 
								else if (!extent_buffer_uptodate(tree_root->node))
 | 
				
			||||||
 | 
									ret = -EUCLEAN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								btrfs_warn(fs_info, "failed to read tree root");
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							btrfs_set_root_node(&tree_root->root_item, tree_root->node);
 | 
				
			||||||
 | 
							tree_root->commit_root = btrfs_root_node(tree_root);
 | 
				
			||||||
 | 
							btrfs_set_root_refs(&tree_root->root_item, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mutex_lock(&tree_root->objectid_mutex);
 | 
				
			||||||
 | 
							ret = btrfs_find_highest_objectid(tree_root,
 | 
				
			||||||
 | 
											&tree_root->highest_objectid);
 | 
				
			||||||
 | 
							if (ret < 0) {
 | 
				
			||||||
 | 
								mutex_unlock(&tree_root->objectid_mutex);
 | 
				
			||||||
 | 
								handle_error = true;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ASSERT(tree_root->highest_objectid <= BTRFS_LAST_FREE_OBJECTID);
 | 
				
			||||||
 | 
							mutex_unlock(&tree_root->objectid_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = btrfs_read_roots(fs_info);
 | 
				
			||||||
 | 
							if (ret < 0) {
 | 
				
			||||||
 | 
								handle_error = true;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* All successful */
 | 
				
			||||||
 | 
							fs_info->generation = generation;
 | 
				
			||||||
 | 
							fs_info->last_trans_committed = generation;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int __cold open_ctree(struct super_block *sb,
 | 
					int __cold open_ctree(struct super_block *sb,
 | 
				
			||||||
	       struct btrfs_fs_devices *fs_devices,
 | 
						       struct btrfs_fs_devices *fs_devices,
 | 
				
			||||||
	       char *options)
 | 
						       char *options)
 | 
				
			||||||
| 
						 | 
					@ -2628,8 +2711,6 @@ int __cold open_ctree(struct super_block *sb,
 | 
				
			||||||
	struct btrfs_root *chunk_root;
 | 
						struct btrfs_root *chunk_root;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
	int err = -EINVAL;
 | 
						int err = -EINVAL;
 | 
				
			||||||
	int num_backups_tried = 0;
 | 
					 | 
				
			||||||
	int backup_index = 0;
 | 
					 | 
				
			||||||
	int clear_free_space_tree = 0;
 | 
						int clear_free_space_tree = 0;
 | 
				
			||||||
	int level;
 | 
						int level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3051,44 +3132,9 @@ int __cold open_ctree(struct super_block *sb,
 | 
				
			||||||
		goto fail_tree_roots;
 | 
							goto fail_tree_roots;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
retry_root_backup:
 | 
						ret = init_tree_roots(fs_info);
 | 
				
			||||||
	generation = btrfs_super_generation(disk_super);
 | 
					 | 
				
			||||||
	level = btrfs_super_root_level(disk_super);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tree_root->node = read_tree_block(fs_info,
 | 
					 | 
				
			||||||
					  btrfs_super_root(disk_super),
 | 
					 | 
				
			||||||
					  generation, level, NULL);
 | 
					 | 
				
			||||||
	if (IS_ERR(tree_root->node) ||
 | 
					 | 
				
			||||||
	    !extent_buffer_uptodate(tree_root->node)) {
 | 
					 | 
				
			||||||
		btrfs_warn(fs_info, "failed to read tree root");
 | 
					 | 
				
			||||||
		if (!IS_ERR(tree_root->node))
 | 
					 | 
				
			||||||
			free_extent_buffer(tree_root->node);
 | 
					 | 
				
			||||||
		tree_root->node = NULL;
 | 
					 | 
				
			||||||
		goto recovery_tree_root;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	btrfs_set_root_node(&tree_root->root_item, tree_root->node);
 | 
					 | 
				
			||||||
	tree_root->commit_root = btrfs_root_node(tree_root);
 | 
					 | 
				
			||||||
	btrfs_set_root_refs(&tree_root->root_item, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_lock(&tree_root->objectid_mutex);
 | 
					 | 
				
			||||||
	ret = btrfs_find_highest_objectid(tree_root,
 | 
					 | 
				
			||||||
					&tree_root->highest_objectid);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		mutex_unlock(&tree_root->objectid_mutex);
 | 
					 | 
				
			||||||
		goto recovery_tree_root;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ASSERT(tree_root->highest_objectid <= BTRFS_LAST_FREE_OBJECTID);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_unlock(&tree_root->objectid_mutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = btrfs_read_roots(fs_info);
 | 
					 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto recovery_tree_root;
 | 
							goto fail_tree_roots;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	fs_info->generation = generation;
 | 
					 | 
				
			||||||
	fs_info->last_trans_committed = generation;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = btrfs_verify_dev_extents(fs_info);
 | 
						ret = btrfs_verify_dev_extents(fs_info);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
| 
						 | 
					@ -3383,24 +3429,6 @@ int __cold open_ctree(struct super_block *sb,
 | 
				
			||||||
	btrfs_free_stripe_hash_table(fs_info);
 | 
						btrfs_free_stripe_hash_table(fs_info);
 | 
				
			||||||
	btrfs_close_devices(fs_info->fs_devices);
 | 
						btrfs_close_devices(fs_info->fs_devices);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
 | 
					 | 
				
			||||||
recovery_tree_root:
 | 
					 | 
				
			||||||
	if (!btrfs_test_opt(fs_info, USEBACKUPROOT))
 | 
					 | 
				
			||||||
		goto fail_tree_roots;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free_root_pointers(fs_info, false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* don't use the log in recovery mode, it won't be valid */
 | 
					 | 
				
			||||||
	btrfs_set_super_log_root(disk_super, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* we can't trust the free space cache either */
 | 
					 | 
				
			||||||
	btrfs_set_opt(fs_info->mount_opt, CLEAR_CACHE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = next_root_backup(fs_info, fs_info->super_copy,
 | 
					 | 
				
			||||||
			       &num_backups_tried, &backup_index);
 | 
					 | 
				
			||||||
	if (ret == -1)
 | 
					 | 
				
			||||||
		goto fail_block_groups;
 | 
					 | 
				
			||||||
	goto retry_root_backup;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ALLOW_ERROR_INJECTION(open_ctree, ERRNO);
 | 
					ALLOW_ERROR_INJECTION(open_ctree, ERRNO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue