summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSlava Pestov <sp@daterainc.com>2015-01-31 18:24:40 -0800
committerKent Overstreet <kmo@daterainc.com>2015-02-12 23:43:28 -0800
commit2a9fa590bbbbf1ad4acd876bbf98d78c0b18bb13 (patch)
tree6e9690be26d7634d61925db43b090388af50061f
parent0fc18d2cd054c895a9386b85456327a87cd2929a (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. Change-Id: I958bdea2201dfe220338ad55585e885b2d54220c
-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 5a9323c101d1..83f60cde9693 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -322,6 +322,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 17438854a3f4..155a6a7ba40b 100644
--- a/drivers/md/bcache/io.c
+++ b/drivers/md/bcache/io.c
@@ -190,21 +190,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 ee727eeaa0ee..186baf16fa11 100644
--- a/drivers/md/bcache/io.h
+++ b/drivers/md/bcache/io.h
@@ -1,6 +1,7 @@
#ifndef _BCACHE_IO_H
#define _BCACHE_IO_H
+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 eba7f46c4590..8188ee795f2a 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 d3ba2cce8c16..fa138439f1f9 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1887,6 +1887,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;