as specified.
 
 Now bh->b_end_io is replaced by bio->bi_end_io, but most of the time the
-right thing to use is bio_endio(bio, uptodate) instead.
+right thing to use is bio_endio(bio) instead.
 
 If the driver is dropping the io_request_lock from its request_fn strategy,
 then it just needs to replace that with q->queue_lock instead.
 
                                bvec_to_phys(&bvec));
                sec += len;
        }
-       bio_endio(bio, 0);
+       bio_endio(bio);
 }
 
 static int nfhd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 
                phys_mem += vec.bv_len;
                transfered += vec.bv_len;
        }
-       bio_endio(bio, 0);
+       bio_endio(bio);
 }
 
 /**
 
        spin_unlock(&dev->lock);
 }
 
-static int simdisk_xfer_bio(struct simdisk *dev, struct bio *bio)
+static void simdisk_make_request(struct request_queue *q, struct bio *bio)
 {
+       struct simdisk *dev = q->queuedata;
        struct bio_vec bvec;
        struct bvec_iter iter;
        sector_t sector = bio->bi_iter.bi_sector;
                sector += len;
                __bio_kunmap_atomic(buffer);
        }
-       return 0;
-}
 
-static void simdisk_make_request(struct request_queue *q, struct bio *bio)
-{
-       struct simdisk *dev = q->queuedata;
-       int status = simdisk_xfer_bio(dev, bio);
-       bio_endio(bio, status);
+       bio_endio(bio);
 }
 
-
 static int simdisk_open(struct block_device *bdev, fmode_t mode)
 {
        struct simdisk *dev = bdev->bd_disk->private_data;
 
                container_of(work, struct bio_integrity_payload, bip_work);
        struct bio *bio = bip->bip_bio;
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
-       int error;
 
-       error = bio_integrity_process(bio, bi->verify_fn);
+       bio->bi_error = bio_integrity_process(bio, bi->verify_fn);
 
        /* Restore original bio completion handler */
        bio->bi_end_io = bip->bip_end_io;
-       bio_endio(bio, error);
+       bio_endio(bio);
 }
 
 /**
  * in process context. This function postpones completion
  * accordingly.
  */
-void bio_integrity_endio(struct bio *bio, int error)
+void bio_integrity_endio(struct bio *bio)
 {
        struct bio_integrity_payload *bip = bio_integrity(bio);
 
         * integrity metadata.  Restore original bio end_io handler
         * and run it.
         */
-       if (error) {
+       if (bio->bi_error) {
                bio->bi_end_io = bip->bip_end_io;
-               bio_endio(bio, error);
+               bio_endio(bio);
 
                return;
        }
 
 void bio_init(struct bio *bio)
 {
        memset(bio, 0, sizeof(*bio));
-       bio->bi_flags = 1 << BIO_UPTODATE;
        atomic_set(&bio->__bi_remaining, 1);
        atomic_set(&bio->__bi_cnt, 1);
 }
        __bio_free(bio);
 
        memset(bio, 0, BIO_RESET_BYTES);
-       bio->bi_flags = flags | (1 << BIO_UPTODATE);
+       bio->bi_flags = flags;
        atomic_set(&bio->__bi_remaining, 1);
 }
 EXPORT_SYMBOL(bio_reset);
 
-static void bio_chain_endio(struct bio *bio, int error)
+static void bio_chain_endio(struct bio *bio)
 {
-       bio_endio(bio->bi_private, error);
+       struct bio *parent = bio->bi_private;
+
+       parent->bi_error = bio->bi_error;
+       bio_endio(parent);
        bio_put(bio);
 }
 
        int error;
 };
 
-static void submit_bio_wait_endio(struct bio *bio, int error)
+static void submit_bio_wait_endio(struct bio *bio)
 {
        struct submit_bio_ret *ret = bio->bi_private;
 
-       ret->error = error;
+       ret->error = bio->bi_error;
        complete(&ret->event);
 }
 
 }
 EXPORT_SYMBOL(bio_unmap_user);
 
-static void bio_map_kern_endio(struct bio *bio, int err)
+static void bio_map_kern_endio(struct bio *bio)
 {
        bio_put(bio);
 }
 }
 EXPORT_SYMBOL(bio_map_kern);
 
-static void bio_copy_kern_endio(struct bio *bio, int err)
+static void bio_copy_kern_endio(struct bio *bio)
 {
        bio_free_pages(bio);
        bio_put(bio);
 }
 
-static void bio_copy_kern_endio_read(struct bio *bio, int err)
+static void bio_copy_kern_endio_read(struct bio *bio)
 {
        char *p = bio->bi_private;
        struct bio_vec *bvec;
                p += bvec->bv_len;
        }
 
-       bio_copy_kern_endio(bio, err);
+       bio_copy_kern_endio(bio);
 }
 
 /**
 /**
  * bio_endio - end I/O on a bio
  * @bio:       bio
- * @error:     error, if any
  *
  * Description:
- *   bio_endio() will end I/O on the whole bio. bio_endio() is the
- *   preferred way to end I/O on a bio, it takes care of clearing
- *   BIO_UPTODATE on error. @error is 0 on success, and and one of the
- *   established -Exxxx (-EIO, for instance) error values in case
- *   something went wrong. No one should call bi_end_io() directly on a
- *   bio unless they own it and thus know that it has an end_io
- *   function.
+ *   bio_endio() will end I/O on the whole bio. bio_endio() is the preferred
+ *   way to end I/O on a bio. No one should call bi_end_io() directly on a
+ *   bio unless they own it and thus know that it has an end_io function.
  **/
-void bio_endio(struct bio *bio, int error)
+void bio_endio(struct bio *bio)
 {
        while (bio) {
-               if (error)
-                       clear_bit(BIO_UPTODATE, &bio->bi_flags);
-               else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
-                       error = -EIO;
-
                if (unlikely(!bio_remaining_done(bio)))
                        break;
 
                 */
                if (bio->bi_end_io == bio_chain_endio) {
                        struct bio *parent = bio->bi_private;
+                       parent->bi_error = bio->bi_error;
                        bio_put(bio);
                        bio = parent;
                } else {
                        if (bio->bi_end_io)
-                               bio->bi_end_io(bio, error);
+                               bio->bi_end_io(bio);
                        bio = NULL;
                }
        }
 
                          unsigned int nbytes, int error)
 {
        if (error)
-               clear_bit(BIO_UPTODATE, &bio->bi_flags);
-       else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
-               error = -EIO;
+               bio->bi_error = error;
 
        if (unlikely(rq->cmd_flags & REQ_QUIET))
                set_bit(BIO_QUIET, &bio->bi_flags);
 
        /* don't actually finish bio if it's part of flush sequence */
        if (bio->bi_iter.bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ))
-               bio_endio(bio, error);
+               bio_endio(bio);
 }
 
 void blk_dump_rq_flags(struct request *rq, char *msg)
        blk_queue_bounce(q, &bio);
 
        if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
-               bio_endio(bio, -EIO);
+               bio->bi_error = -EIO;
+               bio_endio(bio);
                return;
        }
 
         */
        req = get_request(q, rw_flags, bio, GFP_NOIO);
        if (IS_ERR(req)) {
-               bio_endio(bio, PTR_ERR(req));   /* @q is dead */
+               bio->bi_error = PTR_ERR(req);
+               bio_endio(bio);
                goto out_unlock;
        }
 
        return true;
 
 end_io:
-       bio_endio(bio, err);
+       bio->bi_error = err;
+       bio_endio(bio);
        return false;
 }
 
 
 
 struct bio_batch {
        atomic_t                done;
-       unsigned long           flags;
+       int                     error;
        struct completion       *wait;
 };
 
-static void bio_batch_end_io(struct bio *bio, int err)
+static void bio_batch_end_io(struct bio *bio)
 {
        struct bio_batch *bb = bio->bi_private;
 
-       if (err && (err != -EOPNOTSUPP))
-               clear_bit(BIO_UPTODATE, &bb->flags);
+       if (bio->bi_error && bio->bi_error != -EOPNOTSUPP)
+               bb->error = bio->bi_error;
        if (atomic_dec_and_test(&bb->done))
                complete(bb->wait);
        bio_put(bio);
        }
 
        atomic_set(&bb.done, 1);
-       bb.flags = 1 << BIO_UPTODATE;
+       bb.error = 0;
        bb.wait = &wait;
 
        blk_start_plug(&plug);
        if (!atomic_dec_and_test(&bb.done))
                wait_for_completion_io(&wait);
 
-       if (!test_bit(BIO_UPTODATE, &bb.flags))
-               ret = -EIO;
-
+       if (bb.error)
+               return bb.error;
        return ret;
 }
 EXPORT_SYMBOL(blkdev_issue_discard);
                return -EOPNOTSUPP;
 
        atomic_set(&bb.done, 1);
-       bb.flags = 1 << BIO_UPTODATE;
+       bb.error = 0;
        bb.wait = &wait;
 
        while (nr_sects) {
        if (!atomic_dec_and_test(&bb.done))
                wait_for_completion_io(&wait);
 
-       if (!test_bit(BIO_UPTODATE, &bb.flags))
-               ret = -ENOTSUPP;
-
+       if (bb.error)
+               return bb.error;
        return ret;
 }
 EXPORT_SYMBOL(blkdev_issue_write_same);
        DECLARE_COMPLETION_ONSTACK(wait);
 
        atomic_set(&bb.done, 1);
-       bb.flags = 1 << BIO_UPTODATE;
+       bb.error = 0;
        bb.wait = &wait;
 
        ret = 0;
        if (!atomic_dec_and_test(&bb.done))
                wait_for_completion_io(&wait);
 
-       if (!test_bit(BIO_UPTODATE, &bb.flags))
-               /* One of bios in the batch was completed with error.*/
-               ret = -EIO;
-
+       if (bb.error)
+               return bb.error;
        return ret;
 }
 
 
                 * normal IO completion path
                 */
                bio_get(bio);
-               bio_endio(bio, 0);
+               bio_endio(bio);
                __blk_rq_unmap_user(bio);
                return -EINVAL;
        }
 
        struct blk_mq_alloc_data alloc_data;
 
        if (unlikely(blk_mq_queue_enter(q, GFP_KERNEL))) {
-               bio_endio(bio, -EIO);
+               bio_io_error(bio);
                return NULL;
        }
 
        blk_queue_bounce(q, &bio);
 
        if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
-               bio_endio(bio, -EIO);
+               bio_io_error(bio);
                return;
        }
 
        blk_queue_bounce(q, &bio);
 
        if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
-               bio_endio(bio, -EIO);
+               bio_io_error(bio);
                return;
        }
 
 
        }
 }
 
-static void bounce_end_io(struct bio *bio, mempool_t *pool, int err)
+static void bounce_end_io(struct bio *bio, mempool_t *pool)
 {
        struct bio *bio_orig = bio->bi_private;
        struct bio_vec *bvec, *org_vec;
                mempool_free(bvec->bv_page, pool);
        }
 
-       bio_endio(bio_orig, err);
+       bio_orig->bi_error = bio->bi_error;
+       bio_endio(bio_orig);
        bio_put(bio);
 }
 
-static void bounce_end_io_write(struct bio *bio, int err)
+static void bounce_end_io_write(struct bio *bio)
 {
-       bounce_end_io(bio, page_pool, err);
+       bounce_end_io(bio, page_pool);
 }
 
-static void bounce_end_io_write_isa(struct bio *bio, int err)
+static void bounce_end_io_write_isa(struct bio *bio)
 {
 
-       bounce_end_io(bio, isa_page_pool, err);
+       bounce_end_io(bio, isa_page_pool);
 }
 
-static void __bounce_end_io_read(struct bio *bio, mempool_t *pool, int err)
+static void __bounce_end_io_read(struct bio *bio, mempool_t *pool)
 {
        struct bio *bio_orig = bio->bi_private;
 
-       if (test_bit(BIO_UPTODATE, &bio->bi_flags))
+       if (!bio->bi_error)
                copy_to_high_bio_irq(bio_orig, bio);
 
-       bounce_end_io(bio, pool, err);
+       bounce_end_io(bio, pool);
 }
 
-static void bounce_end_io_read(struct bio *bio, int err)
+static void bounce_end_io_read(struct bio *bio)
 {
-       __bounce_end_io_read(bio, page_pool, err);
+       __bounce_end_io_read(bio, page_pool);
 }
 
-static void bounce_end_io_read_isa(struct bio *bio, int err)
+static void bounce_end_io_read_isa(struct bio *bio)
 {
-       __bounce_end_io_read(bio, isa_page_pool, err);
+       __bounce_end_io_read(bio, isa_page_pool);
 }
 
 #ifdef CONFIG_NEED_BOUNCE_POOL
 
                d->ip.rq = NULL;
        do {
                bio = rq->bio;
-               bok = !fastfail && test_bit(BIO_UPTODATE, &bio->bi_flags);
+               bok = !fastfail && !bio->bi_error;
        } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_iter.bi_size));
 
        /* cf. http://lkml.org/lkml/2006/10/31/28 */
                        ahout->cmdstat, ahin->cmdstat,
                        d->aoemajor, d->aoeminor);
 noskb:         if (buf)
-                       clear_bit(BIO_UPTODATE, &buf->bio->bi_flags);
+                       buf->bio->bi_error = -EIO;
                goto out;
        }
 
                                "aoe: runt data size in read from",
                                (long) d->aoemajor, d->aoeminor,
                               skb->len, n);
-                       clear_bit(BIO_UPTODATE, &buf->bio->bi_flags);
+                       buf->bio->bi_error = -EIO;
                        break;
                }
                if (n > f->iter.bi_size) {
                                "aoe: too-large data size in read from",
                                (long) d->aoemajor, d->aoeminor,
                                n, f->iter.bi_size);
-                       clear_bit(BIO_UPTODATE, &buf->bio->bi_flags);
+                       buf->bio->bi_error = -EIO;
                        break;
                }
                bvcpy(skb, f->buf->bio, f->iter, n);
        if (buf == NULL)
                return;
        buf->iter.bi_size = 0;
-       clear_bit(BIO_UPTODATE, &buf->bio->bi_flags);
+       buf->bio->bi_error = -EIO;
        if (buf->nframesout == 0)
                aoe_end_buf(d, buf);
 }
 
        if (rq == NULL)
                return;
        while ((bio = d->ip.nxbio)) {
-               clear_bit(BIO_UPTODATE, &bio->bi_flags);
+               bio->bi_error = -EIO;
                d->ip.nxbio = bio->bi_next;
                n = (unsigned long) rq->special;
                rq->special = (void *) --n;
 
        struct bio_vec bvec;
        sector_t sector;
        struct bvec_iter iter;
-       int err = -EIO;
 
        sector = bio->bi_iter.bi_sector;
        if (bio_end_sector(bio) > get_capacity(bdev->bd_disk))
-               goto out;
+               goto io_error;
 
        if (unlikely(bio->bi_rw & REQ_DISCARD)) {
-               err = 0;
                discard_from_brd(brd, sector, bio->bi_iter.bi_size);
                goto out;
        }
 
        bio_for_each_segment(bvec, bio, iter) {
                unsigned int len = bvec.bv_len;
+               int err;
+
                err = brd_do_bvec(brd, bvec.bv_page, len,
                                        bvec.bv_offset, rw, sector);
                if (err)
-                       break;
+                       goto io_error;
                sector += len >> SECTOR_SHIFT;
        }
 
 out:
-       bio_endio(bio, err);
+       bio_endio(bio);
+       return;
+io_error:
+       bio_io_error(bio);
 }
 
 static int brd_rw_page(struct block_device *bdev, sector_t sector,
 
        atomic_inc(&device->md_io.in_use); /* drbd_md_put_buffer() is in the completion handler */
        device->md_io.submit_jif = jiffies;
        if (drbd_insert_fault(device, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD))
-               bio_endio(bio, -EIO);
+               bio_io_error(bio);
        else
                submit_bio(rw, bio);
        wait_until_done_or_force_detached(device, bdev, &device->md_io.done);
-       if (bio_flagged(bio, BIO_UPTODATE))
+       if (!bio->bi_error)
                err = device->md_io.error;
 
  out:
 
 }
 
 /* bv_page may be a copy, or may be the original */
