From 853b7393c20d5e129f2b16719102a05bbb5dc36f Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sat, 15 Apr 2023 14:26:14 -0400 Subject: [PATCH] bcachefs: Allow answering y or n to all fsck errors of given type This changes the ask_yn() function used by fsck to accept Y or N, meaning yes or no for all errors of a given type. With this, the user can be prompted only for distinct error types - useful when a filesystem has lots of errors. Signed-off-by: Kent Overstreet --- fs/bcachefs/error.c | 63 ++++++++++++++++++++++++++++++++++++++++++--- fs/bcachefs/error.h | 1 + 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/fs/bcachefs/error.c b/fs/bcachefs/error.c index 1dae649ff0e2..aa640284ed19 100644 --- a/fs/bcachefs/error.c +++ b/fs/bcachefs/error.c @@ -65,10 +65,51 @@ void bch2_io_error(struct bch_dev *ca) //queue_work(system_long_wq, &ca->io_error_work); } +enum ask_yn { + YN_NO, + YN_YES, + YN_ALLNO, + YN_ALLYES, +}; + #ifdef __KERNEL__ -#define ask_yn() false +#define bch2_fsck_ask_yn() YN_NO #else + #include "tools-util.h" + +enum ask_yn bch2_fsck_ask_yn(void) +{ + char *buf = NULL; + size_t buflen = 0; + bool ret; + + while (true) { + fputs(" (y,n,Y,N) ", stdout); + fflush(stdout); + + if (getline(&buf, &buflen, stdin) < 0) + die("error reading from standard input"); + + if (strlen(buf) != 1) + continue; + + switch (buf[0]) { + case 'n': + return YN_NO; + case 'y': + return YN_YES; + case 'N': + return YN_ALLNO; + case 'Y': + return YN_ALLYES; + } + } + + free(buf); + return ret; +} + #endif static struct fsck_err_state *fsck_err_get(struct bch_fs *c, const char *fmt) @@ -161,14 +202,28 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...) prt_str(out, ", exiting"); ret = -BCH_ERR_fsck_errors_not_fixed; } else if (flags & FSCK_CAN_FIX) { - if (c->opts.fix_errors == FSCK_OPT_ASK) { + int fix = s && s->fix + ? s->fix + : c->opts.fix_errors; + + if (fix == FSCK_OPT_ASK) { + int ask; + prt_str(out, ": fix?"); bch2_print_string_as_lines(KERN_ERR, out->buf); print = false; - ret = ask_yn() + + ask = bch2_fsck_ask_yn(); + + if (ask >= YN_ALLNO && s) + s->fix = ask == YN_ALLNO + ? FSCK_OPT_NO + : FSCK_OPT_YES; + + ret = ask & 1 ? -BCH_ERR_fsck_fix : -BCH_ERR_fsck_ignore; - } else if (c->opts.fix_errors == FSCK_OPT_YES || + } else if (fix == FSCK_OPT_YES || (c->opts.nochanges && !(flags & FSCK_CAN_IGNORE))) { prt_str(out, ", fixing"); diff --git a/fs/bcachefs/error.h b/fs/bcachefs/error.h index 91c7e4ee8f72..edf12443822c 100644 --- a/fs/bcachefs/error.h +++ b/fs/bcachefs/error.h @@ -104,6 +104,7 @@ struct fsck_err_state { u64 nr; bool ratelimited; int ret; + int fix; char *last_msg; };