btrfs-progs: check: introduce low memory mode
Introduce a new fsck mode: low memory mode. Old btrfsck is working efficiently but uses some memory for each extent item. This method will ensure extents are only iterated once at extent/chunk tree check process. But since it uses some memory for each extent item, for a large fs with several TB metadata, this can easily eat up memory and cause OOM. To handle such limitation and improve scalability, the new low-memory mode will not use any heap memory to record which extent is checked. Instead it will use extent backref to avoid most of uneeded checks on shared fs/subvolume tree blocks. And with the use forward and backward reference cross check, we can also ensure every tree block is at least checked once. Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com> Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Reviewed-by: Josef Bacik <jbacik@fb.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
dad817d3ba
commit
bfecd8bd6a
2 changed files with 84 additions and 2 deletions
|
@ -93,6 +93,12 @@ build the extent tree from scratch
|
|||
+
|
||||
NOTE: Do not use unless you know what you're doing.
|
||||
|
||||
--low-memory::
|
||||
check fs in low memory usage mode(experimental)
|
||||
May takes longer time than normal check.
|
||||
+
|
||||
NOTE: Doesn't work with '--repair' option yet.
|
||||
|
||||
EXIT STATUS
|
||||
-----------
|
||||
*btrfs check* returns a zero exit status if it succeeds. Non zero is
|
||||
|
|
80
cmds-check.c
80
cmds-check.c
|
@ -70,6 +70,7 @@ static LIST_HEAD(delete_items);
|
|||
static int no_holes = 0;
|
||||
static int init_extent_tree = 0;
|
||||
static int check_data_csum = 0;
|
||||
static int low_memory = 0;
|
||||
static struct btrfs_fs_info *global_info;
|
||||
static struct task_ctx ctx = { 0 };
|
||||
static struct cache_tree *roots_info_cache = NULL;
|
||||
|
@ -9952,6 +9953,63 @@ static int traverse_tree_block(struct btrfs_root *root,
|
|||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Low memory usage version check_chunks_and_extents.
|
||||
*/
|
||||
static int check_chunks_and_extents_v2(struct btrfs_root *root)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_root *root1;
|
||||
struct btrfs_root *cur_root;
|
||||
int err = 0;
|
||||
int ret;
|
||||
|
||||
root1 = root->fs_info->chunk_root;
|
||||
ret = traverse_tree_block(root1, root1->node);
|
||||
err |= ret;
|
||||
|
||||
root1 = root->fs_info->tree_root;
|
||||
ret = traverse_tree_block(root1, root1->node);
|
||||
err |= ret;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
key.objectid = BTRFS_EXTENT_TREE_OBJECTID;
|
||||
key.offset = 0;
|
||||
key.type = BTRFS_ROOT_ITEM_KEY;
|
||||
|
||||
ret = btrfs_search_slot(NULL, root1, &key, &path, 0, 0);
|
||||
if (ret) {
|
||||
error("cannot find extent treet in tree_root");
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
|
||||
if (key.type != BTRFS_ROOT_ITEM_KEY)
|
||||
goto next;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
cur_root = btrfs_read_fs_root(root->fs_info, &key);
|
||||
if (IS_ERR(cur_root) || !cur_root) {
|
||||
error("failed to read tree: %lld", key.objectid);
|
||||
goto next;
|
||||
}
|
||||
|
||||
ret = traverse_tree_block(cur_root, cur_root->node);
|
||||
err |= ret;
|
||||
|
||||
next:
|
||||
ret = btrfs_next_item(root1, &path);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
btrfs_release_path(&path);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, int overwrite)
|
||||
{
|
||||
|
@ -11068,6 +11126,7 @@ const char * const cmd_check_usage[] = {
|
|||
"--readonly run in read-only mode (default)",
|
||||
"--init-csum-tree create a new CRC tree",
|
||||
"--init-extent-tree create a new extent tree",
|
||||
"--low-memory check in low memory usage mode(experimental)",
|
||||
"--check-data-csum verify checksums of data blocks",
|
||||
"-Q|--qgroup-report print a report on qgroup consistency",
|
||||
"-E|--subvol-extents <subvolid>",
|
||||
|
@ -11100,7 +11159,8 @@ int cmd_check(int argc, char **argv)
|
|||
int c;
|
||||
enum { GETOPT_VAL_REPAIR = 257, GETOPT_VAL_INIT_CSUM,
|
||||
GETOPT_VAL_INIT_EXTENT, GETOPT_VAL_CHECK_CSUM,
|
||||
GETOPT_VAL_READONLY, GETOPT_VAL_CHUNK_TREE };
|
||||
GETOPT_VAL_READONLY, GETOPT_VAL_CHUNK_TREE,
|
||||
GETOPT_VAL_LOW_MEMORY };
|
||||
static const struct option long_options[] = {
|
||||
{ "super", required_argument, NULL, 's' },
|
||||
{ "repair", no_argument, NULL, GETOPT_VAL_REPAIR },
|
||||
|
@ -11118,6 +11178,8 @@ int cmd_check(int argc, char **argv)
|
|||
{ "chunk-root", required_argument, NULL,
|
||||
GETOPT_VAL_CHUNK_TREE },
|
||||
{ "progress", no_argument, NULL, 'p' },
|
||||
{ "low-memory", no_argument, NULL,
|
||||
GETOPT_VAL_LOW_MEMORY },
|
||||
{ NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
|
@ -11182,6 +11244,9 @@ int cmd_check(int argc, char **argv)
|
|||
case GETOPT_VAL_CHECK_CSUM:
|
||||
check_data_csum = 1;
|
||||
break;
|
||||
case GETOPT_VAL_LOW_MEMORY:
|
||||
low_memory = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11199,6 +11264,14 @@ int cmd_check(int argc, char **argv)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Not supported yet
|
||||
*/
|
||||
if (repair && low_memory) {
|
||||
error("Low memory mode doesn't support repair yet");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
radix_tree_init();
|
||||
cache_tree_init(&root_cache);
|
||||
|
||||
|
@ -11322,7 +11395,10 @@ int cmd_check(int argc, char **argv)
|
|||
|
||||
if (!ctx.progress_enabled)
|
||||
fprintf(stderr, "checking extents\n");
|
||||
ret = check_chunks_and_extents(root);
|
||||
if (low_memory)
|
||||
ret = check_chunks_and_extents_v2(root);
|
||||
else
|
||||
ret = check_chunks_and_extents(root);
|
||||
if (ret)
|
||||
fprintf(stderr, "Errors found in extent allocation tree or chunk allocation\n");
|
||||
|
||||
|
|
Loading…
Reference in a new issue