-static void drbd_bm_endio(struct bio *bio, int error)
+static void drbd_bm_endio(struct bio *bio)
 {
        struct drbd_bm_aio_ctx *ctx = bio->bi_private;
        struct drbd_device *device = ctx->device;
        struct drbd_bitmap *b = device->bitmap;
        unsigned int idx = bm_page_to_idx(bio->bi_io_vec[0].bv_page);
-       int uptodate = bio_flagged(bio, BIO_UPTODATE);
-
-
-       /* strange behavior of some lower level drivers...
-        * fail the request by clearing the uptodate flag,
-        * but do not return any error?!
-        * do we want to WARN() on this? */
-       if (!error && !uptodate)
-               error = -EIO;
 
        if ((ctx->flags & BM_AIO_COPY_PAGES) == 0 &&
            !bm_test_page_unchanged(b->bm_pages[idx]))
                drbd_warn(device, "bitmap page idx %u changed during IO!\n", idx);
 
-       if (error) {
+       if (bio->bi_error) {
                /* ctx error will hold the completed-last non-zero error code,
                 * in case error codes differ. */
-               ctx->error = error;
+               ctx->error = bio->bi_error;
                bm_set_page_io_err(b->bm_pages[idx]);
                /* Not identical to on disk version of it.
                 * Is BM_PAGE_IO_ERROR enough? */
                if (__ratelimit(&drbd_ratelimit_state))
                        drbd_err(device, "IO ERROR %d on bitmap page idx %u\n",
-                                       error, idx);
+                                       bio->bi_error, idx);
        } else {
                bm_clear_page_io_err(b->bm_pages[idx]);
                dynamic_drbd_dbg(device, "bitmap page idx %u completed\n", idx);
 
        if (drbd_insert_fault(device, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) {
                bio->bi_rw |= rw;
-               bio_endio(bio, -EIO);
+               bio_io_error(bio);
        } else {
                submit_bio(rw, bio);
                /* this should not count as user activity and cause the
 
 
 /* drbd_worker.c */
 /* bi_end_io handlers */
-extern void drbd_md_endio(struct bio *bio, int error);
-extern void drbd_peer_request_endio(struct bio *bio, int error);
-extern void drbd_request_endio(struct bio *bio, int error);
+extern void drbd_md_endio(struct bio *bio);
+extern void drbd_peer_request_endio(struct bio *bio);
+extern void drbd_request_endio(struct bio *bio);
 extern int drbd_worker(struct drbd_thread *thi);
 enum drbd_ret_code drbd_resync_after_valid(struct drbd_device *device, int o_minor);
 void drbd_resync_after_changed(struct drbd_device *device);
        __release(local);
        if (!bio->bi_bdev) {
                drbd_err(device, "drbd_generic_make_request: bio->bi_bdev == NULL\n");
-               bio_endio(bio, -ENODEV);
+               bio->bi_error = -ENODEV;
+               bio_endio(bio);
                return;
        }
 
        if (drbd_insert_fault(device, fault_type))
-               bio_endio(bio, -EIO);
+               bio_io_error(bio);
        else
                generic_make_request(bio);
 }
 
 void complete_master_bio(struct drbd_device *device,
                struct bio_and_error *m)
 {
-       bio_endio(m->bio, m->error);
+       m->bio->bi_error = m->error;
+       bio_endio(m->bio);
        dec_ap_bio(device);
 }
 
                                      rw == WRITE ? DRBD_FAULT_DT_WR
                                    : rw == READ  ? DRBD_FAULT_DT_RD
                                    :               DRBD_FAULT_DT_RA))
-                       bio_endio(bio, -EIO);
+                       bio_io_error(bio);
                else
                        generic_make_request(bio);
                put_ldev(device);
        } else
-               bio_endio(bio, -EIO);
+               bio_io_error(bio);
 }
 
 static void drbd_queue_write(struct drbd_device *device, struct drbd_request *req)
                /* only pass the error to the upper layers.
                 * if user cannot handle io errors, that's not our business. */
                drbd_err(device, "could not kmalloc() req\n");
-               bio_endio(bio, -ENOMEM);
+               bio->bi_error = -ENOMEM;
+               bio_endio(bio);
                return ERR_PTR(-ENOMEM);
        }
        req->start_jif = start_jif;
 
 /* used for synchronous meta data and bitmap IO
  * submitted by drbd_md_sync_page_io()
  */
-void drbd_md_endio(struct bio *bio, int error)
+void drbd_md_endio(struct bio *bio)
 {
        struct drbd_device *device;
 
        device = bio->bi_private;
-       device->md_io.error = error;
+       device->md_io.error = bio->bi_error;
 
        /* We grabbed an extra reference in _drbd_md_sync_page_io() to be able
         * to timeout on the lower level device, and eventually detach from it.
 /* writes on behalf of the partner, or resync writes,
  * "submitted" by the receiver.
  */
-void drbd_peer_request_endio(struct bio *bio, int error)
+void drbd_peer_request_endio(struct bio *bio)
 {
        struct drbd_peer_request *peer_req = bio->bi_private;
        struct drbd_device *device = peer_req->peer_device->device;
-       int uptodate = bio_flagged(bio, BIO_UPTODATE);
        int is_write = bio_data_dir(bio) == WRITE;
        int is_discard = !!(bio->bi_rw & REQ_DISCARD);
 
-       if (error && __ratelimit(&drbd_ratelimit_state))
+       if (bio->bi_error && __ratelimit(&drbd_ratelimit_state))
                drbd_warn(device, "%s: error=%d s=%llus\n",
                                is_write ? (is_discard ? "discard" : "write")
-                                       : "read", error,
+                                       : "read", bio->bi_error,
                                (unsigned long long)peer_req->i.sector);
-       if (!error && !uptodate) {
-               if (__ratelimit(&drbd_ratelimit_state))
-                       drbd_warn(device, "%s: setting error to -EIO s=%llus\n",
-                                       is_write ? "write" : "read",
-                                       (unsigned long long)peer_req->i.sector);
-               /* strange behavior of some lower level drivers...
-                * fail the request by clearing the uptodate flag,
-                * but do not return any error?! */
-               error = -EIO;
-       }
 
-       if (error)
+       if (bio->bi_error)
                set_bit(__EE_WAS_ERROR, &peer_req->flags);
 
        bio_put(bio); /* no need for the bio anymore */
 
 /* read, readA or write requests on R_PRIMARY coming from drbd_make_request
  */
-void drbd_request_endio(struct bio *bio, int error)
+void drbd_request_endio(struct bio *bio)
 {
        unsigned long flags;
        struct drbd_request *req = bio->bi_private;
        struct drbd_device *device = req->device;
        struct bio_and_error m;
        enum drbd_req_event what;
-       int uptodate = bio_flagged(bio, BIO_UPTODATE);
-
-       if (!error && !uptodate) {
-               drbd_warn(device, "p %s: setting error to -EIO\n",
-                        bio_data_dir(bio) == WRITE ? "write" : "read");
-               /* strange behavior of some lower level drivers...
-                * fail the request by clearing the uptodate flag,
-                * but do not return any error?! */
-               error = -EIO;
-       }
-
 
        /* If this request was aborted locally before,
         * but now was completed "successfully",
                if (__ratelimit(&drbd_ratelimit_state))
                        drbd_emerg(device, "delayed completion of aborted local request; disk-timeout may be too aggressive\n");
 
-               if (!error)
+               if (!bio->bi_error)
                        panic("possible random memory corruption caused by delayed completion of aborted local request\n");
        }
 
        /* to avoid recursion in __req_mod */
-       if (unlikely(error)) {
+       if (unlikely(bio->bi_error)) {
                if (bio->bi_rw & REQ_DISCARD)
-                       what = (error == -EOPNOTSUPP)
+                       what = (bio->bi_error == -EOPNOTSUPP)
                                ? DISCARD_COMPLETED_NOTSUPP
                                : DISCARD_COMPLETED_WITH_ERROR;
                else
                what = COMPLETED_OK;
 
        bio_put(req->private_bio);
-       req->private_bio = ERR_PTR(error);
+       req->private_bio = ERR_PTR(bio->bi_error);
 
        /* not req_mod(), we need irqsave here! */
        spin_lock_irqsave(&device->resource->req_lock, flags);
 
        struct completion complete;
 };
 
-static void floppy_rb0_cb(struct bio *bio, int err)
+static void floppy_rb0_cb(struct bio *bio)
 {
        struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private;
        int drive = cbdata->drive;
 
-       if (err) {
-               pr_info("floppy: error %d while reading block 0\n", err);
+       if (bio->bi_error) {
+               pr_info("floppy: error %d while reading block 0\n",
+                       bio->bi_error);
                set_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
        }
        complete(&cbdata->complete);
 
                blk_end_request_all(cmd->rq, 0);
                break;
        case NULL_Q_BIO:
-               bio_endio(cmd->bio, 0);
+               bio_endio(cmd->bio);
                break;
        }
 
 
        }
 }
 
-static void pkt_end_io_read(struct bio *bio, int err)
+static void pkt_end_io_read(struct bio *bio)
 {
        struct packet_data *pkt = bio->bi_private;
        struct pktcdvd_device *pd = pkt->pd;
 
        pkt_dbg(2, pd, "bio=%p sec0=%llx sec=%llx err=%d\n",
                bio, (unsigned long long)pkt->sector,
-               (unsigned long long)bio->bi_iter.bi_sector, err);
+               (unsigned long long)bio->bi_iter.bi_sector, bio->bi_error);
 
-       if (err)
+       if (bio->bi_error)
                atomic_inc(&pkt->io_errors);
        if (atomic_dec_and_test(&pkt->io_wait)) {
                atomic_inc(&pkt->run_sm);
        pkt_bio_finished(pd);
 }
 
-static void pkt_end_io_packet_write(struct bio *bio, int err)
+static void pkt_end_io_packet_write(struct bio *bio)
 {
        struct packet_data *pkt = bio->bi_private;
        struct pktcdvd_device *pd = pkt->pd;
        BUG_ON(!pd);
 
-       pkt_dbg(2, pd, "id=%d, err=%d\n", pkt->id, err);
+       pkt_dbg(2, pd, "id=%d, err=%d\n", pkt->id, bio->bi_error);
 
        pd->stats.pkt_ended++;
 
        pkt_queue_bio(pd, pkt->w_bio);
 }
 
-static void pkt_finish_packet(struct packet_data *pkt, int uptodate)
+static void pkt_finish_packet(struct packet_data *pkt, int error)
 {
        struct bio *bio;
 
-       if (!uptodate)
+       if (error)
                pkt->cache_valid = 0;
 
        /* Finish all bios corresponding to this packet */
-       while ((bio = bio_list_pop(&pkt->orig_bios)))
-               bio_endio(bio, uptodate ? 0 : -EIO);
+       while ((bio = bio_list_pop(&pkt->orig_bios))) {
+               bio->bi_error = error;
+               bio_endio(bio);
+       }
 }
 
 static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data *pkt)
 {
-       int uptodate;
-
        pkt_dbg(2, pd, "pkt %d\n", pkt->id);
 
        for (;;) {
                        if (atomic_read(&pkt->io_wait) > 0)
                                return;
 
-                       if (test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags)) {
+                       if (!pkt->w_bio->bi_error) {
                                pkt_set_state(pkt, PACKET_FINISHED_STATE);
                        } else {
                                pkt_set_state(pkt, PACKET_RECOVERY_STATE);
                        break;
 
                case PACKET_FINISHED_STATE:
-                       uptodate = test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags);
-                       pkt_finish_packet(pkt, uptodate);
+                       pkt_finish_packet(pkt, pkt->w_bio->bi_error);
                        return;
 
                default:
 }
 
 
-static void pkt_end_io_read_cloned(struct bio *bio, int err)
+static void pkt_end_io_read_cloned(struct bio *bio)
 {
        struct packet_stacked_data *psd = bio->bi_private;
        struct pktcdvd_device *pd = psd->pd;
 
+       psd->bio->bi_error = bio->bi_error;
        bio_put(bio);
-       bio_endio(psd->bio, err);
+       bio_endio(psd->bio);
        mempool_free(psd, psd_pool);
        pkt_bio_finished(pd);
 }
 
        next = bio_list_peek(&priv->list);
        spin_unlock_irq(&priv->lock);
 
-       bio_endio(bio, error);
+       bio->bi_error = error;
+       bio_endio(bio);
        return next;
 }
 
 
                if (!card->eeh_state && card->gendisk)
                        disk_stats_complete(card, meta->bio, meta->start_time);
 
-               bio_endio(meta->bio, atomic_read(&meta->error) ? -EIO : 0);
+               if (atomic_read(&meta->error))
+                       bio_io_error(meta->bio);
+               else
+                       bio_endio(meta->bio);
                kmem_cache_free(bio_meta_pool, meta);
        }
 }
 queue_err:
        kmem_cache_free(bio_meta_pool, bio_meta);
 req_err:
-       bio_endio(bio, st);
+       if (st)
+               bio->bi_error = st;
+       bio_endio(bio);
 }
 
 /*----------------- Device Setup -------------------*/
 
                                PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
                if (control & DMASCR_HARD_ERROR) {
                        /* error */
-                       clear_bit(BIO_UPTODATE, &bio->bi_flags);
+                       bio->bi_error = -EIO;
                        dev_printk(KERN_WARNING, &card->dev->dev,
                                "I/O error on sector %d/%d\n",
                                le32_to_cpu(desc->local_addr)>>9,
 
                return_bio = bio->bi_next;
                bio->bi_next = NULL;
-               bio_endio(bio, 0);
+               bio_endio(bio);
        }
 }
 
 
 /*
  * bio callback.
  */
-static void end_block_io_op(struct bio *bio, int error)
+static void end_block_io_op(struct bio *bio)
 {
-       __end_block_io_op(bio->bi_private, error);
+       __end_block_io_op(bio->bi_private, bio->bi_error);
        bio_put(bio);
 }
 
 
 struct split_bio {
        struct bio *bio;
        atomic_t pending;
-       int err;
 };
 
 static DEFINE_MUTEX(blkfront_mutex);
        return 0;
 }
 
-static void split_bio_end(struct bio *bio, int error)
+static void split_bio_end(struct bio *bio)
 {
        struct split_bio *split_bio = bio->bi_private;
 
-       if (error)
-               split_bio->err = error;
-
        if (atomic_dec_and_test(&split_bio->pending)) {
                split_bio->bio->bi_phys_segments = 0;
-               bio_endio(split_bio->bio, split_bio->err);
+               split_bio->bio->bi_error = bio->bi_error;
+               bio_endio(split_bio->bio);
                kfree(split_bio);
        }
        bio_put(bio);
 
 
        if (unlikely(bio->bi_rw & REQ_DISCARD)) {
                zram_bio_discard(zram, index, offset, bio);
-               bio_endio(bio, 0);
+               bio_endio(bio);
                return;
        }
 
                update_position(&index, &offset, &bvec);
        }
 
-       set_bit(BIO_UPTODATE, &bio->bi_flags);
-       bio_endio(bio, 0);
+       bio_endio(bio);
        return;
 
 out:
 
        goto out;
 }
 
-static void btree_node_read_endio(struct bio *bio, int error)
+static void btree_node_read_endio(struct bio *bio)
 {
        struct closure *cl = bio->bi_private;
        closure_put(cl);
        bch_submit_bbio(bio, b->c, &b->key, 0);
        closure_sync(&cl);
 
-       if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
+       if (bio->bi_error)
                set_btree_node_io_error(b);
 
        bch_bbio_free(bio, b->c);
        __btree_node_write_done(cl);
 }
 
-static void btree_node_write_endio(struct bio *bio, int error)
+static void btree_node_write_endio(struct bio *bio)
 {
        struct closure *cl = bio->bi_private;
        struct btree *b = container_of(cl, struct btree, io);
 
-       if (error)
+       if (bio->bi_error)
                set_btree_node_io_error(b);
 
-       bch_bbio_count_io_errors(b->c, bio, error, "writing btree");
+       bch_bbio_count_io_errors(b->c, bio, bio->bi_error, "writing btree");
        closure_put(cl);
 }
 
 
  * they are running owned by the thread that is running them. Otherwise, suppose
  * you submit some bios and wish to have a function run when they all complete:
  *
- * foo_endio(struct bio *bio, int error)
+ * foo_endio(struct bio *bio)
  * {
  *     closure_put(cl);
  * }
 
 
        s->bio->bi_end_io = s->bi_end_io;
        s->bio->bi_private = s->bi_private;
-       bio_endio(s->bio, 0);
+       bio_endio(s->bio);
 
        closure_debug_destroy(&s->cl);
        mempool_free(s, s->p->bio_split_hook);
 }
 
