aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLu Fengqi <lufq.fnst@cn.fujitsu.com>2016-04-24 15:47:12 +0800
committerDavid Sterba <dsterba@suse.com>2016-07-29 17:58:20 +0200
commit80f38ed1be3b6417af3a53180ac043f7237b8464 (patch)
treecfb1bc490be3df87a39b0ad516996fbde260a1b7
parent72f9336819edb3dcdcc5b46996c91e2707cdaabd (diff)
downloadbtrfs-progs-foreign/qu/fsck-lowmem-v2.1-fixups.tar.gz
btrfs-progs-foreign/qu/fsck-lowmem-v2.1-fixups.tar.xz
btrfs-progs-foreign/qu/fsck-lowmem-v2.1-fixups.zip
btrfs-progs: check: introduce low memory modeforeign/qu/fsck-lowmem-v2.1-fixups
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>
-rw-r--r--Documentation/btrfs-check.asciidoc6
-rw-r--r--cmds-check.c80
2 files changed, 84 insertions, 2 deletions
diff --git a/Documentation/btrfs-check.asciidoc b/Documentation/btrfs-check.asciidoc
index 74a2ad2..4e27863 100644
--- a/Documentation/btrfs-check.asciidoc
+++ b/Documentation/btrfs-check.asciidoc
@@ -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
diff --git a/cmds-check.c b/cmds-check.c
index 352036a..dd1b708 100644
--- a/cmds-check.c
+++ b/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;
@@ -9927,6 +9928,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)
{
@@ -11043,6 +11101,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>",
@@ -11075,7 +11134,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 },
@@ -11093,6 +11153,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}
};
@@ -11157,6 +11219,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;
}
}
@@ -11174,6 +11239,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);
@@ -11297,7 +11370,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");