Skip to content

Commit c58de57

Browse files
committed
btrfs-progs: fix-data-checksum: introduce interactive mode
This mode will ask user for how to fix each block. User input can match the first letter or the whole action name to specify given action, the input is verified case insensitive. If no user input is provided, the default action is to ignore the corrupted block. If the input matches no action, a warning is outputted and user must retry until a valid input is provided. Signed-off-by: Qu Wenruo <[email protected]>
1 parent 108149b commit c58de57

File tree

4 files changed

+78
-4
lines changed

4 files changed

+78
-4
lines changed

Documentation/btrfs-rescue.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ fix-data-checksum <device>
6969
readonly mode, only scan and report for data checksum mismatch,
7070
do no repair
7171

72+
-i|--interactive
73+
interactive mode, ask for how to repair, ignore the error by default
74+
7275
.. _man-rescue-clear-ino-cache:
7376

7477
clear-ino-cache <device>

cmds/rescue-fix-data-checksum.c

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* Boston, MA 021110-1307, USA.
1515
*/
1616

17+
#include <ctype.h>
1718
#include "kerncompat.h"
1819
#include "kernel-shared/disk-io.h"
1920
#include "kernel-shared/ctree.h"
@@ -45,6 +46,21 @@ struct corrupted_block {
4546
unsigned long *error_mirror_bitmap;
4647
};
4748

49+
enum fix_data_checksum_action_value {
50+
ACTION_IGNORE,
51+
ACTION_LAST,
52+
};
53+
54+
static const struct fix_data_checksum_action {
55+
enum fix_data_checksum_action_value value;
56+
const char *string;
57+
} actions[] = {
58+
[ACTION_IGNORE] = {
59+
.value = ACTION_IGNORE,
60+
.string = "ignore",
61+
},
62+
};
63+
4864
static int global_repair_mode;
4965
LIST_HEAD(corrupted_blocks);
5066

@@ -241,10 +257,49 @@ static int iterate_csum_root(struct btrfs_fs_info *fs_info, struct btrfs_root *c
241257
return ret;
242258
}
243259

244-
static void report_corrupted_blocks(struct btrfs_fs_info *fs_info)
260+
#define ASK_ACTION_BUFSIZE (32)
261+
static enum fix_data_checksum_action_value ask_action()
262+
{
263+
char buf[ASK_ACTION_BUFSIZE] = { 0 };
264+
bool printed;
265+
266+
again:
267+
printed = false;
268+
for (int i = 0; i < ACTION_LAST; i++) {
269+
if (printed)
270+
printf("/");
271+
/* Mark Ignore as default */
272+
if (i == ACTION_IGNORE)
273+
printf("<<%c>>%s", toupper(actions[i].string[0]),
274+
actions[i].string + 1);
275+
else
276+
printf("<%c>%s", toupper(actions[i].string[0]),
277+
actions[i].string + 1);
278+
}
279+
printf(":");
280+
fflush(stdout);
281+
/* Default to Ignore if no action provided. */
282+
if (!fgets(buf, sizeof(buf) - 1, stdin))
283+
return ACTION_IGNORE;
284+
if (buf[0] == '\n')
285+
return ACTION_IGNORE;
286+
/* Check exact match or matching the initial letter. */
287+
for (int i = 0; i < ACTION_LAST; i++) {
288+
if (strncasecmp(buf, actions[i].string, 1) == 0 ||
289+
strncasecmp(buf, actions[i].string, ASK_ACTION_BUFSIZE) == 0)
290+
return actions[i].value;
291+
}
292+
/* No valid action found, retry. */
293+
warning("invalid action, please retry");
294+
goto again;
295+
}
296+
297+
static void report_corrupted_blocks(struct btrfs_fs_info *fs_info,
298+
enum btrfs_fix_data_checksum_mode mode)
245299
{
246300
struct corrupted_block *entry;
247301
struct btrfs_path path = { 0 };
302+
enum fix_data_checksum_action_value action;
248303

249304
if (list_empty(&corrupted_blocks)) {
250305
printf("No data checksum mismatch found\n");
@@ -277,6 +332,16 @@ static void report_corrupted_blocks(struct btrfs_fs_info *fs_info)
277332
error("failed to iterate involved files: %m");
278333
break;
279334
}
335+
switch (mode) {
336+
case BTRFS_FIX_DATA_CSUMS_INTERACTIVE:
337+
action = ask_action();
338+
UASSERT(action == ACTION_IGNORE);
339+
fallthrough;
340+
case BTRFS_FIX_DATA_CSUMS_READONLY:
341+
break;
342+
default:
343+
UASSERT(0);
344+
}
280345
}
281346
}
282347

@@ -333,7 +398,7 @@ int btrfs_recover_fix_data_checksum(const char *path,
333398
errno = -ret;
334399
error("failed to iterate csum tree: %m");
335400
}
336-
report_corrupted_blocks(fs_info);
401+
report_corrupted_blocks(fs_info, mode);
337402
out_close:
338403
free_corrupted_blocks();
339404
close_ctree_fs_info(fs_info);

cmds/rescue.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,8 @@ static const char * const cmd_rescue_fix_data_checksum_usage[] = {
280280
"btrfs rescue fix-data-checksum <device>",
281281
"Fix data checksum mismatches.",
282282
"",
283-
OPTLINE("-r", "readonly mode, only report errors without repair"),
283+
OPTLINE("-r|--readonly", "readonly mode, only report errors without repair"),
284+
OPTLINE("-i|--interactive", "interactive mode, ignore the error by default."),
284285
HELPINFO_INSERT_GLOBALS,
285286
HELPINFO_INSERT_VERBOSE,
286287
NULL
@@ -298,15 +299,19 @@ static int cmd_rescue_fix_data_checksum(const struct cmd_struct *cmd,
298299
enum { GETOPT_VAL_DRYRUN = GETOPT_VAL_FIRST, };
299300
static const struct option long_options [] = {
300301
{"readonly", no_argument, NULL, 'r'},
302+
{"interactive", no_argument, NULL, 'i'},
301303
{"NULL", 0, NULL, 0},
302304
};
303-
c = getopt_long(argc, argv, "r", long_options, NULL);
305+
c = getopt_long(argc, argv, "ri", long_options, NULL);
304306
if (c < 0)
305307
break;
306308
switch (c) {
307309
case 'r':
308310
mode = BTRFS_FIX_DATA_CSUMS_READONLY;
309311
break;
312+
case 'i':
313+
mode = BTRFS_FIX_DATA_CSUMS_INTERACTIVE;
314+
break;
310315
default:
311316
usage_unknown_option(cmd, argv);
312317
}

cmds/rescue.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
enum btrfs_fix_data_checksum_mode {
2424
BTRFS_FIX_DATA_CSUMS_READONLY,
25+
BTRFS_FIX_DATA_CSUMS_INTERACTIVE,
2526
BTRFS_FIX_DATA_CSUMS_LAST,
2627
};
2728

0 commit comments

Comments
 (0)