-static void bch_bio_submit_split_endio(struct bio *bio, int error)
+static void bch_bio_submit_split_endio(struct bio *bio)
 {
        struct closure *cl = bio->bi_private;
        struct bio_split_hook *s = container_of(cl, struct bio_split_hook, cl);
 
-       if (error)
-               clear_bit(BIO_UPTODATE, &s->bio->bi_flags);
+       if (bio->bi_error)
+               s->bio->bi_error = bio->bi_error;
 
        bio_put(bio);
        closure_put(cl);
 
  * bit.
  */
 
-static void journal_read_endio(struct bio *bio, int error)
+static void journal_read_endio(struct bio *bio)
 {
        struct closure *cl = bio->bi_private;
        closure_put(cl);
 
 #define last_seq(j)    ((j)->seq - fifo_used(&(j)->pin) + 1)
 
-static void journal_discard_endio(struct bio *bio, int error)
+static void journal_discard_endio(struct bio *bio)
 {
        struct journal_device *ja =
                container_of(bio, struct journal_device, discard_bio);
                pr_debug("journal_pin full (%zu)", fifo_used(&j->pin));
 }
 
-static void journal_write_endio(struct bio *bio, int error)
+static void journal_write_endio(struct bio *bio)
 {
        struct journal_write *w = bio->bi_private;
 
-       cache_set_err_on(error, w->c, "journal io error");
+       cache_set_err_on(bio->bi_error, w->c, "journal io error");
        closure_put(&w->c->journal.io);
 }
 
 
        closure_return_with_destructor(cl, moving_io_destructor);
 }
 
-static void read_moving_endio(struct bio *bio, int error)
+static void read_moving_endio(struct bio *bio)
 {
        struct bbio *b = container_of(bio, struct bbio, bio);
        struct moving_io *io = container_of(bio->bi_private,
                                            struct moving_io, cl);
 
-       if (error)
-               io->op.error = error;
+       if (bio->bi_error)
+               io->op.error = bio->bi_error;
        else if (!KEY_DIRTY(&b->key) &&
                 ptr_stale(io->op.c, &b->key, 0)) {
                io->op.error = -EINTR;
        }
 
-       bch_bbio_endio(io->op.c, bio, error, "reading data to move");
+       bch_bbio_endio(io->op.c, bio, bio->bi_error, "reading data to move");
 }
 
 static void moving_init(struct moving_io *io)
 
        bch_data_insert_keys(cl);
 }
 
-static void bch_data_insert_endio(struct bio *bio, int error)
+static void bch_data_insert_endio(struct bio *bio)
 {
        struct closure *cl = bio->bi_private;
        struct data_insert_op *op = container_of(cl, struct data_insert_op, cl);
 
-       if (error) {
+       if (bio->bi_error) {
                /* TODO: We could try to recover from this. */
                if (op->writeback)
-                       op->error = error;
+                       op->error = bio->bi_error;
                else if (!op->replace)
                        set_closure_fn(cl, bch_data_insert_error, op->wq);
                else
                        set_closure_fn(cl, NULL, NULL);
        }
 
-       bch_bbio_endio(op->c, bio, error, "writing data to cache");
+       bch_bbio_endio(op->c, bio, bio->bi_error, "writing data to cache");
 }
 
 static void bch_data_insert_start(struct closure *cl)
        struct data_insert_op   iop;
 };
 
-static void bch_cache_read_endio(struct bio *bio, int error)
+static void bch_cache_read_endio(struct bio *bio)
 {
        struct bbio *b = container_of(bio, struct bbio, bio);
        struct closure *cl = bio->bi_private;
         * from the backing device.
         */
 
-       if (error)
-               s->iop.error = error;
+       if (bio->bi_error)
+               s->iop.error = bio->bi_error;
        else if (!KEY_DIRTY(&b->key) &&
                 ptr_stale(s->iop.c, &b->key, 0)) {
                atomic_long_inc(&s->iop.c->cache_read_races);
                s->iop.error = -EINTR;
        }
 
-       bch_bbio_endio(s->iop.c, bio, error, "reading from cache");
+       bch_bbio_endio(s->iop.c, bio, bio->bi_error, "reading from cache");
 }
 
 /*
 
 /* Common code for the make_request functions */
 
-static void request_endio(struct bio *bio, int error)
+static void request_endio(struct bio *bio)
 {
        struct closure *cl = bio->bi_private;
 
-       if (error) {
+       if (bio->bi_error) {
                struct search *s = container_of(cl, struct search, cl);
-               s->iop.error = error;
+               s->iop.error = bio->bi_error;
                /* Only cache read errors are recoverable */
                s->recoverable = false;
        }
                                    &s->d->disk->part0, s->start_time);
 
                trace_bcache_request_end(s->d, s->orig_bio);
-               bio_endio(s->orig_bio, s->iop.error);
+               s->orig_bio->bi_error = s->iop.error;
+               bio_endio(s->orig_bio);
                s->orig_bio = NULL;
        }
 }
        } else {
                if ((bio->bi_rw & REQ_DISCARD) &&
                    !blk_queue_discard(bdev_get_queue(dc->bdev)))
-                       bio_endio(bio, 0);
+                       bio_endio(bio);
                else
                        bch_generic_make_request(bio, &d->bio_split_hook);
        }
 
        return err;
 }
 
-static void write_bdev_super_endio(struct bio *bio, int error)
+static void write_bdev_super_endio(struct bio *bio)
 {
        struct cached_dev *dc = bio->bi_private;
        /* XXX: error checking */
        closure_return_with_destructor(cl, bch_write_bdev_super_unlock);
 }
 
-static void write_super_endio(struct bio *bio, int error)
+static void write_super_endio(struct bio *bio)
 {
        struct cache *ca = bio->bi_private;
 
-       bch_count_io_errors(ca, error, "writing superblock");
+       bch_count_io_errors(ca, bio->bi_error, "writing superblock");
        closure_put(&ca->set->sb_write);
 }
 
 
 /* UUID io */
 
-static void uuid_endio(struct bio *bio, int error)
+static void uuid_endio(struct bio *bio)
 {
        struct closure *cl = bio->bi_private;
        struct cache_set *c = container_of(cl, struct cache_set, uuid_write);
 
-       cache_set_err_on(error, c, "accessing uuids");
+       cache_set_err_on(bio->bi_error, c, "accessing uuids");
        bch_bbio_free(bio, c);
        closure_put(cl);
 }
  * disk.
  */
 
-static void prio_endio(struct bio *bio, int error)
+static void prio_endio(struct bio *bio)
 {
        struct cache *ca = bio->bi_private;
 
-       cache_set_err_on(error, ca->set, "accessing priorities");
+       cache_set_err_on(bio->bi_error, ca->set, "accessing priorities");
        bch_bbio_free(bio, ca->set);
        closure_put(&ca->prio);
 }
 
        closure_return_with_destructor(cl, dirty_io_destructor);
 }
 
-static void dirty_endio(struct bio *bio, int error)
+static void dirty_endio(struct bio *bio)
 {
        struct keybuf_key *w = bio->bi_private;
        struct dirty_io *io = w->private;
 
-       if (error)
+       if (bio->bi_error)
                SET_KEY_DIRTY(&w->key, false);
 
        closure_put(&io->cl);
        continue_at(cl, write_dirty_finish, system_wq);
 }
 
-static void read_dirty_endio(struct bio *bio, int error)
+static void read_dirty_endio(struct bio *bio)
 {
        struct keybuf_key *w = bio->bi_private;
        struct dirty_io *io = w->private;
 
        bch_count_io_errors(PTR_CACHE(io->dc->disk.c, &w->key, 0),
-                           error, "reading dirty data from cache");
+                           bio->bi_error, "reading dirty data from cache");
 
-       dirty_endio(bio, error);
+       dirty_endio(bio);
 }
 
 static void read_dirty_submit(struct closure *cl)
 
        bio_list_init(&bios);
        dm_cell_release(prison, cell, &bios);
 
-       while ((bio = bio_list_pop(&bios)))
-               bio_endio(bio, error);
+       while ((bio = bio_list_pop(&bios))) {
+               bio->bi_error = error;
+               bio_endio(bio);
+       }
 }
 EXPORT_SYMBOL_GPL(dm_cell_error);
 
 
 {
        struct dm_buffer *b = context;
 
-       b->bio.bi_end_io(&b->bio, error ? -EIO : 0);
+       b->bio.bi_error = error ? -EIO : 0;
+       b->bio.bi_end_io(&b->bio);
 }
 
 static void use_dmio(struct dm_buffer *b, int rw, sector_t block,
        b->bio.bi_end_io = end_io;
 
        r = dm_io(&io_req, 1, ®ion, NULL);
-       if (r)
-               end_io(&b->bio, r);
+       if (r) {
+               b->bio.bi_error = r;
+               end_io(&b->bio);
+       }
 }
 
-static void inline_endio(struct bio *bio, int error)
+static void inline_endio(struct bio *bio)
 {
        bio_end_io_t *end_fn = bio->bi_private;
+       int error = bio->bi_error;
 
        /*
         * Reset the bio to free any attached resources
         */
        bio_reset(bio);
 
-       end_fn(bio, error);
+       bio->bi_error = error;
+       end_fn(bio);
 }
 
 static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block,
  * Set the error, clear B_WRITING bit and wake anyone who was waiting on
  * it.
  */
-static void write_endio(struct bio *bio, int error)
+static void write_endio(struct bio *bio)
 {
        struct dm_buffer *b = container_of(bio, struct dm_buffer, bio);
 
-       b->write_error = error;
-       if (unlikely(error)) {
+       b->write_error = bio->bi_error;
+       if (unlikely(bio->bi_error)) {
                struct dm_bufio_client *c = b->c;
+               int error = bio->bi_error;
                (void)cmpxchg(&c->async_write_error, 0, error);
        }
 
  * The endio routine for reading: set the error, clear the bit and wake up
  * anyone waiting on the buffer.
  */
-static void read_endio(struct bio *bio, int error)
+static void read_endio(struct bio *bio)
 {
        struct dm_buffer *b = container_of(bio, struct dm_buffer, bio);
 
-       b->read_error = error;
+       b->read_error = bio->bi_error;
 
        BUG_ON(!test_bit(B_READING, &b->state));
 
 
        wake_worker(cache);
 }
 
-static void writethrough_endio(struct bio *bio, int err)
+static void writethrough_endio(struct bio *bio)
 {
        struct per_bio_data *pb = get_per_bio_data(bio, PB_DATA_SIZE_WT);
 
        dm_unhook_bio(&pb->hook_info, bio);
 
-       if (err) {
-               bio_endio(bio, err);
+       if (bio->bi_error) {
+               bio_endio(bio);
                return;
        }
 
                         * The block was promoted via an overwrite, so it's dirty.
                         */
                        set_dirty(cache, mg->new_oblock, mg->cblock);
-                       bio_endio(mg->new_ocell->holder, 0);
+                       bio_endio(mg->new_ocell->holder);
                        cell_defer(cache, mg->new_ocell, false);
                }
                free_io_migration(mg);
        }
 }
 
-static void overwrite_endio(struct bio *bio, int err)
+static void overwrite_endio(struct bio *bio)
 {
        struct dm_cache_migration *mg = bio->bi_private;
        struct cache *cache = mg->cache;
 
        dm_unhook_bio(&pb->hook_info, bio);
 
-       if (err)
+       if (bio->bi_error)
                mg->err = true;
 
        mg->requeue_holder = false;
                b = to_dblock(from_dblock(b) + 1);
        }
 
-       bio_endio(bio, 0);
+       bio_endio(bio);
        cell_defer(mg->cache, mg->new_ocell, false);
        free_migration(mg);
 }
 
        calc_discard_block_range(cache, bio, &b, &e);
        if (b == e) {
-               bio_endio(bio, 0);
+               bio_endio(bio);
                return;
        }
 
        bio_list_merge(&bios, &cache->deferred_bios);
        bio_list_init(&cache->deferred_bios);
 
-       while ((bio = bio_list_pop(&bios)))
-               bio_endio(bio, DM_ENDIO_REQUEUE);
+       while ((bio = bio_list_pop(&bios))) {
+               bio->bi_error = DM_ENDIO_REQUEUE;
+               bio_endio(bio);
+       }
 }
 
 static int more_work(struct cache *cache)
                         * This is a duplicate writethrough io that is no
                         * longer needed because the block has been demoted.
                         */
-                       bio_endio(bio, 0);
+                       bio_endio(bio);
                        // FIXME: remap everything as a miss
                        cell_defer(cache, cell, false);
                        r = DM_MAPIO_SUBMITTED;
 
        if (io->ctx.req)
                crypt_free_req(cc, io->ctx.req, base_bio);
 
-       bio_endio(base_bio, error);
+       base_bio->bi_error = error;
+       bio_endio(base_bio);
 }
 
 /*
  * The work is done per CPU global for all dm-crypt instances.
  * They should not depend on each other and do not block.
  */
-static void crypt_endio(struct bio *clone, int error)
+static void crypt_endio(struct bio *clone)
 {
        struct dm_crypt_io *io = clone->bi_private;
        struct crypt_config *cc = io->cc;
        unsigned rw = bio_data_dir(clone);
 
-       if (unlikely(!bio_flagged(clone, BIO_UPTODATE) && !error))
-               error = -EIO;
-
        /*
         * free the processed pages
         */
 
        bio_put(clone);
 
-       if (rw == READ && !error) {
+       if (rw == READ && !clone->bi_error) {
                kcryptd_queue_crypt(io);
                return;
        }
 
-       if (unlikely(error))
-               io->error = error;
+       if (unlikely(clone->bi_error))
+               io->error = clone->bi_error;
 
        crypt_dec_pending(io);
 }
 
                 * Drop writes?
                 */
                if (test_bit(DROP_WRITES, &fc->flags)) {
-                       bio_endio(bio, 0);
+                       bio_endio(bio);
                        return DM_MAPIO_SUBMITTED;
                }
 
 
                complete_io(io);
 }
 
-static void endio(struct bio *bio, int error)
+static void endio(struct bio *bio)
 {
        struct io *io;
        unsigned region;
 
-       if (error && bio_data_dir(bio) == READ)
+       if (bio->bi_error && bio_data_dir(bio) == READ)
                zero_fill_bio(bio);
 
        /*
 
        bio_put(bio);
 
-       dec_count(io, region, error);
+       dec_count(io, region, bio->bi_error);
 }
 
 /*-----------------------------------------------------------------
 
        }
 }
 
-static void log_end_io(struct bio *bio, int err)
+static void log_end_io(struct bio *bio)
 {
        struct log_writes_c *lc = bio->bi_private;
        struct bio_vec *bvec;
        int i;
 
-       if (err) {
+       if (bio->bi_error) {
                unsigned long flags;
 
-               DMERR("Error writing log block, error=%d", err);
+               DMERR("Error writing log block, error=%d", bio->bi_error);
                spin_lock_irqsave(&lc->blocks_lock, flags);
                lc->logging_enabled = false;
                spin_unlock_irqrestore(&lc->blocks_lock, flags);
        bio->bi_bdev = lc->logdev->bdev;
        bio->bi_end_io = log_end_io;
        bio->bi_private = lc;
-       set_bit(BIO_UPTODATE, &bio->bi_flags);
 
        page = alloc_page(GFP_KERNEL);
        if (!page) {
        bio->bi_bdev = lc->logdev->bdev;
        bio->bi_end_io = log_end_io;
        bio->bi_private = lc;
-       set_bit(BIO_UPTODATE, &bio->bi_flags);
 
        for (i = 0; i < block->vec_cnt; i++) {
                /*
                        bio->bi_bdev = lc->logdev->bdev;
                        bio->bi_end_io = log_end_io;
                        bio->bi_private = lc;
-                       set_bit(BIO_UPTODATE, &bio->bi_flags);
 
                        ret = bio_add_page(bio, block->vecs[i].bv_page,
                                           block->vecs[i].bv_len, 0);
                WARN_ON(flush_bio || fua_bio);
                if (lc->device_supports_discard)
                        goto map_bio;
-               bio_endio(bio, 0);
+               bio_endio(bio);
                return DM_MAPIO_SUBMITTED;
        }
 
 
                 * If device is suspended, complete the bio.
                 */
                if (dm_noflush_suspending(ms->ti))
-                       bio_endio(bio, DM_ENDIO_REQUEUE);
+                       bio->bi_error = DM_ENDIO_REQUEUE;
                else
-                       bio_endio(bio, -EIO);
+                       bio->bi_error = -EIO;
+
+               bio_endio(bio);
                return;
        }
 
        bio_set_m(bio, NULL);
 
        if (likely(!error)) {
-               bio_endio(bio, 0);
+               bio_endio(bio);
                return;
        }
 
 
        DMERR_LIMIT("Read failure on mirror device %s.  Failing I/O.",
                    m->dev->name);
