summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2016-03-16 00:10:54 -0800
committerKent Overstreet <kent.overstreet@gmail.com>2016-10-07 12:35:48 -0800
commitc5133fe7a0ba3304c0e9a9d7c72f5d8745c65529 (patch)
tree23f4f099db50e6653dbfaa1ab3e8079c592c9027
parentc6593726ae5ea38516d59fee00446ffa6d023435 (diff)
bcache: fix error handling in bch_write()
-rw-r--r--drivers/md/bcache/io.c73
1 files changed, 43 insertions, 30 deletions
diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c
index 792c31964ccd..266b83bbee8b 100644
--- a/drivers/md/bcache/io.c
+++ b/drivers/md/bcache/io.c
@@ -648,34 +648,46 @@ static void bch_write_discard(struct closure *cl)
/*
* Convert extents to be inserted to discards after an error:
*/
-static void __bch_write_discard(struct closure *cl)
+static void bch_write_io_error(struct closure *cl)
{
struct bch_write_op *op = container_of(cl, struct bch_write_op, cl);
- /*
- * Our data write just errored, which means we've got a bunch of keys to
- * insert that point to data that wasn't successfully written.
- *
- * We don't have to insert those keys but we still have to invalidate
- * that region of the cache - so, if we just strip off all the pointers
- * from the keys we'll accomplish just that.
- */
+ if (op->flags & BCH_WRITE_DISCARD_ON_ERROR) {
+ struct bkey_i *src = bch_keylist_front(&op->insert_keys);
+ struct bkey_i *dst = bch_keylist_front(&op->insert_keys);
- struct bkey_i *src = bch_keylist_front(&op->insert_keys);
- struct bkey_i *dst = bch_keylist_front(&op->insert_keys);
+ /*
+ * Our data write just errored, which means we've got a bunch
+ * of keys to insert that point to data that wasn't
+ * successfully written.
+ *
+ * We don't have to insert those keys but we still have to
+ * invalidate that region of the cache - so, if we just strip
+ * off all the pointers from the keys we'll accomplish just
+ * that.
+ */
- while (src != op->insert_keys.top) {
- struct bkey_i *n = bkey_next(src);
+ while (src != op->insert_keys.top) {
+ struct bkey_i *n = bkey_next(src);
- set_bkey_val_u64s(&src->k, 0);
- src->k.type = KEY_TYPE_DISCARD;
- memmove(dst, src, bkey_bytes(&src->k));
+ set_bkey_val_u64s(&src->k, 0);
+ src->k.type = KEY_TYPE_DISCARD;
+ memmove(dst, src, bkey_bytes(&src->k));
- dst = bkey_next(dst);
- src = n;
- }
+ dst = bkey_next(dst);
+ src = n;
+ }
- op->insert_keys.top = dst;
+ op->insert_keys.top = dst;
+ op->flags |= BCH_WRITE_DISCARD;
+ } else {
+ /* TODO: We could try to recover from this. */
+ while (!bch_keylist_empty(&op->insert_keys))
+ bch_keylist_dequeue(&op->insert_keys);
+
+ op->error = -EIO;
+ op->flags |= BCH_WRITE_DONE;
+ }
bch_write_index(cl);
}
@@ -687,15 +699,8 @@ static void bch_write_endio(struct bio *bio)
struct bch_write_bio *wbio = to_wbio(bio);
if (cache_nonfatal_io_err_on(bio->bi_error, wbio->bio.ca,
- "data write")) {
- /* TODO: We could try to recover from this. */
- if (!bkey_extent_is_cached(&op->insert_key.k)) {
- op->error = bio->bi_error;
- } else if (op->flags & BCH_WRITE_DISCARD_ON_ERROR)
- set_closure_fn(cl, __bch_write_discard, op->c->wq);
- else
- set_closure_fn(cl, NULL, NULL);
- }
+ "data write"))
+ set_closure_fn(cl, bch_write_io_error, op->c->wq);
if (wbio->orig)
bio_endio(wbio->orig);
@@ -1063,7 +1068,15 @@ err:
bch_write_discard(cl);
} else {
- op->error = -ENOSPC;
+ /*
+ * Right now we can only error here if we went RO - the
+ * allocation failed, but we already checked for -ENOSPC when we
+ * got our reservation.
+ *
+ * XXX capacity might have changed, but we don't check for that
+ * yet:
+ */
+ op->error = -EROFS;
}
op->flags |= BCH_WRITE_DONE;