aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorColy Li <colyli@suse.de>2018-03-18 20:36:25 -0400
committerJens Axboe <axboe@kernel.dk>2018-03-18 22:15:20 -0400
commitc7b7bd07404c52d8b9c6fd2fe794052ac367a818 (patch)
treef1030fd28b6c26fe397de72a8b7c8e5e7077d36d /drivers/md
parent27a40ab9269e79b55672312b324f8f29d94463d4 (diff)
bcache: add io_disable to struct cached_dev
If a bcache device is configured to writeback mode, current code does not handle write I/O errors on backing devices properly. In writeback mode, write request is written to cache device, and latter being flushed to backing device. If I/O failed when writing from cache device to the backing device, bcache code just ignores the error and upper layer code is NOT noticed that the backing device is broken. This patch tries to handle backing device failure like how the cache device failure is handled, - Add a error counter 'io_errors' and error limit 'error_limit' in struct cached_dev. Add another io_disable to struct cached_dev to disable I/Os on the problematic backing device. - When I/O error happens on backing device, increase io_errors counter. And if io_errors reaches error_limit, set cache_dev->io_disable to true, and stop the bcache device. The result is, if backing device is broken of disconnected, and I/O errors reach its error limit, backing device will be disabled and the associated bcache device will be removed from system. Changelog: v2: remove "bcache: " prefix in pr_error(), and use correct name string to print out bcache device gendisk name. v1: indeed this is new added in v2 patch set. Signed-off-by: Coly Li <colyli@suse.de> Reviewed-by: Hannes Reinecke <hare@suse.com> Reviewed-by: Michael Lyle <mlyle@lyle.org> Cc: Michael Lyle <mlyle@lyle.org> Cc: Junhui Tang <tang.junhui@zte.com.cn> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/bcache/bcache.h6
-rw-r--r--drivers/md/bcache/io.c14
-rw-r--r--drivers/md/bcache/request.c14
-rw-r--r--drivers/md/bcache/super.c21
-rw-r--r--drivers/md/bcache/sysfs.c15
5 files changed, 67 insertions, 3 deletions
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 5e9f3610c6fd..d338b7086013 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -367,6 +367,7 @@ struct cached_dev {
367 unsigned sequential_cutoff; 367 unsigned sequential_cutoff;
368 unsigned readahead; 368 unsigned readahead;
369 369
370 unsigned io_disable:1;
370 unsigned verify:1; 371 unsigned verify:1;
371 unsigned bypass_torture_test:1; 372 unsigned bypass_torture_test:1;
372 373
@@ -388,6 +389,9 @@ struct cached_dev {
388 unsigned writeback_rate_minimum; 389 unsigned writeback_rate_minimum;
389 390
390 enum stop_on_failure stop_when_cache_set_failed; 391 enum stop_on_failure stop_when_cache_set_failed;
392#define DEFAULT_CACHED_DEV_ERROR_LIMIT 64
393 atomic_t io_errors;
394 unsigned error_limit;
391}; 395};
392 396
393enum alloc_reserve { 397enum alloc_reserve {
@@ -911,6 +915,7 @@ static inline void wait_for_kthread_stop(void)
911 915
912/* Forward declarations */ 916/* Forward declarations */
913 917
918void bch_count_backing_io_errors(struct cached_dev *dc, struct bio *bio);
914void bch_count_io_errors(struct cache *, blk_status_t, int, const char *); 919void bch_count_io_errors(struct cache *, blk_status_t, int, const char *);
915void bch_bbio_count_io_errors(struct cache_set *, struct bio *, 920void bch_bbio_count_io_errors(struct cache_set *, struct bio *,
916 blk_status_t, const char *); 921 blk_status_t, const char *);
@@ -938,6 +943,7 @@ int bch_bucket_alloc_set(struct cache_set *, unsigned,
938 struct bkey *, int, bool); 943 struct bkey *, int, bool);
939bool bch_alloc_sectors(struct cache_set *, struct bkey *, unsigned, 944bool bch_alloc_sectors(struct cache_set *, struct bkey *, unsigned,
940 unsigned, unsigned, bool); 945 unsigned, unsigned, bool);
946bool bch_cached_dev_error(struct cached_dev *dc);
941 947
942__printf(2, 3) 948__printf(2, 3)
943bool bch_cache_set_error(struct cache_set *, const char *, ...); 949bool bch_cache_set_error(struct cache_set *, const char *, ...);
diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c
index 8013ecbcdbda..7fac97ae036e 100644
--- a/drivers/md/bcache/io.c
+++ b/drivers/md/bcache/io.c
@@ -50,6 +50,20 @@ void bch_submit_bbio(struct bio *bio, struct cache_set *c,
50} 50}
51 51
52/* IO errors */ 52/* IO errors */
53void bch_count_backing_io_errors(struct cached_dev *dc, struct bio *bio)
54{
55 char buf[BDEVNAME_SIZE];
56 unsigned errors;
57
58 WARN_ONCE(!dc, "NULL pointer of struct cached_dev");
59
60 errors = atomic_add_return(1, &dc->io_errors);
61 if (errors < dc->error_limit)
62 pr_err("%s: IO error on backing device, unrecoverable",
63 bio_devname(bio, buf));
64 else
65 bch_cached_dev_error(dc);
66}
53 67
54void bch_count_io_errors(struct cache *ca, 68void bch_count_io_errors(struct cache *ca,
55 blk_status_t error, 69 blk_status_t error,
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index b4a5768afbe9..5a82237c7025 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -637,6 +637,8 @@ static void backing_request_endio(struct bio *bio)
637 637
638 if (bio->bi_status) { 638 if (bio->bi_status) {
639 struct search *s = container_of(cl, struct search, cl); 639 struct search *s = container_of(cl, struct search, cl);
640 struct cached_dev *dc = container_of(s->d,
641 struct cached_dev, disk);
640 /* 642 /*
641 * If a bio has REQ_PREFLUSH for writeback mode, it is 643 * If a bio has REQ_PREFLUSH for writeback mode, it is
642 * speically assembled in cached_dev_write() for a non-zero 644 * speically assembled in cached_dev_write() for a non-zero
@@ -657,6 +659,7 @@ static void backing_request_endio(struct bio *bio)
657 } 659 }
658 s->recoverable = false; 660 s->recoverable = false;
659 /* should count I/O error for backing device here */ 661 /* should count I/O error for backing device here */
662 bch_count_backing_io_errors(dc, bio);
660 } 663 }
661 664
662 bio_put(bio); 665 bio_put(bio);
@@ -1065,8 +1068,14 @@ static void detached_dev_end_io(struct bio *bio)
1065 bio_data_dir(bio), 1068 bio_data_dir(bio),
1066 &ddip->d->disk->part0, ddip->start_time); 1069 &ddip->d->disk->part0, ddip->start_time);
1067 1070
1068 kfree(ddip); 1071 if (bio->bi_status) {
1072 struct cached_dev *dc = container_of(ddip->d,
1073 struct cached_dev, disk);
1074 /* should count I/O error for backing device here */
1075 bch_count_backing_io_errors(dc, bio);
1076 }
1069 1077
1078 kfree(ddip);
1070 bio->bi_end_io(bio); 1079 bio->bi_end_io(bio);
1071} 1080}
1072 1081
@@ -1105,7 +1114,8 @@ static blk_qc_t cached_dev_make_request(struct request_queue *q,
1105 struct cached_dev *dc = container_of(d, struct cached_dev, disk); 1114 struct cached_dev *dc = container_of(d, struct cached_dev, disk);
1106 int rw = bio_data_dir(bio); 1115 int rw = bio_data_dir(bio);
1107 1116
1108 if (unlikely(d->c && test_bit(CACHE_SET_IO_DISABLE, &d->c->flags))) { 1117 if (unlikely((d->c && test_bit(CACHE_SET_IO_DISABLE, &d->c->flags)) ||
1118 dc->io_disable)) {
1109 bio->bi_status = BLK_STS_IOERR; 1119 bio->bi_status = BLK_STS_IOERR;
1110 bio_endio(bio); 1120 bio_endio(bio);
1111 return BLK_QC_T_NONE; 1121 return BLK_QC_T_NONE;
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 2f8e70aefc90..06f4b4833755 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1197,6 +1197,9 @@ static int cached_dev_init(struct cached_dev *dc, unsigned block_size)
1197 max(dc->disk.disk->queue->backing_dev_info->ra_pages, 1197 max(dc->disk.disk->queue->backing_dev_info->ra_pages,
1198 q->backing_dev_info->ra_pages); 1198 q->backing_dev_info->ra_pages);
1199 1199
1200 atomic_set(&dc->io_errors, 0);
1201 dc->io_disable = false;
1202 dc->error_limit = DEFAULT_CACHED_DEV_ERROR_LIMIT;
1200 /* default to auto */ 1203 /* default to auto */
1201 dc->stop_when_cache_set_failed = BCH_CACHED_DEV_STOP_AUTO; 1204 dc->stop_when_cache_set_failed = BCH_CACHED_DEV_STOP_AUTO;
1202 1205
@@ -1351,6 +1354,24 @@ int bch_flash_dev_create(struct cache_set *c, uint64_t size)
1351 return flash_dev_run(c, u); 1354 return flash_dev_run(c, u);
1352} 1355}
1353 1356
1357bool bch_cached_dev_error(struct cached_dev *dc)
1358{
1359 char name[BDEVNAME_SIZE];
1360
1361 if (!dc || test_bit(BCACHE_DEV_CLOSING, &dc->disk.flags))
1362 return false;
1363
1364 dc->io_disable = true;
1365 /* make others know io_disable is true earlier */
1366 smp_mb();
1367
1368 pr_err("stop %s: too many IO errors on backing device %s\n",
1369 dc->disk.disk->disk_name, bdevname(dc->bdev, name));
1370
1371 bcache_device_stop(&dc->disk);
1372 return true;
1373}
1374
1354/* Cache set */ 1375/* Cache set */
1355 1376
1356__printf(2, 3) 1377__printf(2, 3)
diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c
index 8c3fd05db87a..dfeef583ee50 100644
--- a/drivers/md/bcache/sysfs.c
+++ b/drivers/md/bcache/sysfs.c
@@ -141,7 +141,9 @@ SHOW(__bch_cached_dev)
141 var_print(writeback_delay); 141 var_print(writeback_delay);
142 var_print(writeback_percent); 142 var_print(writeback_percent);
143 sysfs_hprint(writeback_rate, dc->writeback_rate.rate << 9); 143 sysfs_hprint(writeback_rate, dc->writeback_rate.rate << 9);
144 144 sysfs_hprint(io_errors, atomic_read(&dc->io_errors));
145 sysfs_printf(io_error_limit, "%i", dc->error_limit);
146 sysfs_printf(io_disable, "%i", dc->io_disable);
145 var_print(writeback_rate_update_seconds); 147 var_print(writeback_rate_update_seconds);
146 var_print(writeback_rate_i_term_inverse); 148 var_print(writeback_rate_i_term_inverse);
147 var_print(writeback_rate_p_term_inverse); 149 var_print(writeback_rate_p_term_inverse);
@@ -232,6 +234,14 @@ STORE(__cached_dev)
232 d_strtoul(writeback_rate_i_term_inverse); 234 d_strtoul(writeback_rate_i_term_inverse);
233 d_strtoul_nonzero(writeback_rate_p_term_inverse); 235 d_strtoul_nonzero(writeback_rate_p_term_inverse);
234 236
237 sysfs_strtoul_clamp(io_error_limit, dc->error_limit, 0, INT_MAX);
238
239 if (attr == &sysfs_io_disable) {
240 int v = strtoul_or_return(buf);
241
242 dc->io_disable = v ? 1 : 0;
243 }
244
235 d_strtoi_h(sequential_cutoff); 245 d_strtoi_h(sequential_cutoff);
236 d_strtoi_h(readahead); 246 d_strtoi_h(readahead);
237 247
@@ -352,6 +362,9 @@ static struct attribute *bch_cached_dev_files[] = {
352 &sysfs_writeback_rate_i_term_inverse, 362 &sysfs_writeback_rate_i_term_inverse,
353 &sysfs_writeback_rate_p_term_inverse, 363 &sysfs_writeback_rate_p_term_inverse,
354 &sysfs_writeback_rate_debug, 364 &sysfs_writeback_rate_debug,
365 &sysfs_errors,
366 &sysfs_io_error_limit,
367 &sysfs_io_disable,
355 &sysfs_dirty_data, 368 &sysfs_dirty_data,
356 &sysfs_stripe_size, 369 &sysfs_stripe_size,
357 &sysfs_partial_stripes_expensive, 370 &sysfs_partial_stripes_expensive,