-       bio_endio(bio, -EIO);
+       bio_io_error(bio);
 }
 
 /* Asynchronous read. */
                if (likely(m))
                        read_async_bio(m, bio);
                else
-                       bio_endio(bio, -EIO);
+                       bio_io_error(bio);
        }
 }
 
 
 static void write_callback(unsigned long error, void *context)
 {
-       unsigned i, ret = 0;
+       unsigned i;
        struct bio *bio = (struct bio *) context;
        struct mirror_set *ms;
        int should_wake = 0;
         * regions with the same code.
         */
        if (likely(!error)) {
-               bio_endio(bio, ret);
+               bio_endio(bio);
                return;
        }
 
         * degrade the array.
         */
        if (bio->bi_rw & REQ_DISCARD) {
-               bio_endio(bio, -EOPNOTSUPP);
+               bio->bi_error = -EOPNOTSUPP;
+               bio_endio(bio);
                return;
        }
 
                 * be wrong if the failed leg returned after reboot and
                 * got replicated back to the good legs.)
                 */
-
                if (unlikely(!get_valid_mirror(ms) || (keep_log(ms) && ms->log_failure)))
-                       bio_endio(bio, -EIO);
+                       bio_io_error(bio);
                else if (errors_handled(ms) && !keep_log(ms))
                        hold_bio(ms, bio);
                else
-                       bio_endio(bio, 0);
+                       bio_endio(bio);
        }
 }
 
 
                error_bios(snapshot_bios);
        } else {
                if (full_bio)
-                       bio_endio(full_bio, 0);
+                       bio_endio(full_bio);
                flush_bios(snapshot_bios);
        }
 
        dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, copy_callback, pe);
 }
 
-static void full_bio_end_io(struct bio *bio, int error)
+static void full_bio_end_io(struct bio *bio)
 {
        void *callback_data = bio->bi_private;
 
-       dm_kcopyd_do_callback(callback_data, 0, error ? 1 : 0);
+       dm_kcopyd_do_callback(callback_data, 0, bio->bi_error ? 1 : 0);
 }
 
 static void start_full_bio(struct dm_snap_pending_exception *pe,
 
                return DM_MAPIO_REMAPPED;
        } else {
                /* The range doesn't map to the target stripe */
-               bio_endio(bio, 0);
+               bio_endio(bio);
                return DM_MAPIO_SUBMITTED;
        }
 }
 
 {
        struct bio *bio;
 
-       while ((bio = bio_list_pop(bios)))
-               bio_endio(bio, error);
+       while ((bio = bio_list_pop(bios))) {
+               bio->bi_error = error;
+               bio_endio(bio);
+       }
 }
 
 static void error_thin_bio_list(struct thin_c *tc, struct bio_list *master, int error)
        complete_mapping_preparation(m);
 }
 
-static void overwrite_endio(struct bio *bio, int err)
+static void overwrite_endio(struct bio *bio)
 {
        struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
        struct dm_thin_new_mapping *m = h->overwrite_mapping;
 
        bio->bi_end_io = m->saved_bi_end_io;
 
-       m->err = err;
+       m->err = bio->bi_error;
        complete_mapping_preparation(m);
 }
 
         */
        if (bio) {
                inc_remap_and_issue_cell(tc, m->cell, m->data_block);
-               bio_endio(bio, 0);
+               bio_endio(bio);
        } else {
                inc_all_io_entry(tc->pool, m->cell->holder);
                remap_and_issue(tc, m->cell->holder, m->data_block);
 
 static void process_prepared_discard_success(struct dm_thin_new_mapping *m)
 {
-       bio_endio(m->bio, 0);
+       bio_endio(m->bio);
        free_discard_mapping(m);
 }
 
                metadata_operation_failed(tc->pool, "dm_thin_remove_range", r);
                bio_io_error(m->bio);
        } else
-               bio_endio(m->bio, 0);
+               bio_endio(m->bio);
 
        cell_defer_no_holder(tc, m->cell);
        mempool_free(m, tc->pool->mapping_pool);
         * Even if r is set, there could be sub discards in flight that we
         * need to wait for.
         */
-       bio_endio(m->bio, r);
+       m->bio->bi_error = r;
+       bio_endio(m->bio);
        cell_defer_no_holder(tc, m->cell);
        mempool_free(m, pool->mapping_pool);
 }
 {
        int error = should_error_unserviceable_bio(pool);
 
-       if (error)
-               bio_endio(bio, error);
-       else
+       if (error) {
+               bio->bi_error = error;
+               bio_endio(bio);
+       } else
                retry_on_resume(bio);
 }
 
         * will prevent completion until the sub range discards have
         * completed.
         */
-       bio_endio(bio, 0);
+       bio_endio(bio);
 }
 
 static void process_discard_bio(struct thin_c *tc, struct bio *bio)
                /*
                 * The discard covers less than a block.
                 */
-               bio_endio(bio, 0);
+               bio_endio(bio);
                return;
        }
 
        if (bio_data_dir(bio) == READ) {
                zero_fill_bio(bio);
                cell_defer_no_holder(tc, cell);
-               bio_endio(bio, 0);
+               bio_endio(bio);
                return;
        }
 
 
                        } else {
                                zero_fill_bio(bio);
-                               bio_endio(bio, 0);
+                               bio_endio(bio);
                        }
                } else
                        provision_block(tc, bio, block, cell);
                }
 
                zero_fill_bio(bio);
-               bio_endio(bio, 0);
+               bio_endio(bio);
                break;
 
        default:
 
 static void process_bio_success(struct thin_c *tc, struct bio *bio)
 {
-       bio_endio(bio, 0);
+       bio_endio(bio);
 }
 
 static void process_bio_fail(struct thin_c *tc, struct bio *bio)
        thin_hook_bio(tc, bio);
 
        if (tc->requeue_mode) {
-               bio_endio(bio, DM_ENDIO_REQUEUE);
+               bio->bi_error = DM_ENDIO_REQUEUE;
+               bio_endio(bio);
                return DM_MAPIO_SUBMITTED;
        }
 
 
 
        bio->bi_end_io = io->orig_bi_end_io;
        bio->bi_private = io->orig_bi_private;
+       bio->bi_error = error;
 
-       bio_endio(bio, error);
+       bio_endio(bio);
 }
 
 static void verity_work(struct work_struct *w)
        verity_finish_io(io, verity_verify_io(io));
 }
 
-static void verity_end_io(struct bio *bio, int error)
+static void verity_end_io(struct bio *bio)
 {
        struct dm_verity_io *io = bio->bi_private;
 
-       if (error) {
-               verity_finish_io(io, error);
+       if (bio->bi_error) {
+               verity_finish_io(io, bio->bi_error);
                return;
        }
 
 
                break;
        }
 
-       bio_endio(bio, 0);
+       bio_endio(bio);
 
        /* accepted bio, don't make new request */
        return DM_MAPIO_SUBMITTED;
 
                } else {
                        /* done with normal IO or empty flush */
                        trace_block_bio_complete(md->queue, bio, io_error);
-                       bio_endio(bio, io_error);
+                       bio->bi_error = io_error;
+                       bio_endio(bio);
                }
        }
 }
        limits->max_write_same_sectors = 0;
 }
 
-static void clone_endio(struct bio *bio, int error)
+static void clone_endio(struct bio *bio)
 {
+       int error = bio->bi_error;
        int r = error;
        struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone);
        struct dm_io *io = tio->io;
        struct mapped_device *md = tio->io->md;
        dm_endio_fn endio = tio->ti->type->end_io;
 
