Commit 7337f9f1 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: bch2_count_fsck_err()



Factor out a helper from __bch2_fsck_err(), for counting the error in
the superblock and deciding whether to print or ratelimit - will be used
to replace some log_fsck_err() calls, where we want to lift out printing
the error message.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent b00750c2
Loading
Loading
Loading
Loading
+59 −37
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ bool __bch2_inconsistent_error(struct bch_fs *c, struct printbuf *out)
				   journal_cur_seq(&c->journal));
		return true;
	case BCH_ON_ERROR_panic:
		bch2_print_string_as_lines(KERN_ERR, out->buf);
		panic(bch2_fmt(c, "panic after error"));
		return true;
	default:
@@ -268,7 +269,8 @@ static enum ask_yn bch2_fsck_ask_yn(struct bch_fs *c, struct btree_trans *trans)

#endif

static struct fsck_err_state *fsck_err_get(struct bch_fs *c, const char *fmt)
static struct fsck_err_state *fsck_err_get(struct bch_fs *c,
					   enum bch_sb_error_id id)
{
	struct fsck_err_state *s;

@@ -276,7 +278,7 @@ static struct fsck_err_state *fsck_err_get(struct bch_fs *c, const char *fmt)
		return NULL;

	list_for_each_entry(s, &c->fsck_error_msgs, list)
		if (s->fmt == fmt) {
		if (s->id == id) {
			/*
			 * move it to the head of the list: repeated fsck errors
			 * are common
@@ -294,7 +296,7 @@ static struct fsck_err_state *fsck_err_get(struct bch_fs *c, const char *fmt)
	}

	INIT_LIST_HEAD(&s->list);
	s->fmt = fmt;
	s->id = id;
	list_add(&s->list, &c->fsck_error_msgs);
	return s;
}
@@ -344,15 +346,59 @@ static int do_fsck_ask_yn(struct bch_fs *c,
	return ask;
}

static struct fsck_err_state *count_fsck_err_locked(struct bch_fs *c,
			  enum bch_sb_error_id id, const char *msg,
			  bool *repeat, bool *print, bool *suppress)
{
	bch2_sb_error_count(c, id);

	struct fsck_err_state *s = fsck_err_get(c, id);
	if (s) {
		/*
		 * We may be called multiple times for the same error on
		 * transaction restart - this memoizes instead of asking the user
		 * multiple times for the same error:
		 */
		if (s->last_msg && !strcmp(msg, s->last_msg)) {
			*repeat = true;
			*print = false;
			return s;
		}

		kfree(s->last_msg);
		s->last_msg = kstrdup(msg, GFP_KERNEL);

		if (c->opts.ratelimit_errors &&
		    s->nr >= FSCK_ERR_RATELIMIT_NR) {
			if (s->nr == FSCK_ERR_RATELIMIT_NR)
				*suppress = true;
			else
				*print = false;
		}

		s->nr++;
	}
	return s;
}

void __bch2_count_fsck_err(struct bch_fs *c,
			   enum bch_sb_error_id id, const char *msg,
			   bool *repeat, bool *print, bool *suppress)
{
	bch2_sb_error_count(c, id);

	mutex_lock(&c->fsck_error_msgs_lock);
	count_fsck_err_locked(c, id, msg, repeat, print, suppress);
	mutex_unlock(&c->fsck_error_msgs_lock);
}

int __bch2_fsck_err(struct bch_fs *c,
		  struct btree_trans *trans,
		  enum bch_fsck_flags flags,
		  enum bch_sb_error_id err,
		  const char *fmt, ...)
{
	struct fsck_err_state *s = NULL;
	va_list args;
	bool print = true, suppressing = false, inconsistent = false, exiting = false;
	struct printbuf buf = PRINTBUF, *out = &buf;
	int ret = -BCH_ERR_fsck_ignore;
	const char *action_orig = "fix?", *action = action_orig;
@@ -387,8 +433,6 @@ int __bch2_fsck_err(struct bch_fs *c,
			? -BCH_ERR_fsck_fix
			: -BCH_ERR_fsck_ignore;

	bch2_sb_error_count(c, err);

	printbuf_indent_add_nextline(out, 2);

#ifdef BCACHEFS_LOG_PREFIX
@@ -414,37 +458,15 @@ int __bch2_fsck_err(struct bch_fs *c,
	}

	mutex_lock(&c->fsck_error_msgs_lock);
	s = fsck_err_get(c, fmt);
	if (s) {
		/*
		 * We may be called multiple times for the same error on
		 * transaction restart - this memoizes instead of asking the user
		 * multiple times for the same error:
		 */
		if (s->last_msg && !strcmp(buf.buf, s->last_msg)) {
	bool repeat = false, print = true, suppress = false;
	bool inconsistent = false, exiting = false;
	struct fsck_err_state *s =
		count_fsck_err_locked(c, err, buf.buf, &repeat, &print, &suppress);
	if (repeat) {
		ret = s->ret;
		goto err_unlock;
	}

		kfree(s->last_msg);
		s->last_msg = kstrdup(buf.buf, GFP_KERNEL);
		if (!s->last_msg) {
			ret = -ENOMEM;
			goto err_unlock;
		}

		if (c->opts.ratelimit_errors &&
		    !(flags & FSCK_NO_RATELIMIT) &&
		    s->nr >= FSCK_ERR_RATELIMIT_NR) {
			if (s->nr == FSCK_ERR_RATELIMIT_NR)
				suppressing = true;
			else
				print = false;
		}

		s->nr++;
	}

	if ((flags & FSCK_AUTOFIX) &&
	    (c->opts.errors == BCH_ON_ERROR_continue ||
	     c->opts.errors == BCH_ON_ERROR_fix_safe)) {
@@ -528,7 +550,7 @@ int __bch2_fsck_err(struct bch_fs *c,
		__bch2_inconsistent_error(c, out);
	else if (exiting)
		prt_printf(out, "Unable to continue, halting\n");
	else if (suppressing)
	else if (suppress)
		prt_printf(out, "Ratelimiting new instances of previous error\n");

	if (print) {
+7 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ int bch2_fs_topology_error(struct bch_fs *, const char *, ...);

struct fsck_err_state {
	struct list_head	list;
	const char		*fmt;
	enum bch_sb_error_id	id;
	u64			nr;
	bool			ratelimited;
	int			ret;
@@ -77,6 +77,12 @@ struct fsck_err_state {

#define fsck_err_count(_c, _err)	bch2_sb_err_count(_c, BCH_FSCK_ERR_##_err)

void __bch2_count_fsck_err(struct bch_fs *,
			   enum bch_sb_error_id, const char *,
			   bool *, bool *, bool *);
#define bch2_count_fsck_err(_c, _err, ...)				\
	__bch2_count_fsck_err(_c, BCH_FSCK_ERR_##_err, __VA_ARGS__)

__printf(5, 6) __cold
int __bch2_fsck_err(struct bch_fs *, struct btree_trans *,
		  enum bch_fsck_flags,
+2 −0
Original line number Diff line number Diff line
@@ -1632,6 +1632,8 @@ static int overlapping_extents_found(struct btree_trans *trans,
			bch2_trans_commit(trans, &res, NULL, BCH_TRANS_COMMIT_no_enospc);
		bch2_disk_reservation_put(c, &res);

		bch_info(c, "repair ret %s", bch2_err_str(ret));

		if (ret)
			goto err;