summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSlava Pestov <sviatoslavpestov@gmail.com>2015-01-31 18:24:40 -0800
committerKent Overstreet <kent.overstreet@gmail.com>2017-01-18 20:26:54 -0900
commite0814947dd60af87ee08ac15d61628f7b6d7e37f (patch)
treecd83a215aa5f4894b6e7caddc6a97dc9cb1da6e0
parent29fa4033ce7aef6d5ab087415abff5fa333a99ba (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.h2
-rw-r--r--drivers/md/bcache/io.c30
-rw-r--r--drivers/md/bcache/io.h1
-rw-r--r--drivers/md/bcache/notify.c4
-rw-r--r--drivers/md/bcache/notify.h2
-rw-r--r--drivers/md/bcache/super.c2
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;