-       if (!bio_flagged(bio, BIO_UPTODATE) && !error)
-               error = -EIO;
-
        if (endio) {
                r = endio(tio->ti, bio, error);
                if (r < 0 || r == DM_ENDIO_REQUEUE)
 /*
  * Partial completion handling for request-based dm
  */
-static void end_clone_bio(struct bio *clone, int error)
+static void end_clone_bio(struct bio *clone)
 {
        struct dm_rq_clone_bio_info *info =
                container_of(clone, struct dm_rq_clone_bio_info, clone);
                 * the remainder.
                 */
                return;
-       else if (error) {
+       else if (bio->bi_error) {
                /*
                 * Don't notice the error to the upper layer yet.
                 * The error handling decision is made by the target driver,
                 * when the request is completed.
                 */
-               tio->error = error;
+               tio->error = bio->bi_error;
                return;
        }
 
 
 #include <linux/seq_file.h>
 
 
-static void faulty_fail(struct bio *bio, int error)
+static void faulty_fail(struct bio *bio)
 {
        struct bio *b = bio->bi_private;
 
                        /* special case - don't decrement, don't generic_make_request,
                         * just fail immediately
                         */
-                       bio_endio(bio, -EIO);
+                       bio_io_error(bio);
                        return;
                }
 
 
                if (unlikely((split->bi_rw & REQ_DISCARD) &&
                         !blk_queue_discard(bdev_get_queue(split->bi_bdev)))) {
                        /* Just ignore it */
-                       bio_endio(split, 0);
+                       bio_endio(split);
                } else
                        generic_make_request(split);
        } while (split != bio);
 
                return;
        }
        if (mddev->ro == 1 && unlikely(rw == WRITE)) {
-               bio_endio(bio, bio_sectors(bio) == 0 ? 0 : -EROFS);
+               if (bio_sectors(bio) != 0)
+                       bio->bi_error = -EROFS;
+               bio_endio(bio);
                return;
        }
        smp_rmb(); /* Ensure implications of  'active' are visible */
  * Generic flush handling for md
  */
 
-static void md_end_flush(struct bio *bio, int err)
+static void md_end_flush(struct bio *bio)
 {
        struct md_rdev *rdev = bio->bi_private;
        struct mddev *mddev = rdev->mddev;
 
        if (bio->bi_iter.bi_size == 0)
                /* an empty barrier - all done */
-               bio_endio(bio, 0);
+               bio_endio(bio);
        else {
                bio->bi_rw &= ~REQ_FLUSH;
                mddev->pers->make_request(mddev, bio);
 }
 EXPORT_SYMBOL_GPL(md_rdev_clear);
 
-static void super_written(struct bio *bio, int error)
+static void super_written(struct bio *bio)
 {
        struct md_rdev *rdev = bio->bi_private;
        struct mddev *mddev = rdev->mddev;
 
-       if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) {
-               printk("md: super_written gets error=%d, uptodate=%d\n",
-                      error, test_bit(BIO_UPTODATE, &bio->bi_flags));
-               WARN_ON(test_bit(BIO_UPTODATE, &bio->bi_flags));
+       if (bio->bi_error) {
+               printk("md: super_written gets error=%d\n", bio->bi_error);
                md_error(mddev, rdev);
        }
 
        bio_add_page(bio, page, size, 0);
        submit_bio_wait(rw, bio);
 
-       ret = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       ret = !bio->bi_error;
        bio_put(bio);
        return ret;
 }
 
        struct bio *bio = mp_bh->master_bio;
        struct mpconf *conf = mp_bh->mddev->private;
 
-       bio_endio(bio, err);
+       bio->bi_error = err;
+       bio_endio(bio);
        mempool_free(mp_bh, conf->pool);
 }
 
-static void multipath_end_request(struct bio *bio, int error)
+static void multipath_end_request(struct bio *bio)
 {
-       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct multipath_bh *mp_bh = bio->bi_private;
        struct mpconf *conf = mp_bh->mddev->private;
        struct md_rdev *rdev = conf->multipaths[mp_bh->path].rdev;
 
-       if (uptodate)
+       if (!bio->bi_error)
                multipath_end_bh_io(mp_bh, 0);
        else if (!(bio->bi_rw & REQ_RAHEAD)) {
                /*
                       (unsigned long long)bio->bi_iter.bi_sector);
                multipath_reschedule_retry(mp_bh);
        } else
-               multipath_end_bh_io(mp_bh, error);
+               multipath_end_bh_io(mp_bh, bio->bi_error);
        rdev_dec_pending(rdev, conf->mddev);
 }
 
 
        mp_bh->path = multipath_map(conf);
        if (mp_bh->path < 0) {
-               bio_endio(bio, -EIO);
+               bio_io_error(bio);
                mempool_free(mp_bh, conf->pool);
                return;
        }
 
                if (unlikely((split->bi_rw & REQ_DISCARD) &&
                         !blk_queue_discard(bdev_get_queue(split->bi_bdev)))) {
                        /* Just ignore it */
-                       bio_endio(split, 0);
+                       bio_endio(split);
                } else
                        generic_make_request(split);
        } while (split != bio);
 
                done = 1;
 
        if (!test_bit(R1BIO_Uptodate, &r1_bio->state))
-               clear_bit(BIO_UPTODATE, &bio->bi_flags);
+               bio->bi_error = -EIO;
+
        if (done) {
-               bio_endio(bio, 0);
+               bio_endio(bio);
                /*
                 * Wake up any possible resync thread that waits for the device
                 * to go idle.
        return mirror;
 }
 
-static void raid1_end_read_request(struct bio *bio, int error)
+static void raid1_end_read_request(struct bio *bio)
 {
-       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       int uptodate = !bio->bi_error;
        struct r1bio *r1_bio = bio->bi_private;
        int mirror;
        struct r1conf *conf = r1_bio->mddev->private;
        }
 }
 
-static void raid1_end_write_request(struct bio *bio, int error)
+static void raid1_end_write_request(struct bio *bio)
 {
-       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct r1bio *r1_bio = bio->bi_private;
        int mirror, behind = test_bit(R1BIO_BehindIO, &r1_bio->state);
        struct r1conf *conf = r1_bio->mddev->private;
        /*
         * 'one mirror IO has finished' event handler:
         */
-       if (!uptodate) {
+       if (bio->bi_error) {
                set_bit(WriteErrorSeen,
                        &conf->mirrors[mirror].rdev->flags);
                if (!test_and_set_bit(WantReplacement,
                        if (unlikely((bio->bi_rw & REQ_DISCARD) &&
                            !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
                                /* Just ignore it */
-                               bio_endio(bio, 0);
+                               bio_endio(bio);
                        else
                                generic_make_request(bio);
                        bio = next;
                if (unlikely((bio->bi_rw & REQ_DISCARD) &&
                    !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
                        /* Just ignore it */
-                       bio_endio(bio, 0);
+                       bio_endio(bio);
                else
                        generic_make_request(bio);
                bio = next;
        return err;
 }
 
-static void end_sync_read(struct bio *bio, int error)
+static void end_sync_read(struct bio *bio)
 {
        struct r1bio *r1_bio = bio->bi_private;
 
         * or re-read if the read failed.
         * We don't do much here, just schedule handling by raid1d
         */
-       if (test_bit(BIO_UPTODATE, &bio->bi_flags))
+       if (!bio->bi_error)
                set_bit(R1BIO_Uptodate, &r1_bio->state);
 
        if (atomic_dec_and_test(&r1_bio->remaining))
                reschedule_retry(r1_bio);
 }
 
-static void end_sync_write(struct bio *bio, int error)
+static void end_sync_write(struct bio *bio)
 {
-       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       int uptodate = !bio->bi_error;
        struct r1bio *r1_bio = bio->bi_private;
        struct mddev *mddev = r1_bio->mddev;
        struct r1conf *conf = mddev->private;
                idx ++;
        }
        set_bit(R1BIO_Uptodate, &r1_bio->state);
-       set_bit(BIO_UPTODATE, &bio->bi_flags);
+       bio->bi_error = 0;
        return 1;
 }
 
        for (i = 0; i < conf->raid_disks * 2; i++) {
                int j;
                int size;
-               int uptodate;
+               int error;
                struct bio *b = r1_bio->bios[i];
                if (b->bi_end_io != end_sync_read)
                        continue;
-               /* fixup the bio for reuse, but preserve BIO_UPTODATE */
-               uptodate = test_bit(BIO_UPTODATE, &b->bi_flags);
+               /* fixup the bio for reuse, but preserve errno */
+               error = b->bi_error;
                bio_reset(b);
-               if (!uptodate)
-                       clear_bit(BIO_UPTODATE, &b->bi_flags);
+               b->bi_error = error;
                b->bi_vcnt = vcnt;
                b->bi_iter.bi_size = r1_bio->sectors << 9;
                b->bi_iter.bi_sector = r1_bio->sector +
        }
        for (primary = 0; primary < conf->raid_disks * 2; primary++)
                if (r1_bio->bios[primary]->bi_end_io == end_sync_read &&
-                   test_bit(BIO_UPTODATE, &r1_bio->bios[primary]->bi_flags)) {
+                   !r1_bio->bios[primary]->bi_error) {
                        r1_bio->bios[primary]->bi_end_io = NULL;
                        rdev_dec_pending(conf->mirrors[primary].rdev, mddev);
                        break;
                int j;
                struct bio *pbio = r1_bio->bios[primary];
                struct bio *sbio = r1_bio->bios[i];
-               int uptodate = test_bit(BIO_UPTODATE, &sbio->bi_flags);
+               int error = sbio->bi_error;
 
                if (sbio->bi_end_io != end_sync_read)
                        continue;
-               /* Now we can 'fixup' the BIO_UPTODATE flag */
-               set_bit(BIO_UPTODATE, &sbio->bi_flags);
+               /* Now we can 'fixup' the error value */
+               sbio->bi_error = 0;
 
-               if (uptodate) {
+               if (!error) {
                        for (j = vcnt; j-- ; ) {
                                struct page *p, *s;
                                p = pbio->bi_io_vec[j].bv_page;
                if (j >= 0)
                        atomic64_add(r1_bio->sectors, &mddev->resync_mismatches);
                if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)
-                             && uptodate)) {
+                             && !error)) {
                        /* No need to write to this device. */
                        sbio->bi_end_io = NULL;
                        rdev_dec_pending(conf->mirrors[i].rdev, mddev);
                struct bio *bio = r1_bio->bios[m];
                if (bio->bi_end_io == NULL)
                        continue;
-               if (test_bit(BIO_UPTODATE, &bio->bi_flags) &&
+               if (!bio->bi_error &&
                    test_bit(R1BIO_MadeGood, &r1_bio->state)) {
                        rdev_clear_badblocks(rdev, r1_bio->sector, s, 0);
                }
-               if (!test_bit(BIO_UPTODATE, &bio->bi_flags) &&
+               if (bio->bi_error &&
                    test_bit(R1BIO_WriteError, &r1_bio->state)) {
                        if (!rdev_set_badblocks(rdev, r1_bio->sector, s, 0))
                                md_error(conf->mddev, rdev);
 
 static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
                                int *skipped);
 static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio);
-static void end_reshape_write(struct bio *bio, int error);
+static void end_reshape_write(struct bio *bio);
 static void end_reshape(struct r10conf *conf);
 
 static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
        } else
                done = 1;
        if (!test_bit(R10BIO_Uptodate, &r10_bio->state))
-               clear_bit(BIO_UPTODATE, &bio->bi_flags);
+               bio->bi_error = -EIO;
        if (done) {
-               bio_endio(bio, 0);
+               bio_endio(bio);
                /*
                 * Wake up any possible resync thread that waits for the device
                 * to go idle.
        return r10_bio->devs[slot].devnum;
 }
 
-static void raid10_end_read_request(struct bio *bio, int error)
+static void raid10_end_read_request(struct bio *bio)
 {
-       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       int uptodate = !bio->bi_error;
        struct r10bio *r10_bio = bio->bi_private;
        int slot, dev;
        struct md_rdev *rdev;
        }
 }
 
-static void raid10_end_write_request(struct bio *bio, int error)
+static void raid10_end_write_request(struct bio *bio)
 {
-       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct r10bio *r10_bio = bio->bi_private;
        int dev;
        int dec_rdev = 1;
        /*
         * this branch is our 'one mirror IO has finished' event handler:
         */
-       if (!uptodate) {
+       if (bio->bi_error) {
                if (repl)
                        /* Never record new bad blocks to replacement,
                         * just fail it.
                        if (unlikely((bio->bi_rw & REQ_DISCARD) &&
                            !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
                                /* Just ignore it */
-                               bio_endio(bio, 0);
+                               bio_endio(bio);
                        else
                                generic_make_request(bio);
                        bio = next;
                if (unlikely((bio->bi_rw & REQ_DISCARD) &&
                    !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
                        /* Just ignore it */
-                       bio_endio(bio, 0);
+                       bio_endio(bio);
                else
                        generic_make_request(bio);
                bio = next;
        return err;
 }
 
-static void end_sync_read(struct bio *bio, int error)
+static void end_sync_read(struct bio *bio)
 {
        struct r10bio *r10_bio = bio->bi_private;
        struct r10conf *conf = r10_bio->mddev->private;
        } else
                d = find_bio_disk(conf, r10_bio, bio, NULL, NULL);
 
-       if (test_bit(BIO_UPTODATE, &bio->bi_flags))
+       if (!bio->bi_error)
                set_bit(R10BIO_Uptodate, &r10_bio->state);
        else
                /* The write handler will notice the lack of
        }
 }
 
-static void end_sync_write(struct bio *bio, int error)
+static void end_sync_write(struct bio *bio)
 {
-       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct r10bio *r10_bio = bio->bi_private;
        struct mddev *mddev = r10_bio->mddev;
        struct r10conf *conf = mddev->private;
        else
                rdev = conf->mirrors[d].rdev;
 
-       if (!uptodate) {
+       if (bio->bi_error) {
                if (repl)
                        md_error(mddev, rdev);
                else {
 
        /* find the first device with a block */
        for (i=0; i<conf->copies; i++)
-               if (test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags))
+               if (!r10_bio->devs[i].bio->bi_error)
                        break;
 
        if (i == conf->copies)
                        continue;
                if (i == first)
                        continue;
-               if (test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags)) {
+               if (!r10_bio->devs[i].bio->bi_error) {
                        /* We know that the bi_io_vec layout is the same for
                         * both 'first' and 'i', so we just compare them.
                         * All vec entries are PAGE_SIZE;
                        rdev = conf->mirrors[dev].rdev;
                        if (r10_bio->devs[m].bio == NULL)
                                continue;
-                       if (test_bit(BIO_UPTODATE,
-                                    &r10_bio->devs[m].bio->bi_flags)) {
+                       if (!r10_bio->devs[m].bio->bi_error) {
                                rdev_clear_badblocks(
                                        rdev,
                                        r10_bio->devs[m].addr,
                        rdev = conf->mirrors[dev].replacement;
                        if (r10_bio->devs[m].repl_bio == NULL)
                                continue;
-                       if (test_bit(BIO_UPTODATE,
-                                    &r10_bio->devs[m].repl_bio->bi_flags)) {
+
+                       if (!r10_bio->devs[m].repl_bio->bi_error) {
                                rdev_clear_badblocks(
                                        rdev,
                                        r10_bio->devs[m].addr,
                                        r10_bio->devs[m].addr,
                                        r10_bio->sectors, 0);
                                rdev_dec_pending(rdev, conf->mddev);
-                       } else if (bio != NULL &&
-                                  !test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+                       } else if (bio != NULL && bio->bi_error) {
                                if (!narrow_write_error(r10_bio, m)) {
                                        md_error(conf->mddev, rdev);
                                        set_bit(R10BIO_Degraded,
 
                        bio = r10_bio->devs[i].bio;
                        bio_reset(bio);
-                       clear_bit(BIO_UPTODATE, &bio->bi_flags);
+                       bio->bi_error = -EIO;
                        if (conf->mirrors[d].rdev == NULL ||
                            test_bit(Faulty, &conf->mirrors[d].rdev->flags))
                                continue;
                        /* Need to set up for writing to the replacement */
                        bio = r10_bio->devs[i].repl_bio;
                        bio_reset(bio);
-                       clear_bit(BIO_UPTODATE, &bio->bi_flags);
+                       bio->bi_error = -EIO;
 
                        sector = r10_bio->devs[i].addr;
                        atomic_inc(&conf->mirrors[d].rdev->nr_pending);
 
                if (bio->bi_end_io == end_sync_read) {
                        md_sync_acct(bio->bi_bdev, nr_sectors);
-                       set_bit(BIO_UPTODATE, &bio->bi_flags);
+                       bio->bi_error = 0;
                        generic_make_request(bio);
                }
        }
        read_bio->bi_end_io = end_sync_read;
        read_bio->bi_rw = READ;
        read_bio->bi_flags &= (~0UL << BIO_RESET_BITS);
-       __set_bit(BIO_UPTODATE, &read_bio->bi_flags);
+       read_bio->bi_error = 0;
        read_bio->bi_vcnt = 0;
        read_bio->bi_iter.bi_size = 0;
        r10_bio->master_bio = read_bio;
        return 0;
 }
 
-static void end_reshape_write(struct bio *bio, int error)
+static void end_reshape_write(struct bio *bio)
 {
-       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct r10bio *r10_bio = bio->bi_private;
        struct mddev *mddev = r10_bio->mddev;
        struct r10conf *conf = mddev->private;
                rdev = conf->mirrors[d].rdev;
        }
 
-       if (!uptodate) {
+       if (bio->bi_error) {
                /* FIXME should record badblock */
                md_error(mddev, rdev);
        }
 
                bi->bi_iter.bi_size = 0;
                trace_block_bio_complete(bdev_get_queue(bi->bi_bdev),
                                         bi, 0);
-               bio_endio(bi, 0);
+               bio_endio(bi);
                bi = return_bi;
        }
 }
 }
 
 static void
-raid5_end_read_request(struct bio *bi, int error);
+raid5_end_read_request(struct bio *bi);
 static void
-raid5_end_write_request(struct bio *bi, int error);
+raid5_end_write_request(struct bio *bi);
 
 static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
 {
        conf->slab_cache = NULL;
 }
 
-static void raid5_end_read_request(struct bio * bi, int error)
+static void raid5_end_read_request(struct bio * bi)
 {
        struct stripe_head *sh = bi->bi_private;
        struct r5conf *conf = sh->raid_conf;
        int disks = sh->disks, i;
-       int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
        char b[BDEVNAME_SIZE];
        struct md_rdev *rdev = NULL;
        sector_t s;
                if (bi == &sh->dev[i].req)
                        break;
 
-       pr_debug("end_read_request %llu/%d, count: %d, uptodate %d.\n",
+       pr_debug("end_read_request %llu/%d, count: %d, error %d.\n",
                (unsigned long long)sh->sector, i, atomic_read(&sh->count),
-               uptodate);
+               bi->bi_error);
        if (i == disks) {
                BUG();
                return;
                s = sh->sector + rdev->new_data_offset;
        else
                s = sh->sector + rdev->data_offset;
-       if (uptodate) {
+       if (!bi->bi_error) {
                set_bit(R5_UPTODATE, &sh->dev[i].flags);
                if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
                        /* Note that this cannot happen on a
        release_stripe(sh);
 }
 
-static void raid5_end_write_request(struct bio *bi, int error)
+static void raid5_end_write_request(struct bio *bi)
 {
        struct stripe_head *sh = bi->bi_private;
        struct r5conf *conf = sh->raid_conf;
        int disks = sh->disks, i;
        struct md_rdev *uninitialized_var(rdev);
-       int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
        sector_t first_bad;
        int bad_sectors;
        int replacement = 0;
                        break;
                }
        }
-       pr_debug("end_write_request %llu/%d, count %d, uptodate: %d.\n",
+       pr_debug("end_write_request %llu/%d, count %d, error: %d.\n",
                (unsigned long long)sh->sector, i, atomic_read(&sh->count),
-               uptodate);
+               bi->bi_error);
        if (i == disks) {
                BUG();
                return;
        }
 
        if (replacement) {
-               if (!uptodate)
+               if (bi->bi_error)
                        md_error(conf->mddev, rdev);
                else if (is_badblock(rdev, sh->sector,
                                     STRIPE_SECTORS,
                                     &first_bad, &bad_sectors))
                        set_bit(R5_MadeGoodRepl, &sh->dev[i].flags);
        } else {
-               if (!uptodate) {
+               if (bi->bi_error) {
                        set_bit(STRIPE_DEGRADED, &sh->state);
                        set_bit(WriteErrorSeen, &rdev->flags);
                        set_bit(R5_WriteError, &sh->dev[i].flags);
        }
        rdev_dec_pending(rdev, conf->mddev);
 
-       if (sh->batch_head && !uptodate && !replacement)
+       if (sh->batch_head && bi->bi_error && !replacement)
                set_bit(STRIPE_BATCH_ERR, &sh->batch_head->state);
 
        if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags))
                while (bi && bi->bi_iter.bi_sector <
                        sh->dev[i].sector + STRIPE_SECTORS) {
                        struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
-                       clear_bit(BIO_UPTODATE, &bi->bi_flags);
+
+                       bi->bi_error = -EIO;
                        if (!raid5_dec_bi_active_stripes(bi)) {
                                md_write_end(conf->mddev);
                                bi->bi_next = *return_bi;
                while (bi && bi->bi_iter.bi_sector <
                       sh->dev[i].sector + STRIPE_SECTORS) {
                        struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector);
-                       clear_bit(BIO_UPTODATE, &bi->bi_flags);
+
+                       bi->bi_error = -EIO;
                        if (!raid5_dec_bi_active_stripes(bi)) {
                                md_write_end(conf->mddev);
                                bi->bi_next = *return_bi;
                               sh->dev[i].sector + STRIPE_SECTORS) {
                                struct bio *nextbi =
                                        r5_next_bio(bi, sh->dev[i].sector);
-                               clear_bit(BIO_UPTODATE, &bi->bi_flags);
+
+                               bi->bi_error = -EIO;
                                if (!raid5_dec_bi_active_stripes(bi)) {
                                        bi->bi_next = *return_bi;
                                        *return_bi = bi;
  *  first).
  *  If the read failed..
  */
-static void raid5_align_endio(struct bio *bi, int error)
+static void raid5_align_endio(struct bio *bi)
 {
        struct bio* raid_bi  = bi->bi_private;
        struct mddev *mddev;
        struct r5conf *conf;
-       int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
        struct md_rdev *rdev;
 
        bio_put(bi);
 
        rdev_dec_pending(rdev, conf->mddev);
 
-       if (!error && uptodate) {
+       if (!bi->bi_error) {
                trace_block_bio_complete(bdev_get_queue(raid_bi->bi_bdev),
                                         raid_bi, 0);
-               bio_endio(raid_bi, 0);
+               bio_endio(raid_bi);
                if (atomic_dec_and_test(&conf->active_aligned_reads))
                        wake_up(&conf->wait_for_quiescent);
                return;
        remaining = raid5_dec_bi_active_stripes(bi);
        if (remaining == 0) {
                md_write_end(mddev);
-               bio_endio(bi, 0);
+               bio_endio(bi);
        }
 }
 
                        release_stripe_plug(mddev, sh);
                } else {
                        /* cannot get stripe for read-ahead, just give-up */
-                       clear_bit(BIO_UPTODATE, &bi->bi_flags);
+                       bi->bi_error = -EIO;
                        break;
                }
        }
 
                trace_block_bio_complete(bdev_get_queue(bi->bi_bdev),
                                         bi, 0);
-               bio_endio(bi, 0);
+               bio_endio(bi);
        }
 }
 
        if (remaining == 0) {
                trace_block_bio_complete(bdev_get_queue(raid_bio->bi_bdev),
                                         raid_bio, 0);
-               bio_endio(raid_bio, 0);
+               bio_endio(raid_bio);
        }
        if (atomic_dec_and_test(&conf->active_aligned_reads))
                wake_up(&conf->wait_for_quiescent);
 
         * another kernel subsystem, and we just pass it through.
         */
        if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
-               err = -EIO;
+               bio->bi_error = -EIO;
                goto out;
        }
 
                                        "io error in %s sector %lld, len %d,\n",
                                        (rw == READ) ? "READ" : "WRITE",
                                        (unsigned long long) iter.bi_sector, len);
+                       bio->bi_error = err;
                        break;
                }
        }
                nd_iostat_end(bio, start);
 
  out:
-       bio_endio(bio, err);
+       bio_endio(bio);
 }
 
 static int nd_blk_rw_bytes(struct nd_namespace_common *ndns,
 
         * another kernel subsystem, and we just pass it through.
         */
        if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
-               err = -EIO;
+               bio->bi_error = -EIO;
                goto out;
        }
 
                                        "io error in %s sector %lld, len %d,\n",
                                        (rw == READ) ? "READ" : "WRITE",
                                        (unsigned long long) iter.bi_sector, len);
+                       bio->bi_error = err;
                        break;
                }
        }
                nd_iostat_end(bio, start);
 
 out:
-       bio_endio(bio, err);
+       bio_endio(bio);
 }
 
 static int btt_rw_page(struct block_device *bdev, sector_t sector,
 
        if (bio_data_dir(bio))
                wmb_pmem();
 
-       bio_endio(bio, 0);
+       bio_endio(bio);
 }
 
 static int pmem_rw_page(struct block_device *bdev, sector_t sector,
 
                }
                bytes_done += bvec.bv_len;
        }
-       bio_endio(bio, 0);
+       bio_endio(bio);
        return;
 fail:
        bio_io_error(bio);
 
                        index++;
                }
        }
