]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bcachefs: Unlock trans when waiting for user input in fsck
authorKent Overstreet <kent.overstreet@linux.dev>
Thu, 30 May 2024 01:14:40 +0000 (21:14 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 14 Jul 2024 23:00:14 +0000 (19:00 -0400)
We can't hold locks while waiting for user input, that's a deadlock.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/error.c

index cfe7912159154dc05a25f4835353814955f5291a..a62b63108820033eaa3753cf111705eebd24b23d 100644 (file)
@@ -99,7 +99,7 @@ static enum ask_yn parse_yn_response(char *buf)
 }
 
 #ifdef __KERNEL__
-static enum ask_yn bch2_fsck_ask_yn(struct bch_fs *c)
+static enum ask_yn bch2_fsck_ask_yn(struct bch_fs *c, struct btree_trans *trans)
 {
        struct stdio_redirect *stdio = c->stdio;
 
@@ -109,17 +109,33 @@ static enum ask_yn bch2_fsck_ask_yn(struct bch_fs *c)
        if (!stdio)
                return YN_NO;
 
+       if (trans)
+               bch2_trans_unlock(trans);
+
+       unsigned long unlock_long_at = trans ? jiffies + HZ * 2 : 0;
        darray_char line = {};
        int ret;
 
        do {
+               unsigned long t;
                bch2_print(c, " (y,n, or Y,N for all errors of this type) ");
+rewait:
+               t = unlock_long_at
+                       ? max_t(long, unlock_long_at - jiffies, 0)
+                       : MAX_SCHEDULE_TIMEOUT;
+
+               int r = bch2_stdio_redirect_readline_timeout(stdio, &line, t);
+               if (r == -ETIME) {
+                       bch2_trans_unlock_long(trans);
+                       unlock_long_at = 0;
+                       goto rewait;
+               }
 
-               int r = bch2_stdio_redirect_readline(stdio, &line);
                if (r < 0) {
                        ret = YN_NO;
                        break;
                }
+
                darray_last(line) = '\0';
        } while ((ret = parse_yn_response(line.data)) < 0);
 
@@ -130,7 +146,7 @@ static enum ask_yn bch2_fsck_ask_yn(struct bch_fs *c)
 
 #include "tools-util.h"
 
-static enum ask_yn bch2_fsck_ask_yn(struct bch_fs *c)
+static enum ask_yn bch2_fsck_ask_yn(struct bch_fs *c, struct btree_trans *trans)
 {
        char *buf = NULL;
        size_t buflen = 0;
@@ -326,7 +342,15 @@ int __bch2_fsck_err(struct bch_fs *c,
                                bch2_print_string_as_lines(KERN_ERR, out->buf);
                        print = false;
 
-                       int ask = bch2_fsck_ask_yn(c);
+                       int ask = bch2_fsck_ask_yn(c, trans);
+
+                       if (trans) {
+                               ret = bch2_trans_relock(trans);
+                               if (ret) {
+                                       mutex_unlock(&c->fsck_error_msgs_lock);
+                                       goto err;
+                               }
+                       }
 
                        if (ask >= YN_ALLNO && s)
                                s->fix = ask == YN_ALLNO