summaryrefslogtreecommitdiff
path: root/check
diff options
context:
space:
mode:
Diffstat (limited to 'check')
-rw-r--r--check/main.c182
-rw-r--r--check/mode-common.h20
-rw-r--r--check/mode-lowmem.c1
3 files changed, 141 insertions, 62 deletions
diff --git a/check/main.c b/check/main.c
index ceb6d8f5..f8abbd36 100644
--- a/check/main.c
+++ b/check/main.c
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <getopt.h>
#include <uuid/uuid.h>
+#include <time.h>
#include "ctree.h"
#include "volumes.h"
#include "repair.h"
@@ -47,20 +48,6 @@
#include "check/mode-original.h"
#include "check/mode-lowmem.h"
-enum task_position {
- TASK_EXTENTS,
- TASK_FREE_SPACE,
- TASK_FS_ROOTS,
- TASK_NOTHING, /* have to be the last element */
-};
-
-struct task_ctx {
- int progress_enabled;
- enum task_position tp;
-
- struct task_info *info;
-};
-
u64 bytes_used = 0;
u64 total_csum_bytes = 0;
u64 total_btree_bytes = 0;
@@ -72,6 +59,7 @@ u64 data_bytes_referenced = 0;
LIST_HEAD(duplicate_extents);
LIST_HEAD(delete_items);
int no_holes = 0;
+static int is_free_space_tree = 0;
int init_extent_tree = 0;
int check_data_csum = 0;
struct btrfs_fs_info *global_info;
@@ -173,28 +161,55 @@ static int compare_extent_backref(struct rb_node *node1, struct rb_node *node2)
return compare_tree_backref(node1, node2);
}
+static void print_status_check_line(void *p)
+{
+ struct task_ctx *priv = p;
+ const char *task_position_string[] = {
+ "[1/7] checking root items ",
+ "[2/7] checking extents ",
+ is_free_space_tree ?
+ "[3/7] checking free space tree " :
+ "[3/7] checking free space cache ",
+ "[4/7] checking fs roots ",
+ check_data_csum ?
+ "[5/7] checking csums against data " :
+ "[5/7] checking csums (without verifying data) ",
+ "[6/7] checking root refs ",
+ "[7/7] checking quota groups ",
+ };
+ time_t elapsed;
+ int hours;
+ int minutes;
+ int seconds;
+
+ elapsed = time(NULL) - priv->start_time;
+ hours = elapsed / 3600;
+ elapsed -= hours * 3600;
+ minutes = elapsed / 60;
+ elapsed -= minutes * 60;
+ seconds = elapsed;
+
+ printf("%s (%d:%02d:%02d elapsed", task_position_string[priv->tp],
+ hours, minutes, seconds);
+ if (priv->item_count > 0)
+ printf(", %llu items checked)\r", priv->item_count);
+ else
+ printf(")\r");
+ fflush(stdout);
+}
static void *print_status_check(void *p)
{
struct task_ctx *priv = p;
- const char work_indicator[] = { '.', 'o', 'O', 'o' };
- uint32_t count = 0;
- static char *task_position_string[] = {
- "checking extents",
- "checking free space cache",
- "checking fs roots",
- };
- task_period_start(priv->info, 1000 /* 1s */);
+ /* 1 second */
+ task_period_start(priv->info, 1000);
if (priv->tp == TASK_NOTHING)
return NULL;
while (1) {
- printf("%s [%c]\r", task_position_string[priv->tp],
- work_indicator[count % 4]);
- count++;
- fflush(stdout);
+ print_status_check_line(p);
task_period_wait(priv->info);
}
return NULL;
@@ -202,6 +217,7 @@ static void *print_status_check(void *p)
static int print_status_return(void *p)
{
+ print_status_check_line(p);
printf("\n");
fflush(stdout);
@@ -2985,6 +3001,7 @@ static int check_root_refs(struct btrfs_root *root,
loop = 0;
cache = search_cache_extent(root_cache, 0);
while (1) {
+ ctx.item_count++;
if (!cache)
break;
rec = container_of(cache, struct root_record, cache);
@@ -3306,6 +3323,7 @@ static int check_fs_root(struct btrfs_root *root,
}
while (1) {
+ ctx.item_count++;
wret = walk_down_tree(root, &path, wc, &level, &nrefs);
if (wret < 0)
ret = wret;
@@ -3383,11 +3401,6 @@ static int check_fs_roots(struct btrfs_fs_info *fs_info,
int ret;
int err = 0;
- if (ctx.progress_enabled) {
- ctx.tp = TASK_FS_ROOTS;
- task_start(ctx.info);
- }
-
/*
* Just in case we made any changes to the extent tree that weren't
* reflected into the free space cache yet.
@@ -3464,8 +3477,6 @@ out:
if (!cache_tree_empty(&wc.shared))
fprintf(stderr, "warning line %d\n", __LINE__);
- task_stop(ctx.info);
-
return err;
}
@@ -3534,8 +3545,6 @@ static int do_check_fs_roots(struct btrfs_fs_info *fs_info,
{
int ret;
- if (!ctx.progress_enabled)
- fprintf(stderr, "checking fs roots\n");
if (check_mode == CHECK_MODE_LOWMEM)
ret = check_fs_roots_lowmem(fs_info);
else
@@ -5377,12 +5386,8 @@ static int check_space_cache(struct btrfs_root *root)
return 0;
}
- if (ctx.progress_enabled) {
- ctx.tp = TASK_FREE_SPACE;
- task_start(ctx.info);
- }
-
while (1) {
+ ctx.item_count++;
cache = btrfs_lookup_first_block_group(root->fs_info, start);
if (!cache)
break;
@@ -5431,8 +5436,6 @@ static int check_space_cache(struct btrfs_root *root)
}
}
- task_stop(ctx.info);
-
return error ? -EINVAL : 0;
}
@@ -5702,6 +5705,7 @@ static int check_csums(struct btrfs_root *root)
}
while (1) {
+ ctx.item_count++;
if (path.slots[0] >= btrfs_header_nritems(path.nodes[0])) {
ret = btrfs_next_leaf(root, &path);
if (ret < 0) {
@@ -8094,6 +8098,7 @@ static int deal_root_from_list(struct list_head *list,
* can maximize readahead.
*/
while (1) {
+ ctx.item_count++;
ret = run_next_block(root, bits, bits_nr, &last,
pending, seen, reada, nodes,
extent_cache, chunk_cache,
@@ -8257,11 +8262,6 @@ static int check_chunks_and_extents(struct btrfs_fs_info *fs_info)
exit(1);
}
- if (ctx.progress_enabled) {
- ctx.tp = TASK_EXTENTS;
- task_start(ctx.info);
- }
-
again:
root1 = fs_info->tree_root;
level = btrfs_header_level(root1->node);
@@ -8324,7 +8324,6 @@ again:
ret = err;
out:
- task_stop(ctx.info);
if (repair) {
free_corrupt_blocks_tree(fs_info->corrupt_blocks);
extent_io_tree_cleanup(&excluded_extents);
@@ -8366,8 +8365,6 @@ static int do_check_chunks_and_extents(struct btrfs_fs_info *fs_info)
{
int ret;
- if (!ctx.progress_enabled)
- fprintf(stderr, "checking extents\n");
if (check_mode == CHECK_MODE_LOWMEM)
ret = check_chunks_and_extents_lowmem(fs_info);
else
@@ -9097,6 +9094,7 @@ static int build_roots_info_cache(struct btrfs_fs_info *info)
struct cache_extent *entry;
struct root_item_info *rii;
+ ctx.item_count++;
if (slot >= btrfs_header_nritems(leaf)) {
ret = btrfs_next_leaf(info->extent_root, &path);
if (ret < 0) {
@@ -9635,6 +9633,8 @@ int cmd_check(int argc, char **argv)
if (repair && check_mode == CHECK_MODE_LOWMEM)
warning("low-memory mode repair support is only partial");
+ printf("Opening filesystem to check...\n");
+
radix_tree_init();
cache_tree_init(&root_cache);
@@ -9808,7 +9808,14 @@ int cmd_check(int argc, char **argv)
}
if (!init_extent_tree) {
+ if (!ctx.progress_enabled) {
+ fprintf(stderr, "[1/7] checking root items\n");
+ } else {
+ ctx.tp = TASK_ROOT_ITEMS;
+ task_start(ctx.info, &ctx.start_time, &ctx.item_count);
+ }
ret = repair_root_items(info);
+ task_stop(ctx.info);
if (ret < 0) {
err = !!ret;
error("failed to repair root items: %s", strerror(-ret));
@@ -9827,9 +9834,18 @@ int cmd_check(int argc, char **argv)
err |= ret;
goto close_out;
}
+ } else {
+ fprintf(stderr, "[1/7] checking root items... skipped\n");
}
+ if (!ctx.progress_enabled) {
+ fprintf(stderr, "[2/7] checking extents\n");
+ } else {
+ ctx.tp = TASK_EXTENTS;
+ task_start(ctx.info, &ctx.start_time, &ctx.item_count);
+ }
ret = do_check_chunks_and_extents(info);
+ task_stop(ctx.info);
err |= !!ret;
if (ret)
error(
@@ -9838,16 +9854,23 @@ int cmd_check(int argc, char **argv)
/* Only re-check super size after we checked and repaired the fs */
err |= !is_super_size_valid(info);
+ is_free_space_tree = btrfs_fs_compat_ro(info, FREE_SPACE_TREE);
+
if (!ctx.progress_enabled) {
- if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE))
- fprintf(stderr, "checking free space tree\n");
+ if (is_free_space_tree)
+ fprintf(stderr, "[3/7] checking free space tree\n");
else
- fprintf(stderr, "checking free space cache\n");
+ fprintf(stderr, "[3/7] checking free space cache\n");
+ } else {
+ ctx.tp = TASK_FREE_SPACE;
+ task_start(ctx.info, &ctx.start_time, &ctx.item_count);
}
+
ret = check_space_cache(root);
+ task_stop(ctx.info);
err |= !!ret;
if (ret) {
- if (btrfs_fs_compat_ro(info, FREE_SPACE_TREE))
+ if (is_free_space_tree)
error("errors found in free space tree");
else
error("errors found in free space cache");
@@ -9861,19 +9884,34 @@ int cmd_check(int argc, char **argv)
* ignore it when this happens.
*/
no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES);
+ if (!ctx.progress_enabled) {
+ fprintf(stderr, "[4/7] checking fs roots\n");
+ } else {
+ ctx.tp = TASK_FS_ROOTS;
+ task_start(ctx.info, &ctx.start_time, &ctx.item_count);
+ }
+
ret = do_check_fs_roots(info, &root_cache);
+ task_stop(ctx.info);
err |= !!ret;
if (ret) {
error("errors found in fs roots");
goto out;
}
- if (check_data_csum)
- fprintf(stderr, "checking csums against data\n");
- else
- fprintf(stderr,
- "checking only csum items (without verifying data)\n");
+ if (!ctx.progress_enabled) {
+ if (check_data_csum)
+ fprintf(stderr, "[5/7] checking csums against data\n");
+ else
+ fprintf(stderr,
+ "[5/7] checking only csums items (without verifying data)\n");
+ } else {
+ ctx.tp = TASK_CSUMS;
+ task_start(ctx.info, &ctx.start_time, &ctx.item_count);
+ }
+
ret = check_csums(root);
+ task_stop(ctx.info);
/*
* Data csum error is not fatal, and it may indicate more serious
* corruption, continue checking.
@@ -9882,15 +9920,25 @@ int cmd_check(int argc, char **argv)
error("errors found in csum tree");
err |= !!ret;
- fprintf(stderr, "checking root refs\n");
/* For low memory mode, check_fs_roots_v2 handles root refs */
- if (check_mode != CHECK_MODE_LOWMEM) {
+ if (check_mode != CHECK_MODE_LOWMEM) {
+ if (!ctx.progress_enabled) {
+ fprintf(stderr, "[6/7] checking root refs\n");
+ } else {
+ ctx.tp = TASK_ROOT_REFS;
+ task_start(ctx.info, &ctx.start_time, &ctx.item_count);
+ }
+
ret = check_root_refs(root, &root_cache);
+ task_stop(ctx.info);
err |= !!ret;
if (ret) {
error("errors found in root refs");
goto out;
}
+ } else {
+ fprintf(stderr,
+ "[6/7] checking root refs done with fs roots in lowmem mode, skipping\n");
}
while (repair && !list_empty(&root->fs_info->recow_ebs)) {
@@ -9920,8 +9968,15 @@ int cmd_check(int argc, char **argv)
}
if (info->quota_enabled) {
- fprintf(stderr, "checking quota groups\n");
+ qgroup_set_item_count_ptr(&ctx.item_count);
+ if (!ctx.progress_enabled) {
+ fprintf(stderr, "[7/7] checking quota groups\n");
+ } else {
+ ctx.tp = TASK_QGROUPS;
+ task_start(ctx.info, &ctx.start_time, &ctx.item_count);
+ }
ret = qgroup_verify_all(info);
+ task_stop(ctx.info);
err |= !!ret;
if (ret) {
error("failed to check quota groups");
@@ -9936,6 +9991,9 @@ int cmd_check(int argc, char **argv)
if (qgroup_report_ret && (!qgroups_repaired || ret))
err |= qgroup_report_ret;
ret = 0;
+ } else {
+ fprintf(stderr,
+ "[7/7] checking quota groups skipped (not enabled on this FS)\n");
}
if (!list_empty(&root->fs_info->recow_ebs)) {
diff --git a/check/mode-common.h b/check/mode-common.h
index a4748578..6b05f8ba 100644
--- a/check/mode-common.h
+++ b/check/mode-common.h
@@ -38,6 +38,26 @@ struct node_refs {
int full_backref[BTRFS_MAX_LEVEL];
};
+enum task_position {
+ TASK_ROOT_ITEMS,
+ TASK_EXTENTS,
+ TASK_FREE_SPACE,
+ TASK_FS_ROOTS,
+ TASK_CSUMS,
+ TASK_ROOT_REFS,
+ TASK_QGROUPS,
+ TASK_NOTHING, /* has to be the last element */
+};
+
+struct task_ctx {
+ int progress_enabled;
+ enum task_position tp;
+ time_t start_time;
+ u64 item_count;
+
+ struct task_info *info;
+};
+
extern u64 bytes_used;
extern u64 total_csum_bytes;
extern u64 total_btree_bytes;
diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c
index 224129d8..1bce44f5 100644
--- a/check/mode-lowmem.c
+++ b/check/mode-lowmem.c
@@ -4804,6 +4804,7 @@ static int check_btrfs_root(struct btrfs_root *root, int check_all)
}
while (1) {
+ ctx.item_count++;
ret = walk_down_tree(root, &path, &level, &nrefs, check_all);
if (ret > 0)