-       set_bit(BIO_UPTODATE, &bio->bi_flags);
-       bio_endio(bio, 0);
+       bio_endio(bio);
        return;
 fail:
        bio_io_error(bio);
 
        kfree(ibr);
 }
 
-static void iblock_bio_done(struct bio *bio, int err)
+static void iblock_bio_done(struct bio *bio)
 {
        struct se_cmd *cmd = bio->bi_private;
        struct iblock_req *ibr = cmd->priv;
 
-       /*
-        * Set -EIO if !BIO_UPTODATE and the passed is still err=0
-        */
-       if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && !err)
-               err = -EIO;
-
-       if (err != 0) {
-               pr_err("test_bit(BIO_UPTODATE) failed for bio: %p,"
-                       " err: %d\n", bio, err);
+       if (bio->bi_error) {
+               pr_err("bio error: %p,  err: %d\n", bio, bio->bi_error);
                /*
                 * Bump the ib_bio_err_cnt and release bio.
                 */
        blk_finish_plug(&plug);
 }
 
-static void iblock_end_io_flush(struct bio *bio, int err)
+static void iblock_end_io_flush(struct bio *bio)
 {
        struct se_cmd *cmd = bio->bi_private;
 
-       if (err)
-               pr_err("IBLOCK: cache flush failed: %d\n", err);
+       if (bio->bi_error)
+               pr_err("IBLOCK: cache flush failed: %d\n", bio->bi_error);
 
        if (cmd) {
-               if (err)
+               if (bio->bi_error)
                        target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION);
                else
                        target_complete_cmd(cmd, SAM_STAT_GOOD);
 
        return bl;
 }
 
-static void pscsi_bi_endio(struct bio *bio, int error)
+static void pscsi_bi_endio(struct bio *bio)
 {
        bio_put(bio);
 }
        while (*hbio) {
                bio = *hbio;
                *hbio = (*hbio)->bi_next;
-               bio_endio(bio, 0);      /* XXX: should be error */
+               bio_endio(bio);
        }
        return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 }
        while (hbio) {
                struct bio *bio = hbio;
                hbio = hbio->bi_next;
-               bio_endio(bio, 0);      /* XXX: should be error */
+               bio_endio(bio);
        }
        ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 fail:
 
                struct btrfsic_state *state,
                struct btrfsic_block *const block,
                struct btrfs_super_block *const super_hdr);
-static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status);
+static void btrfsic_bio_end_io(struct bio *bp);
 static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate);
 static int btrfsic_is_block_ref_by_superblock(const struct btrfsic_state *state,
                                              const struct btrfsic_block *block,
        goto again;
 }
 
-static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status)
+static void btrfsic_bio_end_io(struct bio *bp)
 {
        struct btrfsic_block *block = (struct btrfsic_block *)bp->bi_private;
        int iodone_w_error;
        /* mutex is not held! This is not save if IO is not yet completed
         * on umount */
        iodone_w_error = 0;
-       if (bio_error_status)
+       if (bp->bi_error)
                iodone_w_error = 1;
 
        BUG_ON(NULL == block);
                     BTRFSIC_PRINT_MASK_END_IO_BIO_BH))
                        printk(KERN_INFO
                               "bio_end_io(err=%d) for %c @%llu (%s/%llu/%d)\n",
-                              bio_error_status,
+                              bp->bi_error,
                               btrfsic_get_block_type(dev_state->state, block),
                               block->logical_bytenr, dev_state->name,
                               block->dev_bytenr, block->mirror_num);
                block = next_block;
        } while (NULL != block);
 
-       bp->bi_end_io(bp, bio_error_status);
+       bp->bi_end_io(bp);
 }
 
 static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate)
 
  * The compressed pages are freed here, and it must be run
  * in process context
  */
-static void end_compressed_bio_read(struct bio *bio, int err)
+static void end_compressed_bio_read(struct bio *bio)
 {
        struct compressed_bio *cb = bio->bi_private;
        struct inode *inode;
        unsigned long index;
        int ret;
 
-       if (err)
+       if (bio->bi_error)
                cb->errors = 1;
 
        /* if there are more bios still pending for this compressed
                bio_for_each_segment_all(bvec, cb->orig_bio, i)
                        SetPageChecked(bvec->bv_page);
 
-               bio_endio(cb->orig_bio, 0);
+               bio_endio(cb->orig_bio);
        }
 
        /* finally free the cb struct */
  * This also calls the writeback end hooks for the file pages so that
  * metadata and checksums can be updated in the file.
  */
-static void end_compressed_bio_write(struct bio *bio, int err)
+static void end_compressed_bio_write(struct bio *bio)
 {
        struct extent_io_tree *tree;
        struct compressed_bio *cb = bio->bi_private;
        struct page *page;
        unsigned long index;
 
-       if (err)
+       if (bio->bi_error)
                cb->errors = 1;
 
        /* if there are more bios still pending for this compressed
                                         cb->start,
                                         cb->start + cb->len - 1,
                                         NULL,
-                                        err ? 0 : 1);
+                                        bio->bi_error ? 0 : 1);
        cb->compressed_pages[0]->mapping = NULL;
 
        end_compressed_writeback(inode, cb);
 
                        ret = btrfs_map_bio(root, READ, comp_bio,
                                            mirror_num, 0);
-                       if (ret)
-                               bio_endio(comp_bio, ret);
+                       if (ret) {
+                               bio->bi_error = ret;
+                               bio_endio(comp_bio);
+                       }
 
                        bio_put(comp_bio);
 
        }
 
        ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
-       if (ret)
-               bio_endio(comp_bio, ret);
+       if (ret) {
+               bio->bi_error = ret;
+               bio_endio(comp_bio);
+       }
 
        bio_put(comp_bio);
        return 0;
 
        return -EIO;    /* we fixed nothing */
 }
 
-static void end_workqueue_bio(struct bio *bio, int err)
+static void end_workqueue_bio(struct bio *bio)
 {
        struct btrfs_end_io_wq *end_io_wq = bio->bi_private;
        struct btrfs_fs_info *fs_info;
        btrfs_work_func_t func;
 
        fs_info = end_io_wq->info;
-       end_io_wq->error = err;
+       end_io_wq->error = bio->bi_error;
 
        if (bio->bi_rw & REQ_WRITE) {
                if (end_io_wq->metadata == BTRFS_WQ_ENDIO_METADATA) {
 
        /* If an error occured we just want to clean up the bio and move on */
        if (async->error) {
-               bio_endio(async->bio, async->error);
+               async->bio->bi_error = async->error;
+               bio_endio(async->bio);
                return;
        }
 
         * submission context.  Just jump into btrfs_map_bio
         */
        ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1);
-       if (ret)
-               bio_endio(bio, ret);
+       if (ret) {
+               bio->bi_error = ret;
+               bio_endio(bio);
+       }
        return ret;
 }
 
                                          __btree_submit_bio_done);
        }
 
-       if (ret) {
+       if (ret)
+               goto out_w_error;
+       return 0;
+
 out_w_error:
-               bio_endio(bio, ret);
-       }
+       bio->bi_error = ret;
+       bio_endio(bio);
        return ret;
 }
 
 {
        struct bio *bio;
        struct btrfs_end_io_wq *end_io_wq;
-       int error;
 
        end_io_wq = container_of(work, struct btrfs_end_io_wq, work);
        bio = end_io_wq->bio;
 
-       error = end_io_wq->error;
+       bio->bi_error = end_io_wq->error;
        bio->bi_private = end_io_wq->private;
        bio->bi_end_io = end_io_wq->end_io;
        kmem_cache_free(btrfs_end_io_wq_cache, end_io_wq);
-       bio_endio(bio, error);
+       bio_endio(bio);
 }
 
 static int cleaner_kthread(void *arg)
  * endio for the write_dev_flush, this will wake anyone waiting
  * for the barrier when it is done
  */
-static void btrfs_end_empty_barrier(struct bio *bio, int err)
+static void btrfs_end_empty_barrier(struct bio *bio)
 {
-       if (err)
-               clear_bit(BIO_UPTODATE, &bio->bi_flags);
        if (bio->bi_private)
                complete(bio->bi_private);
        bio_put(bio);
 
                wait_for_completion(&device->flush_wait);
 
-               if (!bio_flagged(bio, BIO_UPTODATE)) {
-                       ret = -EIO;
+               if (bio->bi_error) {
+                       ret = bio->bi_error;
                        btrfs_dev_stat_inc_and_print(device,
                                BTRFS_DEV_STAT_FLUSH_ERRS);
                }
 
  * Scheduling is not allowed, so the extent state tree is expected
  * to have one and only one object corresponding to this IO.
  */
-static void end_bio_extent_writepage(struct bio *bio, int err)
+static void end_bio_extent_writepage(struct bio *bio)
 {
        struct bio_vec *bvec;
        u64 start;
                start = page_offset(page);
                end = start + bvec->bv_offset + bvec->bv_len - 1;
 
-               if (end_extent_writepage(page, err, start, end))
+               if (end_extent_writepage(page, bio->bi_error, start, end))
                        continue;
 
                end_page_writeback(page);
  * Scheduling is not allowed, so the extent state tree is expected
  * to have one and only one object corresponding to this IO.
  */
-static void end_bio_extent_readpage(struct bio *bio, int err)
+static void end_bio_extent_readpage(struct bio *bio)
 {
        struct bio_vec *bvec;
-       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       int uptodate = !bio->bi_error;
        struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
        struct extent_io_tree *tree;
        u64 offset = 0;
        int ret;
        int i;
 
-       if (err)
-               uptodate = 0;
-
        bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
                struct inode *inode = page->mapping->host;
 
                pr_debug("end_bio_extent_readpage: bi_sector=%llu, err=%d, "
-                        "mirror=%u\n", (u64)bio->bi_iter.bi_sector, err,
-                        io_bio->mirror_num);
+                        "mirror=%u\n", (u64)bio->bi_iter.bi_sector,
+                        bio->bi_error, io_bio->mirror_num);
                tree = &BTRFS_I(inode)->io_tree;
 
                /* We always issue full-page reads, but if some block
 
                if (tree->ops && tree->ops->readpage_io_failed_hook) {
                        ret = tree->ops->readpage_io_failed_hook(page, mirror);
-                       if (!ret && !err &&
-                           test_bit(BIO_UPTODATE, &bio->bi_flags))
+                       if (!ret && !bio->bi_error)
                                uptodate = 1;
                } else {
                        /*
                        ret = bio_readpage_error(bio, offset, page, start, end,
                                                 mirror);
                        if (ret == 0) {
-                               uptodate =
-                                       test_bit(BIO_UPTODATE, &bio->bi_flags);
-                               if (err)
-                                       uptodate = 0;
+                               uptodate = !bio->bi_error;
                                offset += len;
                                continue;
                        }
                endio_readpage_release_extent(tree, extent_start, extent_len,
                                              uptodate);
        if (io_bio->end_io)
-               io_bio->end_io(io_bio, err);
+               io_bio->end_io(io_bio, bio->bi_error);
        bio_put(bio);
 }
 
        }
 }
 
-static void end_bio_extent_buffer_writepage(struct bio *bio, int err)
+static void end_bio_extent_buffer_writepage(struct bio *bio)
 {
        struct bio_vec *bvec;
        struct extent_buffer *eb;
                BUG_ON(!eb);
                done = atomic_dec_and_test(&eb->io_pages);
 
-               if (err || test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) {
+               if (bio->bi_error ||
+                   test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) {
                        ClearPageUptodate(page);
                        set_btree_ioerr(page);
                }
 
        int ret;
 
        ret = btrfs_map_bio(root, rw, bio, mirror_num, 1);
-       if (ret)
-               bio_endio(bio, ret);
+       if (ret) {
+               bio->bi_error = ret;
+               bio_endio(bio);
+       }
        return ret;
 }
 
        ret = btrfs_map_bio(root, rw, bio, mirror_num, 0);
 
 out:
-       if (ret < 0)
-               bio_endio(bio, ret);
+       if (ret < 0) {
+               bio->bi_error = ret;
+               bio_endio(bio);
+       }
        return ret;
 }
 
        int uptodate;
 };
 
-static void btrfs_retry_endio_nocsum(struct bio *bio, int err)
+static void btrfs_retry_endio_nocsum(struct bio *bio)
 {
        struct btrfs_retry_complete *done = bio->bi_private;
        struct bio_vec *bvec;
        int i;
 
-       if (err)
+       if (bio->bi_error)
                goto end;
 
        done->uptodate = 1;
        return 0;
 }
 
-static void btrfs_retry_endio(struct bio *bio, int err)
+static void btrfs_retry_endio(struct bio *bio)
 {
        struct btrfs_retry_complete *done = bio->bi_private;
        struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
        int ret;
        int i;
 
-       if (err)
+       if (bio->bi_error)
                goto end;
 
        uptodate = 1;
        }
 }
 
-static void btrfs_endio_direct_read(struct bio *bio, int err)
+static void btrfs_endio_direct_read(struct bio *bio)
 {
        struct btrfs_dio_private *dip = bio->bi_private;
        struct inode *inode = dip->inode;
        struct bio *dio_bio;
        struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
+       int err = bio->bi_error;
 
        if (dip->flags & BTRFS_DIO_ORIG_BIO_SUBMITTED)
                err = btrfs_subio_endio_read(inode, io_bio, err);
 
        kfree(dip);
 
-       /* If we had a csum failure make sure to clear the uptodate flag */
-       if (err)
-               clear_bit(BIO_UPTODATE, &dio_bio->bi_flags);
-       dio_end_io(dio_bio, err);
+       dio_end_io(dio_bio, bio->bi_error);
 
        if (io_bio->end_io)
                io_bio->end_io(io_bio, err);
        bio_put(bio);
 }
 
-static void btrfs_endio_direct_write(struct bio *bio, int err)
+static void btrfs_endio_direct_write(struct bio *bio)
 {
        struct btrfs_dio_private *dip = bio->bi_private;
        struct inode *inode = dip->inode;
 again:
        ret = btrfs_dec_test_first_ordered_pending(inode, &ordered,
                                                   &ordered_offset,
-                                                  ordered_bytes, !err);
+                                                  ordered_bytes,
+                                                  !bio->bi_error);
        if (!ret)
                goto out_test;
 
 
        kfree(dip);
 
-       /* If we had an error make sure to clear the uptodate flag */
-       if (err)
-               clear_bit(BIO_UPTODATE, &dio_bio->bi_flags);
-       dio_end_io(dio_bio, err);
+       dio_end_io(dio_bio, bio->bi_error);
        bio_put(bio);
 }
 
        return 0;
 }
 
