diff options
author | Slava Pestov <sviatoslavpestov@gmail.com> | 2015-01-31 18:24:40 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2017-01-18 20:26:54 -0900 |
commit | e0814947dd60af87ee08ac15d61628f7b6d7e37f (patch) | |
tree | cd83a215aa5f4894b6e7caddc6a97dc9cb1da6e0 | |
parent | 29fa4033ce7aef6d5ab087415abff5fa333a99ba (diff) |
bcache: re-work bbio IO error reporting
We can't call bch_notify_*() from atomic context, so move it to a new
ca->io_error_work.
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r-- | drivers/md/bcache/bcache.h | 2 | ||||
-rw-r--r-- | drivers/md/bcache/io.c | 30 | ||||
-rw-r--r-- | drivers/md/bcache/io.h | 1 | ||||
-rw-r--r-- | drivers/md/bcache/notify.c | 4 | ||||
-rw-r--r-- | drivers/md/bcache/notify.h | 2 | ||||
-rw-r--r-- | drivers/md/bcache/super.c | 2 |
6 files changed, 26 insertions, 15 deletions
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 1250669cf37e..afc718930e02 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -327,6 +327,8 @@ struct cache { struct journal_device journal; + struct work_struct io_error_work; + /* The rest of this all shows up in sysfs */ #define IO_ERROR_SHIFT 20 atomic_t io_errors; diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index 09441498bf6a..cbaa60c3e762 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -192,21 +192,27 @@ void bch_count_io_errors(struct cache *ca, int error, const char *m) if (error) { char buf[BDEVNAME_SIZE]; - unsigned errors = atomic_add_return(1 << IO_ERROR_SHIFT, - &ca->io_errors); - if (errors < ca->set->error_limit) { - bch_notify_cache_error(ca, false, m); + atomic_add(1 << IO_ERROR_SHIFT, &ca->io_errors); + queue_work(system_long_wq, &ca->io_error_work); + printk_ratelimited(KERN_ERR "%s: IO error on %s", + bdevname(ca->disk_sb.bdev, buf), m); + } +} - pr_err("%s: IO error on %s, recovering", - bdevname(ca->disk_sb.bdev, buf), m); - } else { - bch_notify_cache_error(ca, true, m); +void bch_cache_io_error_work(struct work_struct *work) +{ + struct cache *ca = container_of(work, struct cache, io_error_work); + unsigned errors = atomic_read(&ca->io_errors); + char buf[BDEVNAME_SIZE]; - if (bch_cache_remove(ca, true)) - pr_err("%s: too many IO errors on %s, removing", - bdevname(ca->disk_sb.bdev, buf), m); - } + if (errors < ca->set->error_limit) { + bch_notify_cache_error(ca, false); + } else { + bch_notify_cache_error(ca, true); + printk_ratelimited(KERN_ERR "%s: too many IO errors, removing", + bdevname(ca->disk_sb.bdev, buf)); + bch_cache_remove(ca, true); } } diff --git a/drivers/md/bcache/io.h b/drivers/md/bcache/io.h index 25c1ede300d3..f25513c172c8 100644 --- a/drivers/md/bcache/io.h +++ b/drivers/md/bcache/io.h @@ -76,6 +76,7 @@ void bch_write(struct closure *); int bch_read(struct cache_set *, struct bio *, u64); +void bch_cache_io_error_work(struct work_struct *); void bch_count_io_errors(struct cache *, int, const char *); void bch_bbio_count_io_errors(struct bbio *, int, const char *); void bch_bbio_endio(struct bbio *, int, const char *); diff --git a/drivers/md/bcache/notify.c b/drivers/md/bcache/notify.c index 9d3a8ca78ae2..99a70f28d4e5 100644 --- a/drivers/md/bcache/notify.c +++ b/drivers/md/bcache/notify.c @@ -5,6 +5,7 @@ */ #include "bcache.h" +#include "notify.h" #include <linux/kobject.h> @@ -112,13 +113,12 @@ void bch_notify_cache_removed(struct cache *ca) notify_put(c); } -void bch_notify_cache_error(struct cache *ca, bool fatal, const char *m) +void bch_notify_cache_error(struct cache *ca, bool fatal) { struct cache_set *c = ca->set; notify_get_cache(ca); notify_var(c, "STATE=error"); notify_var(c, "FATAL=%d", fatal); - notify_var(c, "MESSAGE=%s", m); notify_put(c); } diff --git a/drivers/md/bcache/notify.h b/drivers/md/bcache/notify.h index b915feff3c00..e121a711cf1d 100644 --- a/drivers/md/bcache/notify.h +++ b/drivers/md/bcache/notify.h @@ -16,6 +16,6 @@ void bch_notify_cache_read_only(struct cache *); void bch_notify_cache_added(struct cache *); void bch_notify_cache_removing(struct cache *); void bch_notify_cache_removed(struct cache *); -void bch_notify_cache_error(struct cache *, bool, const char *); +void bch_notify_cache_error(struct cache *, bool); #endif /* _NOTIFY_H */ diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 8a81c3e04b2f..3630088946fb 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1766,6 +1766,8 @@ static const char *cache_alloc(struct bcache_superblock *sb, ca->disk_sb.bdev->bd_holder = ca; memset(sb, 0, sizeof(*sb)); + INIT_WORK(&ca->io_error_work, bch_cache_io_error_work); + err = "dynamic fault"; if (cache_set_init_fault("cache_alloc")) goto err; |