Commit 889fb3dc authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Unlock trans when waiting for user input in fsck



We can't hold locks while waiting for user input, that's a deadlock.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 747d1d6c
Loading
Loading
Loading
Loading
+28 −4
Original line number Diff line number Diff line
@@ -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