-static void btrfs_end_dio_bio(struct bio *bio, int err)
+static void btrfs_end_dio_bio(struct bio *bio)
 {
        struct btrfs_dio_private *dip = bio->bi_private;
+       int err = bio->bi_error;
 
        if (err)
                btrfs_warn(BTRFS_I(dip->inode)->root->fs_info,
        if (dip->errors) {
                bio_io_error(dip->orig_bio);
        } else {
-               set_bit(BIO_UPTODATE, &dip->dio_bio->bi_flags);
-               bio_endio(dip->orig_bio, 0);
+               dip->dio_bio->bi_error = 0;
+               bio_endio(dip->orig_bio);
        }
 out:
        bio_put(bio);
         * callbacks - they require an allocated dip and a clone of dio_bio.
         */
        if (io_bio && dip) {
-               bio_endio(io_bio, ret);
+               io_bio->bi_error = -EIO;
+               bio_endio(io_bio);
                /*
                 * The end io callbacks free our dip, do the final put on io_bio
                 * and all the cleanup and final put for dio_bio (through
                        unlock_extent(&BTRFS_I(inode)->io_tree, file_offset,
                              file_offset + dio_bio->bi_iter.bi_size - 1);
                }
-               clear_bit(BIO_UPTODATE, &dio_bio->bi_flags);
+               dio_bio->bi_error = -EIO;
                /*
                 * Releases and cleans up our dio_bio, no need to bio_put()
                 * nor bio_endio()/bio_io_error() against dio_bio.
 
  * this frees the rbio and runs through all the bios in the
  * bio_list and calls end_io on them
  */
-static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err, int uptodate)
+static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err)
 {
        struct bio *cur = bio_list_get(&rbio->bio_list);
        struct bio *next;
        while (cur) {
                next = cur->bi_next;
                cur->bi_next = NULL;
-               if (uptodate)
-                       set_bit(BIO_UPTODATE, &cur->bi_flags);
-               bio_endio(cur, err);
+               cur->bi_error = err;
+               bio_endio(cur);
                cur = next;
        }
 }
  * end io function used by finish_rmw.  When we finally
  * get here, we've written a full stripe
  */
-static void raid_write_end_io(struct bio *bio, int err)
+static void raid_write_end_io(struct bio *bio)
 {
        struct btrfs_raid_bio *rbio = bio->bi_private;
+       int err = bio->bi_error;
 
        if (err)
                fail_bio_stripe(rbio, bio);
        if (atomic_read(&rbio->error) > rbio->bbio->max_errors)
                err = -EIO;
 
-       rbio_orig_end_io(rbio, err, 0);
+       rbio_orig_end_io(rbio, err);
        return;
 }
 
                 * devices or if they are not contiguous
                 */
                if (last_end == disk_start && stripe->dev->bdev &&
-                   test_bit(BIO_UPTODATE, &last->bi_flags) &&
+                   !last->bi_error &&
                    last->bi_bdev == stripe->dev->bdev) {
                        ret = bio_add_page(last, page, PAGE_CACHE_SIZE, 0);
                        if (ret == PAGE_CACHE_SIZE)
        bio->bi_iter.bi_size = 0;
        bio->bi_bdev = stripe->dev->bdev;
        bio->bi_iter.bi_sector = disk_start >> 9;
-       set_bit(BIO_UPTODATE, &bio->bi_flags);
 
        bio_add_page(bio, page, PAGE_CACHE_SIZE, 0);
        bio_list_add(bio_list, bio);
 
                bio->bi_private = rbio;
                bio->bi_end_io = raid_write_end_io;
-               BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags));
                submit_bio(WRITE, bio);
        }
        return;
 
 cleanup:
-       rbio_orig_end_io(rbio, -EIO, 0);
+       rbio_orig_end_io(rbio, -EIO);
 }
 
 /*
  * This will usually kick off finish_rmw once all the bios are read in, but it
  * may trigger parity reconstruction if we had any errors along the way
  */
-static void raid_rmw_end_io(struct bio *bio, int err)
+static void raid_rmw_end_io(struct bio *bio)
 {
        struct btrfs_raid_bio *rbio = bio->bi_private;
 
-       if (err)
+       if (bio->bi_error)
                fail_bio_stripe(rbio, bio);
        else
                set_bio_pages_uptodate(bio);
        if (!atomic_dec_and_test(&rbio->stripes_pending))
                return;
 
-       err = 0;
        if (atomic_read(&rbio->error) > rbio->bbio->max_errors)
                goto cleanup;
 
 
 cleanup:
 
-       rbio_orig_end_io(rbio, -EIO, 0);
+       rbio_orig_end_io(rbio, -EIO);
 }
 
 static void async_rmw_stripe(struct btrfs_raid_bio *rbio)
                btrfs_bio_wq_end_io(rbio->fs_info, bio,
                                    BTRFS_WQ_ENDIO_RAID56);
 
-               BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags));
                submit_bio(READ, bio);
        }
        /* the actual write will happen once the reads are done */
        return 0;
 
 cleanup:
-       rbio_orig_end_io(rbio, -EIO, 0);
+       rbio_orig_end_io(rbio, -EIO);
        return -EIO;
 
 finish:
                else
                        clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags);
 
-               rbio_orig_end_io(rbio, err, err == 0);
+               rbio_orig_end_io(rbio, err);
        } else if (err == 0) {
                rbio->faila = -1;
                rbio->failb = -1;
                else
                        BUG();
        } else {
-               rbio_orig_end_io(rbio, err, 0);
+               rbio_orig_end_io(rbio, err);
        }
 }
 
  * This is called only for stripes we've read from disk to
  * reconstruct the parity.
  */
-static void raid_recover_end_io(struct bio *bio, int err)
+static void raid_recover_end_io(struct bio *bio)
 {
        struct btrfs_raid_bio *rbio = bio->bi_private;
 
         * we only read stripe pages off the disk, set them
         * up to date if there were no errors
         */
-       if (err)
+       if (bio->bi_error)
                fail_bio_stripe(rbio, bio);
        else
                set_bio_pages_uptodate(bio);
                return;
 
        if (atomic_read(&rbio->error) > rbio->bbio->max_errors)
-               rbio_orig_end_io(rbio, -EIO, 0);
+               rbio_orig_end_io(rbio, -EIO);
        else
                __raid_recover_end_io(rbio);
 }
                btrfs_bio_wq_end_io(rbio->fs_info, bio,
                                    BTRFS_WQ_ENDIO_RAID56);
 
-               BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags));
                submit_bio(READ, bio);
        }
 out:
 
 cleanup:
        if (rbio->operation == BTRFS_RBIO_READ_REBUILD)
-               rbio_orig_end_io(rbio, -EIO, 0);
+               rbio_orig_end_io(rbio, -EIO);
        return -EIO;
 }
 
  * end io function used by finish_rmw.  When we finally
  * get here, we've written a full stripe
  */
-static void raid_write_parity_end_io(struct bio *bio, int err)
+static void raid_write_parity_end_io(struct bio *bio)
 {
        struct btrfs_raid_bio *rbio = bio->bi_private;
+       int err = bio->bi_error;
 
-       if (err)
+       if (bio->bi_error)
                fail_bio_stripe(rbio, bio);
 
        bio_put(bio);
        if (atomic_read(&rbio->error))
                err = -EIO;
 
-       rbio_orig_end_io(rbio, err, 0);
+       rbio_orig_end_io(rbio, err);
 }
 
 static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
        nr_data = bio_list_size(&bio_list);
        if (!nr_data) {
                /* Every parity is right */
-               rbio_orig_end_io(rbio, 0, 0);
+               rbio_orig_end_io(rbio, 0);
                return;
        }
 
 
                bio->bi_private = rbio;
                bio->bi_end_io = raid_write_parity_end_io;
-               BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags));
                submit_bio(WRITE, bio);
        }
        return;
 
 cleanup:
-       rbio_orig_end_io(rbio, -EIO, 0);
+       rbio_orig_end_io(rbio, -EIO);
 }
 
 static inline int is_data_stripe(struct btrfs_raid_bio *rbio, int stripe)
        return;
 
 cleanup:
-       rbio_orig_end_io(rbio, -EIO, 0);
+       rbio_orig_end_io(rbio, -EIO);
 }
 
 /*
  * This will usually kick off finish_rmw once all the bios are read in, but it
  * may trigger parity reconstruction if we had any errors along the way
  */
-static void raid56_parity_scrub_end_io(struct bio *bio, int err)
+static void raid56_parity_scrub_end_io(struct bio *bio)
 {
        struct btrfs_raid_bio *rbio = bio->bi_private;
 
-       if (err)
+       if (bio->bi_error)
                fail_bio_stripe(rbio, bio);
        else
                set_bio_pages_uptodate(bio);
                btrfs_bio_wq_end_io(rbio->fs_info, bio,
                                    BTRFS_WQ_ENDIO_RAID56);
 
-               BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags));
                submit_bio(READ, bio);
        }
        /* the actual write will happen once the reads are done */
        return;
 
 cleanup:
-       rbio_orig_end_io(rbio, -EIO, 0);
+       rbio_orig_end_io(rbio, -EIO);
        return;
 
 finish:
 
                       u64 physical, struct btrfs_device *dev, u64 flags,
                       u64 gen, int mirror_num, u8 *csum, int force,
                       u64 physical_for_dev_replace);
-static void scrub_bio_end_io(struct bio *bio, int err);
+static void scrub_bio_end_io(struct bio *bio);
 static void scrub_bio_end_io_worker(struct btrfs_work *work);
 static void scrub_block_complete(struct scrub_block *sblock);
 static void scrub_remap_extent(struct btrfs_fs_info *fs_info,
 static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx,
                                    struct scrub_page *spage);
 static void scrub_wr_submit(struct scrub_ctx *sctx);
-static void scrub_wr_bio_end_io(struct bio *bio, int err);
+static void scrub_wr_bio_end_io(struct bio *bio);
 static void scrub_wr_bio_end_io_worker(struct btrfs_work *work);
 static int write_page_nocow(struct scrub_ctx *sctx,
                            u64 physical_for_dev_replace, struct page *page);
        int error;
 };
 
-static void scrub_bio_wait_endio(struct bio *bio, int error)
+static void scrub_bio_wait_endio(struct bio *bio)
 {
        struct scrub_bio_ret *ret = bio->bi_private;
 
-       ret->error = error;
+       ret->error = bio->bi_error;
        complete(&ret->event);
 }
 
        btrfsic_submit_bio(WRITE, sbio->bio);
 }
 
-static void scrub_wr_bio_end_io(struct bio *bio, int err)
+static void scrub_wr_bio_end_io(struct bio *bio)
 {
        struct scrub_bio *sbio = bio->bi_private;
        struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info;
 
-       sbio->err = err;
+       sbio->err = bio->bi_error;
        sbio->bio = bio;
 
        btrfs_init_work(&sbio->work, btrfs_scrubwrc_helper,
                 */
                printk_ratelimited(KERN_WARNING
                        "BTRFS: scrub_submit(bio bdev == NULL) is unexpected!\n");
-               bio_endio(sbio->bio, -EIO);
+               bio_io_error(sbio->bio);
        } else {
                btrfsic_submit_bio(READ, sbio->bio);
        }
        return 0;
 }
 
-static void scrub_bio_end_io(struct bio *bio, int err)
+static void scrub_bio_end_io(struct bio *bio)
 {
        struct scrub_bio *sbio = bio->bi_private;
        struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info;
 
-       sbio->err = err;
+       sbio->err = bio->bi_error;
        sbio->bio = bio;
 
        btrfs_queue_work(fs_info->scrub_workers, &sbio->work);
        scrub_pending_bio_dec(sctx);
 }
 
-static void scrub_parity_bio_endio(struct bio *bio, int error)
+static void scrub_parity_bio_endio(struct bio *bio)
 {
        struct scrub_parity *sparity = (struct scrub_parity *)bio->bi_private;
 
-       if (error)
+       if (bio->bi_error)
                bitmap_or(sparity->ebitmap, sparity->ebitmap, sparity->dbitmap,
                          sparity->nsectors);
 
 
        return 0;
 }
 
-static inline void btrfs_end_bbio(struct btrfs_bio *bbio, struct bio *bio, int err)
+static inline void btrfs_end_bbio(struct btrfs_bio *bbio, struct bio *bio)
 {
        bio->bi_private = bbio->private;
        bio->bi_end_io = bbio->end_io;
-       bio_endio(bio, err);
+       bio_endio(bio);
 
        btrfs_put_bbio(bbio);
 }
 
-static void btrfs_end_bio(struct bio *bio, int err)
+static void btrfs_end_bio(struct bio *bio)
 {
        struct btrfs_bio *bbio = bio->bi_private;
        int is_orig_bio = 0;
 
-       if (err) {
+       if (bio->bi_error) {
                atomic_inc(&bbio->error);
-               if (err == -EIO || err == -EREMOTEIO) {
+               if (bio->bi_error == -EIO || bio->bi_error == -EREMOTEIO) {
                        unsigned int stripe_index =
                                btrfs_io_bio(bio)->stripe_index;
                        struct btrfs_device *dev;
                 * beyond the tolerance of the btrfs bio
                 */
                if (atomic_read(&bbio->error) > bbio->max_errors) {
-                       err = -EIO;
+                       bio->bi_error = -EIO;
                } else {
                        /*
                         * this bio is actually up to date, we didn't
                         * go over the max number of errors
                         */
-                       set_bit(BIO_UPTODATE, &bio->bi_flags);
-                       err = 0;
+                       bio->bi_error = 0;
                }
 
-               btrfs_end_bbio(bbio, bio, err);
+               btrfs_end_bbio(bbio, bio);
        } else if (!is_orig_bio) {
                bio_put(bio);
        }
        struct btrfs_pending_bios *pending_bios;
 
        if (device->missing || !device->bdev) {
-               bio_endio(bio, -EIO);
+               bio_io_error(bio);
                return;
        }
 
 
                btrfs_io_bio(bio)->mirror_num = bbio->mirror_num;
                bio->bi_iter.bi_sector = logical >> 9;
-
-               btrfs_end_bbio(bbio, bio, -EIO);
+               bio->bi_error = -EIO;
+               btrfs_end_bbio(bbio, bio);
        }
 }
 
 
 }
 EXPORT_SYMBOL(generic_block_bmap);
 
-static void end_bio_bh_io_sync(struct bio *bio, int err)
+static void end_bio_bh_io_sync(struct bio *bio)
 {
        struct buffer_head *bh = bio->bi_private;
 
        if (unlikely (test_bit(BIO_QUIET,&bio->bi_flags)))
                set_bit(BH_Quiet, &bh->b_state);
 
-       bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags));
+       bh->b_end_io(bh, !bio->bi_error);
        bio_put(bio);
 }
 
 
 /*
  * Asynchronous IO callback. 
  */
-static void dio_bio_end_aio(struct bio *bio, int error)
+static void dio_bio_end_aio(struct bio *bio)
 {
        struct dio *dio = bio->bi_private;
        unsigned long remaining;
  * During I/O bi_private points at the dio.  After I/O, bi_private is used to
  * implement a singly-linked list of completed BIOs, at dio->bio_list.
  */
-static void dio_bio_end_io(struct bio *bio, int error)
+static void dio_bio_end_io(struct bio *bio)
 {
        struct dio *dio = bio->bi_private;
        unsigned long flags;
        struct dio *dio = bio->bi_private;
 
        if (dio->is_async)
-               dio_bio_end_aio(bio, error);
+               dio_bio_end_aio(bio);
        else
-               dio_bio_end_io(bio, error);
+               dio_bio_end_io(bio);
 }
 EXPORT_SYMBOL_GPL(dio_end_io);
 
  */
 static int dio_bio_complete(struct dio *dio, struct bio *bio)
 {
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct bio_vec *bvec;
        unsigned i;
 
-       if (!uptodate)
+       if (bio->bi_error)
                dio->io_error = -EIO;
 
        if (dio->is_async && dio->rw == READ) {
                }
                bio_put(bio);
        }
-       return uptodate ? 0 : -EIO;
+       return bio->bi_error;
 }
 
 /*
 
 static void ext4_finish_bio(struct bio *bio)
 {
        int i;
-       int error = !test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct bio_vec *bvec;
 
        bio_for_each_segment_all(bvec, bio, i) {
                }
 #endif
 
-               if (error) {
+               if (bio->bi_error) {
                        SetPageError(page);
                        set_bit(AS_EIO, &page->mapping->flags);
                }
                                continue;
                        }
                        clear_buffer_async_write(bh);
-                       if (error)
+                       if (bio->bi_error)
                                buffer_io_error(bh);
                } while ((bh = bh->b_this_page) != head);
                bit_spin_unlock(BH_Uptodate_Lock, &head->b_state);
 }
 
 /* BIO completion function for page writeback */
