bcachefs: Allow answering y or n to all fsck errors of given type
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 15 Apr 2023 18:26:14 +0000 (14:26 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:10:00 +0000 (17:10 -0400)
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 <kent.overstreet@linux.dev>
fs/bcachefs/error.c
fs/bcachefs/error.h

index 1dae649ff0e223386eefe0e1992ddd564f020197..aa640284ed1990e575917229ba6340a0546fde08 100644 (file)
@@ -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");
index 91c7e4ee8f7266ea193414461a145236e7dc5277..edf12443822c2599fe99651b3fd1855d40f18c00 100644 (file)
@@ -104,6 +104,7 @@ struct fsck_err_state {
        u64                     nr;
        bool                    ratelimited;
        int                     ret;
+       int                     fix;
        char                    *last_msg;
 };