diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2017-04-14 20:38:49 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2017-04-14 20:40:31 -0800 |
commit | 819f2dde79241915a6edda2c20bb4ca5d4017030 (patch) | |
tree | b165cdf270fd14e98ecfa4affe57943c6854529e /libbcachefs/error.c | |
parent | 03bc9d71b13e6f8e879894f93ea16f1f4a8280c9 (diff) |
Update bcachefs sources to f026e4e024
Diffstat (limited to 'libbcachefs/error.c')
-rw-r--r-- | libbcachefs/error.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/libbcachefs/error.c b/libbcachefs/error.c index 8babf196..5b7316de 100644 --- a/libbcachefs/error.c +++ b/libbcachefs/error.c @@ -49,3 +49,102 @@ void bch2_nonfatal_io_error(struct bch_dev *ca) { queue_work(system_long_wq, &ca->io_error_work); } + +#ifdef __KERNEL__ +#define ask_yn() false +#else +#include "tools-util.h" +#endif + +enum fsck_err_ret bch2_fsck_err(struct bch_fs *c, unsigned flags, + const char *fmt, ...) +{ + struct fsck_err_state *s; + va_list args; + bool fix = false, print = true, suppressing = false; + char _buf[sizeof(s->buf)], *buf = _buf; + + mutex_lock(&c->fsck_error_lock); + + if (test_bit(BCH_FS_FSCK_DONE, &c->flags)) + goto print; + + list_for_each_entry(s, &c->fsck_errors, list) + if (s->fmt == fmt) + goto found; + + s = kzalloc(sizeof(*s), GFP_KERNEL); + if (!s) { + if (!c->fsck_alloc_err) + bch_err(c, "kmalloc err, cannot ratelimit fsck errs"); + c->fsck_alloc_err = true; + buf = _buf; + goto print; + } + + INIT_LIST_HEAD(&s->list); + s->fmt = fmt; +found: + list_move(&s->list, &c->fsck_errors); + s->nr++; + suppressing = s->nr == 10; + print = s->nr <= 10; + buf = s->buf; +print: + va_start(args, fmt); + vscnprintf(buf, sizeof(_buf), fmt, args); + va_end(args); + + if (flags & FSCK_CAN_FIX) { + if (c->opts.fix_errors == FSCK_ERR_ASK) { + printk(KERN_ERR "%s: fix?", buf); + fix = ask_yn(); + } else if (c->opts.fix_errors == FSCK_ERR_YES || + (c->opts.nochanges && + !(flags & FSCK_CAN_IGNORE))) { + if (print) + bch_err(c, "%s, fixing", buf); + fix = true; + } else { + if (print) + bch_err(c, "%s, not fixing", buf); + fix = false; + } + } else if (flags & FSCK_NEED_FSCK) { + if (print) + bch_err(c, "%s (run fsck to correct)", buf); + } else { + if (print) + bch_err(c, "%s (repair unimplemented)", buf); + } + + if (suppressing) + bch_err(c, "Ratelimiting new instances of previous error"); + + mutex_unlock(&c->fsck_error_lock); + + if (fix) + set_bit(BCH_FS_FSCK_FIXED_ERRORS, &c->flags); + + return fix ? FSCK_ERR_FIX + : flags & FSCK_CAN_IGNORE ? FSCK_ERR_IGNORE + : FSCK_ERR_EXIT; +} + +void bch2_flush_fsck_errs(struct bch_fs *c) +{ + struct fsck_err_state *s, *n; + + mutex_lock(&c->fsck_error_lock); + set_bit(BCH_FS_FSCK_DONE, &c->flags); + + list_for_each_entry_safe(s, n, &c->fsck_errors, list) { + if (s->nr > 10) + bch_err(c, "Saw %llu errors like:\n %s", s->nr, s->buf); + + list_del(&s->list); + kfree(s); + } + + mutex_unlock(&c->fsck_error_lock); +} |