-static void ext4_end_bio(struct bio *bio, int error)
+static void ext4_end_bio(struct bio *bio)
 {
        ext4_io_end_t *io_end = bio->bi_private;
        sector_t bi_sector = bio->bi_iter.bi_sector;
 
        BUG_ON(!io_end);
        bio->bi_end_io = NULL;
-       if (test_bit(BIO_UPTODATE, &bio->bi_flags))
-               error = 0;
 
-       if (error) {
+       if (bio->bi_error) {
                struct inode *inode = io_end->inode;
 
                ext4_warning(inode->i_sb, "I/O error %d writing to inode %lu "
                             "(offset %llu size %ld starting block %llu)",
-                            error, inode->i_ino,
+                            bio->bi_error, inode->i_ino,
                             (unsigned long long) io_end->offset,
                             (long) io_end->size,
                             (unsigned long long)
                             bi_sector >> (inode->i_blkbits - 9));
-               mapping_set_error(inode->i_mapping, error);
+               mapping_set_error(inode->i_mapping, bio->bi_error);
        }
 
        if (io_end->flag & EXT4_IO_END_UNWRITTEN) {
 
  * status of that page is hard.  See end_buffer_async_read() for the details.
  * There is no point in duplicating all that complexity.
  */
-static void mpage_end_io(struct bio *bio, int err)
+static void mpage_end_io(struct bio *bio)
 {
        struct bio_vec *bv;
        int i;
        if (ext4_bio_encrypted(bio)) {
                struct ext4_crypto_ctx *ctx = bio->bi_private;
 
-               if (err) {
+               if (bio->bi_error) {
                        ext4_release_crypto_ctx(ctx);
                } else {
                        INIT_WORK(&ctx->r.work, completion_pages);
        bio_for_each_segment_all(bv, bio, i) {
                struct page *page = bv->bv_page;
 
-               if (!err) {
+               if (!bio->bi_error) {
                        SetPageUptodate(page);
                } else {
                        ClearPageUptodate(page);
 
 static struct kmem_cache *extent_tree_slab;
 static struct kmem_cache *extent_node_slab;
 
-static void f2fs_read_end_io(struct bio *bio, int err)
+static void f2fs_read_end_io(struct bio *bio)
 {
        struct bio_vec *bvec;
        int i;
 
        if (f2fs_bio_encrypted(bio)) {
-               if (err) {
+               if (bio->bi_error) {
                        f2fs_release_crypto_ctx(bio->bi_private);
                } else {
                        f2fs_end_io_crypto_work(bio->bi_private, bio);
        bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
 
-               if (!err) {
+               if (!bio->bi_error) {
                        SetPageUptodate(page);
                } else {
                        ClearPageUptodate(page);
        bio_put(bio);
 }
 
-static void f2fs_write_end_io(struct bio *bio, int err)
+static void f2fs_write_end_io(struct bio *bio)
 {
        struct f2fs_sb_info *sbi = bio->bi_private;
        struct bio_vec *bvec;
 
                f2fs_restore_and_release_control_page(&page);
 
-               if (unlikely(err)) {
+               if (unlikely(bio->bi_error)) {
                        set_page_dirty(page);
                        set_bit(AS_EIO, &page->mapping->flags);
                        f2fs_stop_checkpoint(sbi);
 
  *
  */
 
-static void gfs2_end_log_write(struct bio *bio, int error)
+static void gfs2_end_log_write(struct bio *bio)
 {
        struct gfs2_sbd *sdp = bio->bi_private;
        struct bio_vec *bvec;
        struct page *page;
        int i;
 
-       if (error) {
-               sdp->sd_log_error = error;
-               fs_err(sdp, "Error %d writing to log\n", error);
+       if (bio->bi_error) {
+               sdp->sd_log_error = bio->bi_error;
+               fs_err(sdp, "Error %d writing to log\n", bio->bi_error);
        }
 
        bio_for_each_segment_all(bvec, bio, i) {
                page = bvec->bv_page;
                if (page_has_buffers(page))
-                       gfs2_end_log_write_bh(sdp, bvec, error);
+                       gfs2_end_log_write_bh(sdp, bvec, bio->bi_error);
                else
                        mempool_free(page, gfs2_page_pool);
        }
 
        return -EINVAL;
 }
 
-static void end_bio_io_page(struct bio *bio, int error)
+static void end_bio_io_page(struct bio *bio)
 {
        struct page *page = bio->bi_private;
 
-       if (!error)
+       if (!bio->bi_error)
                SetPageUptodate(page);
        else
-               pr_warn("error %d reading superblock\n", error);
+               pr_warn("error %d reading superblock\n", bio->bi_error);
        unlock_page(page);
 }
 
 
        /*check if journaling to disk has been disabled*/
        if (log->no_integrity) {
                bio->bi_iter.bi_size = 0;
-               lbmIODone(bio, 0);
+               lbmIODone(bio);
        } else {
                submit_bio(READ_SYNC, bio);
        }
        /* check if journaling to disk has been disabled */
        if (log->no_integrity) {
                bio->bi_iter.bi_size = 0;
-               lbmIODone(bio, 0);
+               lbmIODone(bio);
        } else {
                submit_bio(WRITE_SYNC, bio);
                INCREMENT(lmStat.submitted);
  *
  * executed at INTIODONE level
  */
-static void lbmIODone(struct bio *bio, int error)
+static void lbmIODone(struct bio *bio)
 {
        struct lbuf *bp = bio->bi_private;
        struct lbuf *nextbp, *tail;
 
        bp->l_flag |= lbmDONE;
 
-       if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+       if (bio->bi_error) {
                bp->l_flag |= lbmERROR;
 
                jfs_err("lbmIODone: I/O error in JFS log");
 
        unlock_page(page);
 }
 
-static void metapage_read_end_io(struct bio *bio, int err)
+static void metapage_read_end_io(struct bio *bio)
 {
        struct page *page = bio->bi_private;
 
-       if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+       if (bio->bi_error) {
                printk(KERN_ERR "metapage_read_end_io: I/O error\n");
                SetPageError(page);
        }
        end_page_writeback(page);
 }
 
-static void metapage_write_end_io(struct bio *bio, int err)
+static void metapage_write_end_io(struct bio *bio)
 {
        struct page *page = bio->bi_private;
 
        BUG_ON(!PagePrivate(page));
 
-       if (! test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+       if (bio->bi_error) {
                printk(KERN_ERR "metapage_write_end_io: I/O error\n");
                SetPageError(page);
        }
 
 
 static DECLARE_WAIT_QUEUE_HEAD(wq);
 
-static void writeseg_end_io(struct bio *bio, int err)
+static void writeseg_end_io(struct bio *bio)
 {
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct bio_vec *bvec;
        int i;
        struct super_block *sb = bio->bi_private;
        struct logfs_super *super = logfs_super(sb);
 
-       BUG_ON(!uptodate); /* FIXME: Retry io or write elsewhere */
-       BUG_ON(err);
+       BUG_ON(bio->bi_error); /* FIXME: Retry io or write elsewhere */
 
        bio_for_each_segment_all(bvec, bio, i) {
                end_page_writeback(bvec->bv_page);
 }
 
 
-static void erase_end_io(struct bio *bio, int err) 
+static void erase_end_io(struct bio *bio)
 { 
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); 
        struct super_block *sb = bio->bi_private; 
        struct logfs_super *super = logfs_super(sb); 
 
-       BUG_ON(!uptodate); /* FIXME: Retry io or write elsewhere */ 
-       BUG_ON(err); 
+       BUG_ON(bio->bi_error); /* FIXME: Retry io or write elsewhere */ 
        BUG_ON(bio->bi_vcnt == 0); 
        bio_put(bio); 
        if (atomic_dec_and_test(&super->s_pending_writes))
 
  * status of that page is hard.  See end_buffer_async_read() for the details.
  * There is no point in duplicating all that complexity.
  */
-static void mpage_end_io(struct bio *bio, int err)
+static void mpage_end_io(struct bio *bio)
 {
        struct bio_vec *bv;
        int i;
 
        bio_for_each_segment_all(bv, bio, i) {
                struct page *page = bv->bv_page;
-               page_endio(page, bio_data_dir(bio), err);
+               page_endio(page, bio_data_dir(bio), bio->bi_error);
        }
 
        bio_put(bio);
 
 
 static struct bio *
 bl_alloc_init_bio(int npg, struct block_device *bdev, sector_t disk_sector,
-               void (*end_io)(struct bio *, int err), struct parallel_io *par)
+               bio_end_io_t end_io, struct parallel_io *par)
 {
        struct bio *bio;
 
 static struct bio *
 do_add_page_to_bio(struct bio *bio, int npg, int rw, sector_t isect,
                struct page *page, struct pnfs_block_dev_map *map,
-               struct pnfs_block_extent *be,
-               void (*end_io)(struct bio *, int err),
+               struct pnfs_block_extent *be, bio_end_io_t end_io,
                struct parallel_io *par, unsigned int offset, int *len)
 {
        struct pnfs_block_dev *dev =
        return bio;
 }
 
-static void bl_end_io_read(struct bio *bio, int err)
+static void bl_end_io_read(struct bio *bio)
 {
        struct parallel_io *par = bio->bi_private;
 
-       if (err) {
+       if (bio->bi_error) {
                struct nfs_pgio_header *header = par->data;
 
                if (!header->pnfs_error)
        return PNFS_ATTEMPTED;
 }
 
-static void bl_end_io_write(struct bio *bio, int err)
+static void bl_end_io_write(struct bio *bio)
 {
        struct parallel_io *par = bio->bi_private;
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct nfs_pgio_header *header = par->data;
 
-       if (!uptodate) {
+       if (bio->bi_error) {
                if (!header->pnfs_error)
                        header->pnfs_error = -EIO;
                pnfs_set_lo_fail(header->lseg);
 
 /*
  * BIO operations
  */
-static void nilfs_end_bio_write(struct bio *bio, int err)
+static void nilfs_end_bio_write(struct bio *bio)
 {
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct nilfs_segment_buffer *segbuf = bio->bi_private;
 
-       if (!uptodate)
+       if (bio->bi_error)
                atomic_inc(&segbuf->sb_err);
 
        bio_put(bio);
 
        wait_for_completion(&wc->wc_io_complete);
 }
 
-static void o2hb_bio_end_io(struct bio *bio,
-                          int error)
+static void o2hb_bio_end_io(struct bio *bio)
 {
        struct o2hb_bio_wait_ctxt *wc = bio->bi_private;
 
-       if (error) {
-               mlog(ML_ERROR, "IO Error %d\n", error);
-               wc->wc_error = error;
+       if (bio->bi_error) {
+               mlog(ML_ERROR, "IO Error %d\n", bio->bi_error);
+               wc->wc_error = bio->bi_error;
        }
 
        o2hb_bio_wait_dec(wc, 1);
 
  */
 STATIC void
 xfs_end_bio(
-       struct bio              *bio,
-       int                     error)
+       struct bio              *bio)
 {
        xfs_ioend_t             *ioend = bio->bi_private;
 
-       ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error;
+       ioend->io_error = bio->bi_error;
 
        /* Toss bio and pass work off to an xfsdatad thread */
        bio->bi_private = NULL;
 
 
 STATIC void
 xfs_buf_bio_end_io(
-       struct bio              *bio,
-       int                     error)
+       struct bio              *bio)
 {
        xfs_buf_t               *bp = (xfs_buf_t *)bio->bi_private;
 
         * don't overwrite existing errors - otherwise we can lose errors on
         * buffers that require multiple bios to complete.
         */
-       if (error) {
+       if (bio->bi_error) {
                spin_lock(&bp->b_lock);
                if (!bp->b_io_error)
-                       bp->b_io_error = error;
+                       bp->b_io_error = bio->bi_error;
                spin_unlock(&bp->b_lock);
        }
 
 
        return offset || ((bprv->bv_offset + bprv->bv_len) & (PAGE_SIZE - 1));
 }
 
-#define bio_io_error(bio) bio_endio((bio), -EIO)
-
 /*
  * drivers should _never_ use the all version - the bio may have been split
  * before it got to the driver and the driver won't own all of it
 
 }
 
-extern void bio_endio(struct bio *, int);
+extern void bio_endio(struct bio *);
+
+static inline void bio_io_error(struct bio *bio)
+{
+       bio->bi_error = -EIO;
+       bio_endio(bio);
+}
+
 struct request_queue;
 extern int bio_phys_segments(struct request_queue *, struct bio *);
 
 extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int);
 extern bool bio_integrity_enabled(struct bio *bio);
 extern int bio_integrity_prep(struct bio *);
-extern void bio_integrity_endio(struct bio *, int);
+extern void bio_integrity_endio(struct bio *);
 extern void bio_integrity_advance(struct bio *, unsigned int);
 extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int);
 extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t);
 
 struct block_device;
 struct io_context;
 struct cgroup_subsys_state;
-typedef void (bio_end_io_t) (struct bio *, int);
+typedef void (bio_end_io_t) (struct bio *);
 typedef void (bio_destructor_t) (struct bio *);
 
 /*
 
        struct bvec_iter        bi_iter;
 
+       int                     bi_error;
        /* Number of segments in this BIO after
         * physical address coalescing is performed.
         */
 /*
  * bio flags
  */
-#define BIO_UPTODATE   0       /* ok after I/O completion */
 #define BIO_SEG_VALID  1       /* bi_phys_segments valid */
 #define BIO_CLONED     2       /* doesn't own data */
 #define BIO_BOUNCED    3       /* bio is a bounce bio */
 
 /* linux/mm/page_io.c */
 extern int swap_readpage(struct page *);
 extern int swap_writepage(struct page *page, struct writeback_control *wbc);
-extern void end_swap_bio_write(struct bio *bio, int err);
+extern void end_swap_bio_write(struct bio *bio);
 extern int __swap_writepage(struct page *page, struct writeback_control *wbc,
-       void (*end_write_func)(struct bio *, int));
+       bio_end_io_t end_write_func);
 extern int swap_set_page_dirty(struct page *page);
 
 int add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
 
        hb->error = 0;
 }
 
-static void hib_end_io(struct bio *bio, int error)
+static void hib_end_io(struct bio *bio)
 {
        struct hib_bio_batch *hb = bio->bi_private;
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct page *page = bio->bi_io_vec[0].bv_page;
 
-       if (!uptodate || error) {
+       if (bio->bi_error) {
                printk(KERN_ALERT "Read-error on swap-device (%u:%u:%Lu)\n",
                                imajor(bio->bi_bdev->bd_inode),
                                iminor(bio->bi_bdev->bd_inode),
                                (unsigned long long)bio->bi_iter.bi_sector);
-
-               if (!error)
-                       error = -EIO;
        }
 
        if (bio_data_dir(bio) == WRITE)
                put_page(page);
 
-       if (error && !hb->error)
-               hb->error = error;
+       if (bio->bi_error && !hb->error)
+               hb->error = bio->bi_error;
        if (atomic_dec_and_test(&hb->count))
                wake_up(&hb->wait);
 
 
        if (likely(!bt))
                return;
 
-       if (!error && !bio_flagged(bio, BIO_UPTODATE))
-               error = EIO;
-
        __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
                        bio->bi_rw, what, error, 0, NULL);
 }
 
                __blk_add_trace(bt, bio->bi_iter.bi_sector,
                                bio->bi_iter.bi_size, bio->bi_rw, BLK_TA_SPLIT,
-                               !bio_flagged(bio, BIO_UPTODATE),
-                               sizeof(rpdu), &rpdu);
+                               bio->bi_error, sizeof(rpdu), &rpdu);
        }
 }
 
        r.sector_from = cpu_to_be64(from);
 
        __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
-                       bio->bi_rw, BLK_TA_REMAP,
-                       !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r);
+                       bio->bi_rw, BLK_TA_REMAP, bio->bi_error,
+                       sizeof(r), &r);
 }
 
 /**
 
        return bio;
 }
 
-void end_swap_bio_write(struct bio *bio, int err)
+void end_swap_bio_write(struct bio *bio)
 {
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct page *page = bio->bi_io_vec[0].bv_page;
 
-       if (!uptodate) {
+       if (bio->bi_error) {
                SetPageError(page);
                /*
                 * We failed to write the page out to swap-space.
        bio_put(bio);
 }
 
-static void end_swap_bio_read(struct bio *bio, int err)
+static void end_swap_bio_read(struct bio *bio)
 {
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct page *page = bio->bi_io_vec[0].bv_page;
 
-       if (!uptodate) {
+       if (bio->bi_error) {
                SetPageError(page);
                ClearPageUptodate(page);
                printk(KERN_ALERT "Read-error on swap-device (%u:%u:%Lu)\n",
 }
 
 int __swap_writepage(struct page *page, struct writeback_control *wbc,
-       void (*end_write_func)(struct bio *, int))
+               bio_end_io_t end_write_func)
 {
        struct bio *bio;
        int ret, rw = WRITE;