Re: [PATCH] block: add a bi_error field to struct bio

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jul 20, 2015 at 03:29:37PM +0200, Christoph Hellwig wrote:
> Currently we have two different ways to signal an I/O error on a BIO:
> 
>  (1) by clearing the BIO_UPTODATE flag
>  (2) by returning a Linux errno value to the bi_end_io callback
> 
> The first one has the drawback of only communicating a single possible
> error (-EIO), and the second one has the drawback of not beeing persistent
> when bios are queued up, and are not passed along from child to parent
> bio in the ever more popular chaining scenario.  Having both mechanisms
> available has the additional drawback of utterly confusing driver authors
> and introducing bugs where various I/O submitters only deal with one of
> them, and the others have to add boilerplate code to deal with both kinds
> of error returns.
> 
> So add a new bi_error field to store an errno value directly in struct
> bio and remove the existing mechanisms to clean all this up.

Reviewed-by: Liu Bo <bo.li.liu@xxxxxxxxxx> (btrfs)

Thanks,

-liubo

> 
> Signed-off-by: Christoph Hellwig <hch@xxxxxx>
> ---
>  Documentation/block/biodoc.txt      |  2 +-
>  arch/m68k/emu/nfblock.c             |  2 +-
>  arch/powerpc/sysdev/axonram.c       |  2 +-
>  arch/xtensa/platforms/iss/simdisk.c | 12 ++-----
>  block/bio-integrity.c               | 11 +++----
>  block/bio.c                         | 43 +++++++++++--------------
>  block/blk-core.c                    | 15 ++++-----
>  block/blk-lib.c                     | 30 ++++++++----------
>  block/blk-map.c                     |  2 +-
>  block/blk-mq.c                      |  6 ++--
>  block/bounce.c                      | 27 ++++++++--------
>  drivers/block/aoe/aoecmd.c          | 10 +++---
>  drivers/block/aoe/aoedev.c          |  2 +-
>  drivers/block/brd.c                 | 13 +++++---
>  drivers/block/drbd/drbd_actlog.c    |  4 +--
>  drivers/block/drbd/drbd_bitmap.c    | 19 +++---------
>  drivers/block/drbd/drbd_int.h       | 11 ++++---
>  drivers/block/drbd/drbd_req.c       | 10 +++---
>  drivers/block/drbd/drbd_worker.c    | 44 +++++++-------------------
>  drivers/block/floppy.c              |  7 +++--
>  drivers/block/null_blk.c            |  2 +-
>  drivers/block/pktcdvd.c             | 32 +++++++++----------
>  drivers/block/ps3vram.c             |  3 +-
>  drivers/block/rsxx/dev.c            |  9 ++++--
>  drivers/block/umem.c                |  4 +--
>  drivers/block/xen-blkback/blkback.c |  4 +--
>  drivers/block/xen-blkfront.c        |  9 ++----
>  drivers/block/zram/zram_drv.c       |  5 ++-
>  drivers/md/bcache/btree.c           | 10 +++---
>  drivers/md/bcache/closure.h         |  2 +-
>  drivers/md/bcache/io.c              |  8 ++---
>  drivers/md/bcache/journal.c         |  8 ++---
>  drivers/md/bcache/movinggc.c        |  8 ++---
>  drivers/md/bcache/request.c         | 27 ++++++++--------
>  drivers/md/bcache/super.c           | 14 ++++-----
>  drivers/md/bcache/writeback.c       | 10 +++---
>  drivers/md/dm-bio-prison.c          |  6 ++--
>  drivers/md/dm-bufio.c               | 26 ++++++++++------
>  drivers/md/dm-cache-target.c        | 24 +++++++-------
>  drivers/md/dm-crypt.c               | 14 ++++-----
>  drivers/md/dm-flakey.c              |  2 +-
>  drivers/md/dm-io.c                  |  6 ++--
>  drivers/md/dm-log-writes.c          | 11 +++----
>  drivers/md/dm-raid1.c               | 24 +++++++-------
>  drivers/md/dm-snap.c                |  6 ++--
>  drivers/md/dm-stripe.c              |  2 +-
>  drivers/md/dm-thin.c                | 41 +++++++++++++-----------
>  drivers/md/dm-verity.c              |  9 +++---
>  drivers/md/dm-zero.c                |  2 +-
>  drivers/md/dm.c                     | 15 +++++----
>  drivers/md/faulty.c                 |  4 +--
>  drivers/md/linear.c                 |  2 +-
>  drivers/md/md.c                     | 18 +++++------
>  drivers/md/multipath.c              | 12 +++----
>  drivers/md/raid0.c                  |  2 +-
>  drivers/md/raid1.c                  | 53 ++++++++++++++++---------------
>  drivers/md/raid10.c                 | 55 +++++++++++++++-----------------
>  drivers/md/raid5.c                  | 52 +++++++++++++++----------------
>  drivers/nvdimm/blk.c                |  5 +--
>  drivers/nvdimm/btt.c                |  5 +--
>  drivers/nvdimm/pmem.c               |  2 +-
>  drivers/s390/block/dcssblk.c        |  2 +-
>  drivers/s390/block/xpram.c          |  3 +-
>  drivers/target/target_core_iblock.c | 21 +++++--------
>  drivers/target/target_core_pscsi.c  |  6 ++--
>  fs/btrfs/check-integrity.c          | 10 +++---
>  fs/btrfs/compression.c              | 24 ++++++++------
>  fs/btrfs/disk-io.c                  | 35 +++++++++++----------
>  fs/btrfs/extent_io.c                | 30 +++++++-----------
>  fs/btrfs/inode.c                    | 50 ++++++++++++++++--------------
>  fs/btrfs/raid56.c                   | 62 +++++++++++++++++--------------------
>  fs/btrfs/scrub.c                    | 22 ++++++-------
>  fs/btrfs/volumes.c                  | 23 +++++++-------
>  fs/buffer.c                         |  4 +--
>  fs/direct-io.c                      | 13 ++++----
>  fs/ext4/page-io.c                   | 15 ++++-----
>  fs/ext4/readpage.c                  |  6 ++--
>  fs/f2fs/data.c                      | 10 +++---
>  fs/gfs2/lops.c                      | 10 +++---
>  fs/gfs2/ops_fstype.c                |  6 ++--
>  fs/jfs/jfs_logmgr.c                 |  8 ++---
>  fs/jfs/jfs_metapage.c               |  8 ++---
>  fs/logfs/dev_bdev.c                 | 12 +++----
>  fs/mpage.c                          |  4 +--
>  fs/nfs/blocklayout/blocklayout.c    | 14 ++++-----
>  fs/nilfs2/segbuf.c                  |  5 ++-
>  fs/ocfs2/cluster/heartbeat.c        |  9 +++---
>  fs/xfs/xfs_aops.c                   |  5 ++-
>  fs/xfs/xfs_buf.c                    |  7 ++---
>  include/linux/bio.h                 | 13 +++++---
>  include/linux/blk_types.h           |  4 +--
>  include/linux/swap.h                |  4 +--
>  kernel/power/swap.c                 | 12 +++----
>  kernel/trace/blktrace.c             | 10 ++----
>  mm/page_io.c                        | 12 +++----
>  95 files changed, 622 insertions(+), 682 deletions(-)
> 
> diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
> index fd12c0d..5be8a7f 100644
> --- a/Documentation/block/biodoc.txt
> +++ b/Documentation/block/biodoc.txt
> @@ -1109,7 +1109,7 @@ it will loop and handle as many sectors (on a bio-segment granularity)
>  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.
> diff --git a/arch/m68k/emu/nfblock.c b/arch/m68k/emu/nfblock.c
> index 2d75ae2..f2a00c5 100644
> --- a/arch/m68k/emu/nfblock.c
> +++ b/arch/m68k/emu/nfblock.c
> @@ -76,7 +76,7 @@ static void nfhd_make_request(struct request_queue *queue, struct bio *bio)
>  				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)
> diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
> index ee90db1..f86250c 100644
> --- a/arch/powerpc/sysdev/axonram.c
> +++ b/arch/powerpc/sysdev/axonram.c
> @@ -132,7 +132,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
>  		phys_mem += vec.bv_len;
>  		transfered += vec.bv_len;
>  	}
> -	bio_endio(bio, 0);
> +	bio_endio(bio);
>  }
>  
>  /**
> diff --git a/arch/xtensa/platforms/iss/simdisk.c b/arch/xtensa/platforms/iss/simdisk.c
> index 48eebac..fa84ca9 100644
> --- a/arch/xtensa/platforms/iss/simdisk.c
> +++ b/arch/xtensa/platforms/iss/simdisk.c
> @@ -101,8 +101,9 @@ static void simdisk_transfer(struct simdisk *dev, unsigned long sector,
>  	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;
> @@ -116,17 +117,10 @@ static int simdisk_xfer_bio(struct simdisk *dev, struct bio *bio)
>  		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;
> diff --git a/block/bio-integrity.c b/block/bio-integrity.c
> index 719b715..4aecca7 100644
> --- a/block/bio-integrity.c
> +++ b/block/bio-integrity.c
> @@ -355,13 +355,12 @@ static void bio_integrity_verify_fn(struct work_struct *work)
>  		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);
>  }
>  
>  /**
> @@ -376,7 +375,7 @@ static void bio_integrity_verify_fn(struct work_struct *work)
>   * 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);
>  
> @@ -386,9 +385,9 @@ void bio_integrity_endio(struct bio *bio, int error)
>  	 * 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;
>  	}
> diff --git a/block/bio.c b/block/bio.c
> index 2a00d34..a23f489 100644
> --- a/block/bio.c
> +++ b/block/bio.c
> @@ -269,7 +269,6 @@ static void bio_free(struct bio *bio)
>  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);
>  }
> @@ -292,14 +291,17 @@ void bio_reset(struct bio *bio)
>  	__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);
>  }
>  
> @@ -896,11 +898,11 @@ struct submit_bio_ret {
>  	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);
>  }
>  
> @@ -1445,7 +1447,7 @@ void bio_unmap_user(struct bio *bio)
>  }
>  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);
>  }
> @@ -1501,13 +1503,13 @@ struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len,
>  }
>  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;
> @@ -1518,7 +1520,7 @@ static void bio_copy_kern_endio_read(struct bio *bio, int err)
>  		p += bvec->bv_len;
>  	}
>  
> -	bio_copy_kern_endio(bio, err);
> +	bio_copy_kern_endio(bio);
>  }
>  
>  /**
> @@ -1778,25 +1780,15 @@ static inline bool bio_remaining_done(struct bio *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;
>  
> @@ -1810,11 +1802,12 @@ void bio_endio(struct bio *bio, int error)
>  		 */
>  		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;
>  		}
>  	}
> diff --git a/block/blk-core.c b/block/blk-core.c
> index 627ed0c..7ef15b9 100644
> --- a/block/blk-core.c
> +++ b/block/blk-core.c
> @@ -143,9 +143,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio,
>  			  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);
> @@ -154,7 +152,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio,
>  
>  	/* 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)
> @@ -1620,7 +1618,8 @@ static void blk_queue_bio(struct request_queue *q, struct bio *bio)
>  	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;
>  	}
>  
> @@ -1673,7 +1672,8 @@ get_rq:
>  	 */
>  	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;
>  	}
>  
> @@ -1896,7 +1896,8 @@ generic_make_request_checks(struct bio *bio)
>  	return true;
>  
>  end_io:
> -	bio_endio(bio, err);
> +	bio->bi_error = err;
> +	bio_endio(bio);
>  	return false;
>  }
>  
> diff --git a/block/blk-lib.c b/block/blk-lib.c
> index 7688ee3..6dee174 100644
> --- a/block/blk-lib.c
> +++ b/block/blk-lib.c
> @@ -11,16 +11,16 @@
>  
>  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);
> @@ -78,7 +78,7 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
>  	}
>  
>  	atomic_set(&bb.done, 1);
> -	bb.flags = 1 << BIO_UPTODATE;
> +	bb.error = 0;
>  	bb.wait = &wait;
>  
>  	blk_start_plug(&plug);
> @@ -134,9 +134,8 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
>  	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);
> @@ -172,7 +171,7 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector,
>  		return -EOPNOTSUPP;
>  
>  	atomic_set(&bb.done, 1);
> -	bb.flags = 1 << BIO_UPTODATE;
> +	bb.error = 0;
>  	bb.wait = &wait;
>  
>  	while (nr_sects) {
> @@ -208,9 +207,8 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector,
>  	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);
> @@ -236,7 +234,7 @@ static int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
>  	DECLARE_COMPLETION_ONSTACK(wait);
>  
>  	atomic_set(&bb.done, 1);
> -	bb.flags = 1 << BIO_UPTODATE;
> +	bb.error = 0;
>  	bb.wait = &wait;
>  
>  	ret = 0;
> @@ -270,10 +268,8 @@ static int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
>  	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;
>  }
>  
> diff --git a/block/blk-map.c b/block/blk-map.c
> index da310a1..5fe1c30 100644
> --- a/block/blk-map.c
> +++ b/block/blk-map.c
> @@ -103,7 +103,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
>  		 * normal IO completion path
>  		 */
>  		bio_get(bio);
> -		bio_endio(bio, 0);
> +		bio_endio(bio);
>  		__blk_rq_unmap_user(bio);
>  		return -EINVAL;
>  	}
> diff --git a/block/blk-mq.c b/block/blk-mq.c
> index 7d842db..9455902 100644
> --- a/block/blk-mq.c
> +++ b/block/blk-mq.c
> @@ -1199,7 +1199,7 @@ static struct request *blk_mq_map_request(struct request_queue *q,
>  	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;
>  	}
>  
> @@ -1283,7 +1283,7 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
>  	blk_queue_bounce(q, &bio);
>  
>  	if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
> -		bio_endio(bio, -EIO);
> +		bio_io_error(bio);
>  		return;
>  	}
>  
> @@ -1368,7 +1368,7 @@ static void blk_sq_make_request(struct request_queue *q, struct bio *bio)
>  	blk_queue_bounce(q, &bio);
>  
>  	if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
> -		bio_endio(bio, -EIO);
> +		bio_io_error(bio);
>  		return;
>  	}
>  
> diff --git a/block/bounce.c b/block/bounce.c
> index b173112..f4db245 100644
> --- a/block/bounce.c
> +++ b/block/bounce.c
> @@ -123,7 +123,7 @@ static void copy_to_high_bio_irq(struct bio *to, struct bio *from)
>  	}
>  }
>  
> -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;
> @@ -141,39 +141,40 @@ static void bounce_end_io(struct bio *bio, mempool_t *pool, int err)
>  		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
> diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
> index 422b7d8..ad80c85 100644
> --- a/drivers/block/aoe/aoecmd.c
> +++ b/drivers/block/aoe/aoecmd.c
> @@ -1110,7 +1110,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail)
>  		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 */
> @@ -1172,7 +1172,7 @@ ktiocomplete(struct frame *f)
>  			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;
>  	}
>  
> @@ -1185,7 +1185,7 @@ noskb:		if (buf)
>  				"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) {
> @@ -1193,7 +1193,7 @@ noskb:		if (buf)
>  				"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);
> @@ -1695,7 +1695,7 @@ aoe_failbuf(struct aoedev *d, struct buf *buf)
>  	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);
>  }
> diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
> index e774c50..ffd1947 100644
> --- a/drivers/block/aoe/aoedev.c
> +++ b/drivers/block/aoe/aoedev.c
> @@ -170,7 +170,7 @@ aoe_failip(struct aoedev *d)
>  	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;
> diff --git a/drivers/block/brd.c b/drivers/block/brd.c
> index e573e470b..f9ab745 100644
> --- a/drivers/block/brd.c
> +++ b/drivers/block/brd.c
> @@ -331,14 +331,12 @@ static void brd_make_request(struct request_queue *q, struct bio *bio)
>  	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;
>  	}
> @@ -349,15 +347,20 @@ static void brd_make_request(struct request_queue *q, struct bio *bio)
>  
>  	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,
> diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
> index 1318e32..b3868e7 100644
> --- a/drivers/block/drbd/drbd_actlog.c
> +++ b/drivers/block/drbd/drbd_actlog.c
> @@ -175,11 +175,11 @@ static int _drbd_md_sync_page_io(struct drbd_device *device,
>  	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:
> diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
> index 434c77d..e5e0f19 100644
> --- a/drivers/block/drbd/drbd_bitmap.c
> +++ b/drivers/block/drbd/drbd_bitmap.c
> @@ -941,36 +941,27 @@ static void drbd_bm_aio_ctx_destroy(struct kref *kref)
>  }
>  
>  /* 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);
> @@ -1031,7 +1022,7 @@ static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr) __must_ho
>  
>  	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
> diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
> index efd19c2..a08c4a9 100644
> --- a/drivers/block/drbd/drbd_int.h
> +++ b/drivers/block/drbd/drbd_int.h
> @@ -1481,9 +1481,9 @@ extern int drbd_khelper(struct drbd_device *device, char *cmd);
>  
>  /* 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);
> @@ -1604,12 +1604,13 @@ static inline void drbd_generic_make_request(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);
>  }
> diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
> index 3907202..9cb4116 100644
> --- a/drivers/block/drbd/drbd_req.c
> +++ b/drivers/block/drbd/drbd_req.c
> @@ -201,7 +201,8 @@ void start_new_tl_epoch(struct drbd_connection *connection)
>  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);
>  }
>  
> @@ -1153,12 +1154,12 @@ drbd_submit_req_private_bio(struct drbd_request *req)
>  				      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)
> @@ -1191,7 +1192,8 @@ drbd_request_prepare(struct drbd_device *device, struct bio *bio, unsigned long
>  		/* 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;
> diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
> index d0fae55..5578c14 100644
> --- a/drivers/block/drbd/drbd_worker.c
> +++ b/drivers/block/drbd/drbd_worker.c
> @@ -65,12 +65,12 @@ rwlock_t global_state_lock;
>  /* 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.
> @@ -170,31 +170,20 @@ void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(l
>  /* 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 */
> @@ -208,24 +197,13 @@ void drbd_peer_request_endio(struct bio *bio, int error)
>  
>  /* 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",
> @@ -259,14 +237,14 @@ void drbd_request_endio(struct bio *bio, int error)
>  		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
> @@ -279,7 +257,7 @@ void drbd_request_endio(struct bio *bio, int error)
>  		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);
> diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
> index a08cda9..331363e 100644
> --- a/drivers/block/floppy.c
> +++ b/drivers/block/floppy.c
> @@ -3771,13 +3771,14 @@ struct rb0_cbdata {
>  	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);
> diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c
> index 69de41a..016a59a 100644
> --- a/drivers/block/null_blk.c
> +++ b/drivers/block/null_blk.c
> @@ -222,7 +222,7 @@ static void end_cmd(struct nullb_cmd *cmd)
>  		blk_end_request_all(cmd->rq, 0);
>  		break;
>  	case NULL_Q_BIO:
> -		bio_endio(cmd->bio, 0);
> +		bio_endio(cmd->bio);
>  		break;
>  	}
>  
> diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
> index 4c20c22..a7a259e 100644
> --- a/drivers/block/pktcdvd.c
> +++ b/drivers/block/pktcdvd.c
> @@ -977,7 +977,7 @@ static void pkt_make_local_copy(struct packet_data *pkt, struct bio_vec *bvec)
>  	}
>  }
>  
> -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;
> @@ -985,9 +985,9 @@ static void pkt_end_io_read(struct bio *bio, int err)
>  
>  	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);
> @@ -996,13 +996,13 @@ static void pkt_end_io_read(struct bio *bio, int err)
>  	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++;
>  
> @@ -1340,22 +1340,22 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
>  	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 (;;) {
> @@ -1384,7 +1384,7 @@ static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data
>  			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);
> @@ -1401,8 +1401,7 @@ static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data
>  			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:
> @@ -2332,13 +2331,14 @@ static void pkt_close(struct gendisk *disk, fmode_t mode)
>  }
>  
>  
> -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);
>  }
> diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c
> index b1612eb..49b4706 100644
> --- a/drivers/block/ps3vram.c
> +++ b/drivers/block/ps3vram.c
> @@ -593,7 +593,8 @@ out:
>  	next = bio_list_peek(&priv->list);
>  	spin_unlock_irq(&priv->lock);
>  
> -	bio_endio(bio, error);
> +	bio->bi_error = error;
> +	bio_endio(bio);
>  	return next;
>  }
>  
> diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c
> index ac8c62c..63b9d2f 100644
> --- a/drivers/block/rsxx/dev.c
> +++ b/drivers/block/rsxx/dev.c
> @@ -137,7 +137,10 @@ static void bio_dma_done_cb(struct rsxx_cardinfo *card,
>  		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);
>  	}
>  }
> @@ -199,7 +202,9 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio)
>  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 -------------------*/
> diff --git a/drivers/block/umem.c b/drivers/block/umem.c
> index 4cf81b5..3b3afd2 100644
> --- a/drivers/block/umem.c
> +++ b/drivers/block/umem.c
> @@ -456,7 +456,7 @@ static void process_page(unsigned long data)
>  				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,
> @@ -505,7 +505,7 @@ static void process_page(unsigned long data)
>  
>  		return_bio = bio->bi_next;
>  		bio->bi_next = NULL;
> -		bio_endio(bio, 0);
> +		bio_endio(bio);
>  	}
>  }
>  
> diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
> index ced9677..662648e 100644
> --- a/drivers/block/xen-blkback/blkback.c
> +++ b/drivers/block/xen-blkback/blkback.c
> @@ -1078,9 +1078,9 @@ static void __end_block_io_op(struct pending_req *pending_req, int error)
>  /*
>   * 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);
>  }
>  
> diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
> index 6d89ed3..d542db7 100644
> --- a/drivers/block/xen-blkfront.c
> +++ b/drivers/block/xen-blkfront.c
> @@ -82,7 +82,6 @@ struct blk_shadow {
>  struct split_bio {
>  	struct bio *bio;
>  	atomic_t pending;
> -	int err;
>  };
>  
>  static DEFINE_MUTEX(blkfront_mutex);
> @@ -1478,16 +1477,14 @@ static int blkfront_probe(struct xenbus_device *dev,
>  	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);
> diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
> index f439ad2..68c3d48 100644
> --- a/drivers/block/zram/zram_drv.c
> +++ b/drivers/block/zram/zram_drv.c
> @@ -850,7 +850,7 @@ static void __zram_make_request(struct zram *zram, struct bio *bio)
>  
>  	if (unlikely(bio->bi_rw & REQ_DISCARD)) {
>  		zram_bio_discard(zram, index, offset, bio);
> -		bio_endio(bio, 0);
> +		bio_endio(bio);
>  		return;
>  	}
>  
> @@ -883,8 +883,7 @@ static void __zram_make_request(struct zram *zram, struct bio *bio)
>  		update_position(&index, &offset, &bvec);
>  	}
>  
> -	set_bit(BIO_UPTODATE, &bio->bi_flags);
> -	bio_endio(bio, 0);
> +	bio_endio(bio);
>  	return;
>  
>  out:
> diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
> index 00cde40..83392f8 100644
> --- a/drivers/md/bcache/btree.c
> +++ b/drivers/md/bcache/btree.c
> @@ -278,7 +278,7 @@ err:
>  	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);
> @@ -305,7 +305,7 @@ static void bch_btree_node_read(struct btree *b)
>  	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);
> @@ -371,15 +371,15 @@ static void btree_node_write_done(struct closure *cl)
>  	__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);
>  }
>  
> diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h
> index 79a6d63..782cc2c 100644
> --- a/drivers/md/bcache/closure.h
> +++ b/drivers/md/bcache/closure.h
> @@ -38,7 +38,7 @@
>   * 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);
>   * }
> diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c
> index bf6a9ca..9440df9 100644
> --- a/drivers/md/bcache/io.c
> +++ b/drivers/md/bcache/io.c
> @@ -55,19 +55,19 @@ static void bch_bio_submit_split_done(struct closure *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);
> diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
> index 418607a..d6a4e16 100644
> --- a/drivers/md/bcache/journal.c
> +++ b/drivers/md/bcache/journal.c
> @@ -24,7 +24,7 @@
>   * 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);
> @@ -401,7 +401,7 @@ retry:
>  
>  #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);
> @@ -547,11 +547,11 @@ void bch_journal_next(struct journal *j)
>  		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);
>  }
>  
> diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c
> index cd74903..b929fc9 100644
> --- a/drivers/md/bcache/movinggc.c
> +++ b/drivers/md/bcache/movinggc.c
> @@ -60,20 +60,20 @@ static void write_moving_finish(struct closure *cl)
>  	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)
> diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
> index f292790..a09b946 100644
> --- a/drivers/md/bcache/request.c
> +++ b/drivers/md/bcache/request.c
> @@ -173,22 +173,22 @@ static void bch_data_insert_error(struct closure *cl)
>  	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)
> @@ -477,7 +477,7 @@ struct search {
>  	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;
> @@ -490,15 +490,15 @@ static void bch_cache_read_endio(struct bio *bio, int error)
>  	 * 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");
>  }
>  
>  /*
> @@ -591,13 +591,13 @@ static void cache_lookup(struct closure *cl)
>  
>  /* 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;
>  	}
> @@ -613,7 +613,8 @@ static void bio_complete(struct search *s)
>  				    &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;
>  	}
>  }
> @@ -992,7 +993,7 @@ static void cached_dev_make_request(struct request_queue *q, struct bio *bio)
>  	} 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);
>  	}
> diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
> index fc8e545..be01fd3 100644
> --- a/drivers/md/bcache/super.c
> +++ b/drivers/md/bcache/super.c
> @@ -221,7 +221,7 @@ err:
>  	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 */
> @@ -290,11 +290,11 @@ void bch_write_bdev_super(struct cached_dev *dc, struct closure *parent)
>  	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);
>  }
>  
> @@ -339,12 +339,12 @@ void bcache_write_super(struct cache_set *c)
>  
>  /* 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);
>  }
> @@ -512,11 +512,11 @@ static struct uuid_entry *uuid_find_empty(struct cache_set *c)
>   * 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);
>  }
> diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
> index f1986bc..b4fc874 100644
> --- a/drivers/md/bcache/writeback.c
> +++ b/drivers/md/bcache/writeback.c
> @@ -166,12 +166,12 @@ static void write_dirty_finish(struct closure *cl)
>  	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);
> @@ -193,15 +193,15 @@ static void write_dirty(struct closure *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)
> diff --git a/drivers/md/dm-bio-prison.c b/drivers/md/dm-bio-prison.c
> index cd6d1d2..03af174 100644
> --- a/drivers/md/dm-bio-prison.c
> +++ b/drivers/md/dm-bio-prison.c
> @@ -236,8 +236,10 @@ void dm_cell_error(struct dm_bio_prison *prison,
>  	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);
>  
> diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
> index 86dbbc7..83cc52e 100644
> --- a/drivers/md/dm-bufio.c
> +++ b/drivers/md/dm-bufio.c
> @@ -545,7 +545,8 @@ static void dmio_complete(unsigned long error, void *context)
>  {
>  	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,
> @@ -575,13 +576,16 @@ 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, &region, 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
> @@ -589,7 +593,8 @@ static void inline_endio(struct bio *bio, int error)
>  	 */
>  	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,
> @@ -661,13 +666,14 @@ static void submit_io(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);
>  	}
>  
> @@ -1026,11 +1032,11 @@ found_buffer:
>   * 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));
>  
> diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
> index 1b4e175..04d0dad 100644
> --- a/drivers/md/dm-cache-target.c
> +++ b/drivers/md/dm-cache-target.c
> @@ -919,14 +919,14 @@ static void defer_writethrough_bio(struct cache *cache, struct bio *bio)
>  	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;
>  	}
>  
> @@ -1231,7 +1231,7 @@ static void migration_success_post_commit(struct dm_cache_migration *mg)
>  			 * 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);
> @@ -1284,7 +1284,7 @@ static void issue_copy(struct dm_cache_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;
> @@ -1294,7 +1294,7 @@ static void overwrite_endio(struct bio *bio, int err)
>  
>  	dm_unhook_bio(&pb->hook_info, bio);
>  
> -	if (err)
> +	if (bio->bi_error)
>  		mg->err = true;
>  
>  	mg->requeue_holder = false;
> @@ -1358,7 +1358,7 @@ static void issue_discard(struct dm_cache_migration *mg)
>  		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);
>  }
> @@ -1631,7 +1631,7 @@ static void process_discard_bio(struct cache *cache, struct prealloc *structs,
>  
>  	calc_discard_block_range(cache, bio, &b, &e);
>  	if (b == e) {
> -		bio_endio(bio, 0);
> +		bio_endio(bio);
>  		return;
>  	}
>  
> @@ -2213,8 +2213,10 @@ static void requeue_deferred_bios(struct cache *cache)
>  	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)
> @@ -3119,7 +3121,7 @@ static int cache_map(struct dm_target *ti, struct bio *bio)
>  			 * 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;
> diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
> index 0f48fed..744b80c 100644
> --- a/drivers/md/dm-crypt.c
> +++ b/drivers/md/dm-crypt.c
> @@ -1076,7 +1076,8 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
>  	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);
>  }
>  
>  /*
> @@ -1096,15 +1097,12 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
>   * 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
>  	 */
> @@ -1113,13 +1111,13 @@ static void crypt_endio(struct bio *clone, int error)
>  
>  	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);
>  }
> diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
> index b257e46..0448124 100644
> --- a/drivers/md/dm-flakey.c
> +++ b/drivers/md/dm-flakey.c
> @@ -296,7 +296,7 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
>  		 * Drop writes?
>  		 */
>  		if (test_bit(DROP_WRITES, &fc->flags)) {
> -			bio_endio(bio, 0);
> +			bio_endio(bio);
>  			return DM_MAPIO_SUBMITTED;
>  		}
>  
> diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
> index 74adcd2..efc6659 100644
> --- a/drivers/md/dm-io.c
> +++ b/drivers/md/dm-io.c
> @@ -134,12 +134,12 @@ static void dec_count(struct io *io, unsigned int region, int error)
>  		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);
>  
>  	/*
> @@ -149,7 +149,7 @@ static void endio(struct bio *bio, int error)
>  
>  	bio_put(bio);
>  
> -	dec_count(io, region, error);
> +	dec_count(io, region, bio->bi_error);
>  }
>  
>  /*-----------------------------------------------------------------
> diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c
> index ad1b049..e9d1748 100644
> --- a/drivers/md/dm-log-writes.c
> +++ b/drivers/md/dm-log-writes.c
> @@ -146,16 +146,16 @@ static void put_io_block(struct log_writes_c *lc)
>  	}
>  }
>  
> -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);
> @@ -205,7 +205,6 @@ static int write_metadata(struct log_writes_c *lc, void *entry,
>  	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) {
> @@ -270,7 +269,6 @@ static int log_one_block(struct log_writes_c *lc,
>  	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++) {
>  		/*
> @@ -292,7 +290,6 @@ static int log_one_block(struct log_writes_c *lc,
>  			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);
> @@ -606,7 +603,7 @@ static int log_writes_map(struct dm_target *ti, struct bio *bio)
>  		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;
>  	}
>  
> diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
> index d83696b..e1eabfb 100644
> --- a/drivers/md/dm-raid1.c
> +++ b/drivers/md/dm-raid1.c
> @@ -490,9 +490,11 @@ static void hold_bio(struct mirror_set *ms, struct bio *bio)
>  		 * 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;
>  	}
>  
> @@ -515,7 +517,7 @@ static void read_callback(unsigned long error, void *context)
>  	bio_set_m(bio, NULL);
>  
>  	if (likely(!error)) {
> -		bio_endio(bio, 0);
> +		bio_endio(bio);
>  		return;
>  	}
>  
> @@ -531,7 +533,7 @@ static void read_callback(unsigned long error, void *context)
>  
>  	DMERR_LIMIT("Read failure on mirror device %s.  Failing I/O.",
>  		    m->dev->name);
> -	bio_endio(bio, -EIO);
> +	bio_io_error(bio);
>  }
>  
>  /* Asynchronous read. */
> @@ -580,7 +582,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads)
>  		if (likely(m))
>  			read_async_bio(m, bio);
>  		else
> -			bio_endio(bio, -EIO);
> +			bio_io_error(bio);
>  	}
>  }
>  
> @@ -598,7 +600,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads)
>  
>  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;
> @@ -614,7 +616,7 @@ static void write_callback(unsigned long error, void *context)
>  	 * regions with the same code.
>  	 */
>  	if (likely(!error)) {
> -		bio_endio(bio, ret);
> +		bio_endio(bio);
>  		return;
>  	}
>  
> @@ -623,7 +625,8 @@ static void write_callback(unsigned long error, void *context)
>  	 * degrade the array.
>  	 */
>  	if (bio->bi_rw & REQ_DISCARD) {
> -		bio_endio(bio, -EOPNOTSUPP);
> +		bio->bi_error = -EOPNOTSUPP;
> +		bio_endio(bio);
>  		return;
>  	}
>  
> @@ -828,13 +831,12 @@ static void do_failures(struct mirror_set *ms, struct bio_list *failures)
>  		 * 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);
>  	}
>  }
>  
> diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
> index 7c82d3c..dd8ca0b 100644
> --- a/drivers/md/dm-snap.c
> +++ b/drivers/md/dm-snap.c
> @@ -1490,7 +1490,7 @@ out:
>  		error_bios(snapshot_bios);
>  	} else {
>  		if (full_bio)
> -			bio_endio(full_bio, 0);
> +			bio_endio(full_bio);
>  		flush_bios(snapshot_bios);
>  	}
>  
> @@ -1580,11 +1580,11 @@ static void start_copy(struct dm_snap_pending_exception *pe)
>  	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,
> diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
> index a672a15..4f94c7d 100644
> --- a/drivers/md/dm-stripe.c
> +++ b/drivers/md/dm-stripe.c
> @@ -273,7 +273,7 @@ static int stripe_map_range(struct stripe_c *sc, struct bio *bio,
>  		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;
>  	}
>  }
> diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
> index c33f61a..2ade2c4 100644
> --- a/drivers/md/dm-thin.c
> +++ b/drivers/md/dm-thin.c
> @@ -614,8 +614,10 @@ static void error_bio_list(struct bio_list *bios, int error)
>  {
>  	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)
> @@ -864,14 +866,14 @@ static void copy_complete(int read_err, unsigned long write_err, void *context)
>  	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);
>  }
>  
> @@ -996,7 +998,7 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *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);
> @@ -1026,7 +1028,7 @@ static void process_prepared_discard_fail(struct dm_thin_new_mapping *m)
>  
>  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);
>  }
>  
> @@ -1040,7 +1042,7 @@ static void process_prepared_discard_no_passdown(struct dm_thin_new_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);
> @@ -1111,7 +1113,8 @@ static void process_prepared_discard_passdown(struct dm_thin_new_mapping *m)
>  	 * 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);
>  }
> @@ -1487,9 +1490,10 @@ static void handle_unserviceable_bio(struct pool *pool, struct bio *bio)
>  {
>  	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);
>  }
>  
> @@ -1625,7 +1629,7 @@ static void process_discard_cell_passdown(struct thin_c *tc, struct dm_bio_priso
>  	 * 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)
> @@ -1639,7 +1643,7 @@ 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;
>  	}
>  
> @@ -1784,7 +1788,7 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
>  	if (bio_data_dir(bio) == READ) {
>  		zero_fill_bio(bio);
>  		cell_defer_no_holder(tc, cell);
> -		bio_endio(bio, 0);
> +		bio_endio(bio);
>  		return;
>  	}
>  
> @@ -1849,7 +1853,7 @@ static void process_cell(struct thin_c *tc, struct dm_bio_prison_cell *cell)
>  
>  			} else {
>  				zero_fill_bio(bio);
> -				bio_endio(bio, 0);
> +				bio_endio(bio);
>  			}
>  		} else
>  			provision_block(tc, bio, block, cell);
> @@ -1920,7 +1924,7 @@ static void __process_bio_read_only(struct thin_c *tc, struct bio *bio,
>  		}
>  
>  		zero_fill_bio(bio);
> -		bio_endio(bio, 0);
> +		bio_endio(bio);
>  		break;
>  
>  	default:
> @@ -1945,7 +1949,7 @@ static void process_cell_read_only(struct thin_c *tc, struct dm_bio_prison_cell
>  
>  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)
> @@ -2581,7 +2585,8 @@ static int thin_bio_map(struct dm_target *ti, 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;
>  	}
>  
> diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c
> index bb9c6a0..4b34df8 100644
> --- a/drivers/md/dm-verity.c
> +++ b/drivers/md/dm-verity.c
> @@ -458,8 +458,9 @@ static void verity_finish_io(struct dm_verity_io *io, int error)
>  
>  	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)
> @@ -469,12 +470,12 @@ 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;
>  	}
>  
> diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c
> index b9a64bb..766bc93 100644
> --- a/drivers/md/dm-zero.c
> +++ b/drivers/md/dm-zero.c
> @@ -47,7 +47,7 @@ static int zero_map(struct dm_target *ti, struct bio *bio)
>  		break;
>  	}
>  
> -	bio_endio(bio, 0);
> +	bio_endio(bio);
>  
>  	/* accepted bio, don't make new request */
>  	return DM_MAPIO_SUBMITTED;
> diff --git a/drivers/md/dm.c b/drivers/md/dm.c
> index f331d88..7f367fc 100644
> --- a/drivers/md/dm.c
> +++ b/drivers/md/dm.c
> @@ -944,7 +944,8 @@ static void dec_pending(struct dm_io *io, int error)
>  		} 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);
>  		}
>  	}
>  }
> @@ -957,17 +958,15 @@ static void disable_write_same(struct mapped_device *md)
>  	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)
> @@ -996,7 +995,7 @@ static void clone_endio(struct bio *bio, int error)
>  /*
>   * 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);
> @@ -1013,13 +1012,13 @@ static void end_clone_bio(struct bio *clone, int error)
>  		 * 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;
>  	}
>  
> diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c
> index 1277eb2..4a8e150 100644
> --- a/drivers/md/faulty.c
> +++ b/drivers/md/faulty.c
> @@ -70,7 +70,7 @@
>  #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;
>  
> @@ -181,7 +181,7 @@ static void make_request(struct mddev *mddev, struct bio *bio)
>  			/* special case - don't decrement, don't generic_make_request,
>  			 * just fail immediately
>  			 */
> -			bio_endio(bio, -EIO);
> +			bio_io_error(bio);
>  			return;
>  		}
>  
> diff --git a/drivers/md/linear.c b/drivers/md/linear.c
> index fa7d577..aefd661 100644
> --- a/drivers/md/linear.c
> +++ b/drivers/md/linear.c
> @@ -297,7 +297,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio)
>  		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);
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index d429c30..ac4381a 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -263,7 +263,9 @@ static void md_make_request(struct request_queue *q, struct bio *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 */
> @@ -377,7 +379,7 @@ static int md_mergeable_bvec(struct request_queue *q,
>   * 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;
> @@ -433,7 +435,7 @@ static void md_submit_flush_data(struct work_struct *ws)
>  
>  	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);
> @@ -728,15 +730,13 @@ void md_rdev_clear(struct md_rdev *rdev)
>  }
>  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);
>  	}
>  
> @@ -791,7 +791,7 @@ int sync_page_io(struct md_rdev *rdev, sector_t sector, int size,
>  	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;
>  }
> diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
> index ac3ede2..082a489 100644
> --- a/drivers/md/multipath.c
> +++ b/drivers/md/multipath.c
> @@ -77,18 +77,18 @@ static void multipath_end_bh_io (struct multipath_bh *mp_bh, int err)
>  	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)) {
>  		/*
> @@ -101,7 +101,7 @@ static void multipath_end_request(struct bio *bio, int error)
>  		       (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);
>  }
>  
> @@ -123,7 +123,7 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio)
>  
>  	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;
>  	}
> diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
> index efb654e..e6e0ae5 100644
> --- a/drivers/md/raid0.c
> +++ b/drivers/md/raid0.c
> @@ -543,7 +543,7 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio)
>  		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);
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index f80f1af..9aa7d1f 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
> @@ -255,9 +255,10 @@ static void call_bio_endio(struct r1bio *r1_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.
> @@ -312,9 +313,9 @@ static int find_bio_disk(struct r1bio *r1_bio, struct bio *bio)
>  	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;
> @@ -397,9 +398,8 @@ static void r1_bio_write_done(struct r1bio *r1_bio)
>  	}
>  }
>  
> -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;
> @@ -410,7 +410,7 @@ static void raid1_end_write_request(struct bio *bio, int error)
>  	/*
>  	 * '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,
> @@ -793,7 +793,7 @@ static void flush_pending_writes(struct r1conf *conf)
>  			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;
> @@ -1068,7 +1068,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule)
>  		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;
> @@ -1734,7 +1734,7 @@ abort:
>  	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;
>  
> @@ -1745,16 +1745,16 @@ static void end_sync_read(struct bio *bio, int error)
>  	 * 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;
> @@ -1941,7 +1941,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
>  		idx ++;
>  	}
>  	set_bit(R1BIO_Uptodate, &r1_bio->state);
> -	set_bit(BIO_UPTODATE, &bio->bi_flags);
> +	bio->bi_error = 0;
>  	return 1;
>  }
>  
> @@ -1965,15 +1965,14 @@ static void process_checks(struct r1bio *r1_bio)
>  	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 +
> @@ -1996,7 +1995,7 @@ static void process_checks(struct r1bio *r1_bio)
>  	}
>  	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;
> @@ -2006,14 +2005,14 @@ static void process_checks(struct r1bio *r1_bio)
>  		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;
> @@ -2028,7 +2027,7 @@ static void process_checks(struct r1bio *r1_bio)
>  		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);
> @@ -2269,11 +2268,11 @@ static void handle_sync_write_finished(struct r1conf *conf, struct r1bio *r1_bio
>  		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);
> diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
> index 940f2f3..929e9a2 100644
> --- a/drivers/md/raid10.c
> +++ b/drivers/md/raid10.c
> @@ -101,7 +101,7 @@ static int _enough(struct r10conf *conf, int previous, int ignore);
>  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)
> @@ -307,9 +307,9 @@ static void raid_end_bio_io(struct r10bio *r10_bio)
>  	} 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.
> @@ -358,9 +358,9 @@ static int find_bio_disk(struct r10conf *conf, struct r10bio *r10_bio,
>  	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;
> @@ -438,9 +438,8 @@ static void one_write_done(struct r10bio *r10_bio)
>  	}
>  }
>  
> -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;
> @@ -460,7 +459,7 @@ static void raid10_end_write_request(struct bio *bio, int error)
>  	/*
>  	 * 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.
> @@ -957,7 +956,7 @@ static void flush_pending_writes(struct r10conf *conf)
>  			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;
> @@ -1133,7 +1132,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)
>  		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;
> @@ -1916,7 +1915,7 @@ abort:
>  	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;
> @@ -1928,7 +1927,7 @@ static void end_sync_read(struct bio *bio, int error)
>  	} 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
> @@ -1977,9 +1976,8 @@ static void end_sync_request(struct r10bio *r10_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);
>  	struct r10bio *r10_bio = bio->bi_private;
>  	struct mddev *mddev = r10_bio->mddev;
>  	struct r10conf *conf = mddev->private;
> @@ -1996,7 +1994,7 @@ static void end_sync_write(struct bio *bio, int error)
>  	else
>  		rdev = conf->mirrors[d].rdev;
>  
> -	if (!uptodate) {
> +	if (bio->bi_error) {
>  		if (repl)
>  			md_error(mddev, rdev);
>  		else {
> @@ -2044,7 +2042,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
>  
>  	/* 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)
> @@ -2064,7 +2062,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
>  			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;
> @@ -2706,8 +2704,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
>  			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,
> @@ -2722,8 +2719,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
>  			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,
> @@ -2748,8 +2745,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
>  					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,
> @@ -3263,7 +3259,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
>  
>  			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;
> @@ -3300,7 +3296,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
>  			/* 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);
> @@ -3377,7 +3373,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
>  
>  		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);
>  		}
>  	}
> @@ -4380,7 +4376,7 @@ read_more:
>  	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;
> @@ -4601,9 +4597,8 @@ static int handle_reshape_read_error(struct mddev *mddev,
>  	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;
> @@ -4620,7 +4615,7 @@ static void end_reshape_write(struct bio *bio, int error)
>  		rdev = conf->mirrors[d].rdev;
>  	}
>  
> -	if (!uptodate) {
> +	if (bio->bi_error) {
>  		/* FIXME should record badblock */
>  		md_error(mddev, rdev);
>  	}
> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
> index 59e44e9..84d6eec 100644
> --- a/drivers/md/raid5.c
> +++ b/drivers/md/raid5.c
> @@ -233,7 +233,7 @@ static void return_io(struct bio *return_bi)
>  		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;
>  	}
>  }
> @@ -887,9 +887,9 @@ static int use_new_offset(struct r5conf *conf, struct stripe_head *sh)
>  }
>  
>  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)
>  {
> @@ -2277,12 +2277,11 @@ static void shrink_stripes(struct r5conf *conf)
>  	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;
> @@ -2291,9 +2290,9 @@ static void raid5_end_read_request(struct bio * bi, int error)
>  		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;
> @@ -2312,7 +2311,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
>  		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
> @@ -2400,13 +2399,12 @@ static void raid5_end_read_request(struct bio * bi, int error)
>  	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;
> @@ -2429,23 +2427,23 @@ static void raid5_end_write_request(struct bio *bi, int error)
>  			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);
> @@ -2466,7 +2464,7 @@ static void raid5_end_write_request(struct bio *bi, int error)
>  	}
>  	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))
> @@ -3107,7 +3105,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
>  		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;
> @@ -3131,7 +3130,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
>  		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;
> @@ -3156,7 +3156,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
>  			       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;
> @@ -4749,12 +4750,11 @@ static struct bio *remove_bio_from_retry(struct r5conf *conf)
>   *  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);
> @@ -4766,10 +4766,10 @@ static void raid5_align_endio(struct bio *bi, int error)
>  
>  	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;
> @@ -5133,7 +5133,7 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)
>  	remaining = raid5_dec_bi_active_stripes(bi);
>  	if (remaining == 0) {
>  		md_write_end(mddev);
> -		bio_endio(bi, 0);
> +		bio_endio(bi);
>  	}
>  }
>  
> @@ -5297,7 +5297,7 @@ static void make_request(struct mddev *mddev, struct bio * 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;
>  		}
>  	}
> @@ -5311,7 +5311,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
>  
>  		trace_block_bio_complete(bdev_get_queue(bi->bi_bdev),
>  					 bi, 0);
> -		bio_endio(bi, 0);
> +		bio_endio(bi);
>  	}
>  }
>  
> @@ -5707,7 +5707,7 @@ static int  retry_aligned_read(struct r5conf *conf, struct bio *raid_bio)
>  	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);
> diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
> index 4f97b24..0df77cb 100644
> --- a/drivers/nvdimm/blk.c
> +++ b/drivers/nvdimm/blk.c
> @@ -180,7 +180,7 @@ static void nd_blk_make_request(struct request_queue *q, struct bio *bio)
>  	 * 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;
>  	}
>  
> @@ -199,6 +199,7 @@ static void nd_blk_make_request(struct request_queue *q, struct bio *bio)
>  					"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;
>  		}
>  	}
> @@ -206,7 +207,7 @@ static void nd_blk_make_request(struct request_queue *q, struct bio *bio)
>  		nd_iostat_end(bio, start);
>  
>   out:
> -	bio_endio(bio, err);
> +	bio_endio(bio);
>  }
>  
>  static int nd_blk_rw_bytes(struct nd_namespace_common *ndns,
> diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
> index 411c7b2..341202e 100644
> --- a/drivers/nvdimm/btt.c
> +++ b/drivers/nvdimm/btt.c
> @@ -1189,7 +1189,7 @@ static void btt_make_request(struct request_queue *q, struct bio *bio)
>  	 * 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;
>  	}
>  
> @@ -1211,6 +1211,7 @@ static void btt_make_request(struct request_queue *q, struct bio *bio)
>  					"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;
>  		}
>  	}
> @@ -1218,7 +1219,7 @@ static void btt_make_request(struct request_queue *q, struct bio *bio)
>  		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,
> diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
> index ade9eb9..4c079d5 100644
> --- a/drivers/nvdimm/pmem.c
> +++ b/drivers/nvdimm/pmem.c
> @@ -77,7 +77,7 @@ static void pmem_make_request(struct request_queue *q, struct bio *bio)
>  	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,
> diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
> index da21281..8bcb822 100644
> --- a/drivers/s390/block/dcssblk.c
> +++ b/drivers/s390/block/dcssblk.c
> @@ -871,7 +871,7 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio)
>  		}
>  		bytes_done += bvec.bv_len;
>  	}
> -	bio_endio(bio, 0);
> +	bio_endio(bio);
>  	return;
>  fail:
>  	bio_io_error(bio);
> diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
> index 7d4e939..93856b9 100644
> --- a/drivers/s390/block/xpram.c
> +++ b/drivers/s390/block/xpram.c
> @@ -220,8 +220,7 @@ static void xpram_make_request(struct request_queue *q, struct bio *bio)
>  			index++;
>  		}
>  	}
> -	set_bit(BIO_UPTODATE, &bio->bi_flags);
> -	bio_endio(bio, 0);
> +	bio_endio(bio);
>  	return;
>  fail:
>  	bio_io_error(bio);
> diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
> index 6d88d24..5a9982f 100644
> --- a/drivers/target/target_core_iblock.c
> +++ b/drivers/target/target_core_iblock.c
> @@ -306,20 +306,13 @@ static void iblock_complete_cmd(struct se_cmd *cmd)
>  	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.
>  		 */
> @@ -370,15 +363,15 @@ static void iblock_submit_bios(struct bio_list *list, int rw)
>  	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);
> diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
> index 08e9084..de18790 100644
> --- a/drivers/target/target_core_pscsi.c
> +++ b/drivers/target/target_core_pscsi.c
> @@ -852,7 +852,7 @@ static ssize_t pscsi_show_configfs_dev_params(struct se_device *dev, char *b)
>  	return bl;
>  }
>  
> -static void pscsi_bi_endio(struct bio *bio, int error)
> +static void pscsi_bi_endio(struct bio *bio)
>  {
>  	bio_put(bio);
>  }
> @@ -973,7 +973,7 @@ fail:
>  	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;
>  }
> @@ -1061,7 +1061,7 @@ fail_free_bio:
>  	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:
> diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c
> index ce7dec8..541fbfa 100644
> --- a/fs/btrfs/check-integrity.c
> +++ b/fs/btrfs/check-integrity.c
> @@ -343,7 +343,7 @@ static int btrfsic_process_written_superblock(
>  		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,
> @@ -2207,7 +2207,7 @@ continue_loop:
>  	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;
> @@ -2215,7 +2215,7 @@ static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status)
>  	/* 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);
> @@ -2230,7 +2230,7 @@ static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status)
>  		     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);
> @@ -2252,7 +2252,7 @@ static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status)
>  		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)
> diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
> index ce62324..302266e 100644
> --- a/fs/btrfs/compression.c
> +++ b/fs/btrfs/compression.c
> @@ -152,7 +152,7 @@ fail:
>   * 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;
> @@ -160,7 +160,7 @@ static void end_compressed_bio_read(struct bio *bio, int err)
>  	unsigned long index;
>  	int ret;
>  
> -	if (err)
> +	if (bio->bi_error)
>  		cb->errors = 1;
>  
>  	/* if there are more bios still pending for this compressed
> @@ -210,7 +210,7 @@ csum_failed:
>  		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 */
> @@ -266,7 +266,7 @@ static noinline void end_compressed_writeback(struct inode *inode,
>   * 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;
> @@ -274,7 +274,7 @@ static void end_compressed_bio_write(struct bio *bio, int err)
>  	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
> @@ -293,7 +293,7 @@ static void end_compressed_bio_write(struct bio *bio, int err)
>  					 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);
> @@ -697,8 +697,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *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);
>  
> @@ -724,8 +726,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *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;
> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> index a9aadb2..a8c0de8 100644
> --- a/fs/btrfs/disk-io.c
> +++ b/fs/btrfs/disk-io.c
> @@ -703,7 +703,7 @@ static int btree_io_failed_hook(struct page *page, int failed_mirror)
>  	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;
> @@ -711,7 +711,7 @@ static void end_workqueue_bio(struct bio *bio, int err)
>  	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) {
> @@ -808,7 +808,8 @@ static void run_one_async_done(struct btrfs_work *work)
>  
>  	/* 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;
>  	}
>  
> @@ -908,8 +909,10 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
>  	 * 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;
>  }
>  
> @@ -960,10 +963,13 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
>  					  __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;
>  }
>  
> @@ -1735,16 +1741,15 @@ static void end_workqueue_fn(struct btrfs_work *work)
>  {
>  	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)
> @@ -3323,10 +3328,8 @@ static int write_dev_supers(struct btrfs_device *device,
>   * 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);
> @@ -3354,8 +3357,8 @@ static int write_dev_flush(struct btrfs_device *device, int wait)
>  
>  		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);
>  		}
> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> index 02d0581..c22f175 100644
> --- a/fs/btrfs/extent_io.c
> +++ b/fs/btrfs/extent_io.c
> @@ -2486,7 +2486,7 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end)
>   * 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;
> @@ -2516,7 +2516,7 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
>  		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);
> @@ -2548,10 +2548,10 @@ endio_readpage_release_extent(struct extent_io_tree *tree, u64 start, u64 len,
>   * 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;
> @@ -2564,16 +2564,13 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
>  	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
> @@ -2614,8 +2611,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
>  
>  		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 {
>  			/*
> @@ -2631,10 +2627,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
>  			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;
>  			}
> @@ -2684,7 +2677,7 @@ readpage_ok:
>  		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);
>  }
>  
> @@ -3696,7 +3689,7 @@ static void set_btree_ioerr(struct page *page)
>  	}
>  }
>  
> -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;
> @@ -3709,7 +3702,8 @@ static void end_bio_extent_buffer_writepage(struct bio *bio, int err)
>  		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);
>  		}
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index b33c0cf..6b8becf 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -1845,8 +1845,10 @@ static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
>  	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;
>  }
>  
> @@ -1906,8 +1908,10 @@ mapit:
>  	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;
>  }
>  
> @@ -7689,13 +7693,13 @@ struct btrfs_retry_complete {
>  	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;
> @@ -7744,7 +7748,7 @@ try_again:
>  	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);
> @@ -7753,7 +7757,7 @@ static void btrfs_retry_endio(struct bio *bio, int err)
>  	int ret;
>  	int i;
>  
> -	if (err)
> +	if (bio->bi_error)
>  		goto end;
>  
>  	uptodate = 1;
> @@ -7836,12 +7840,13 @@ static int btrfs_subio_endio_read(struct inode *inode,
>  	}
>  }
>  
> -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);
> @@ -7852,17 +7857,14 @@ static void btrfs_endio_direct_read(struct bio *bio, int 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;
> @@ -7876,7 +7878,8 @@ static void btrfs_endio_direct_write(struct bio *bio, int err)
>  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;
>  
> @@ -7899,10 +7902,7 @@ 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);
>  }
>  
> @@ -7917,9 +7917,10 @@ static int __btrfs_submit_bio_start_direct_io(struct inode *inode, int rw,
>  	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,
> @@ -7948,8 +7949,8 @@ static void btrfs_end_dio_bio(struct bio *bio, int err)
>  	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);
> @@ -8220,7 +8221,8 @@ free_ordered:
>  	 * 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
> @@ -8247,7 +8249,7 @@ free_ordered:
>  			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.
> diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
> index fa72068..0a02e24 100644
> --- a/fs/btrfs/raid56.c
> +++ b/fs/btrfs/raid56.c
> @@ -851,7 +851,7 @@ static void free_raid_bio(struct btrfs_raid_bio *rbio)
>   * 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;
> @@ -864,9 +864,8 @@ static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err, int uptodate)
>  	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;
>  	}
>  }
> @@ -875,9 +874,10 @@ static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err, int uptodate)
>   * 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);
> @@ -893,7 +893,7 @@ static void raid_write_end_io(struct bio *bio, int err)
>  	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;
>  }
>  
> @@ -1071,7 +1071,7 @@ static int rbio_add_io_page(struct btrfs_raid_bio *rbio,
>  		 * 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)
> @@ -1087,7 +1087,6 @@ static int rbio_add_io_page(struct btrfs_raid_bio *rbio,
>  	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);
> @@ -1312,13 +1311,12 @@ write_data:
>  
>  		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);
>  }
>  
>  /*
> @@ -1441,11 +1439,11 @@ static void set_bio_pages_uptodate(struct bio *bio)
>   * 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);
> @@ -1455,7 +1453,6 @@ static void raid_rmw_end_io(struct bio *bio, int err)
>  	if (!atomic_dec_and_test(&rbio->stripes_pending))
>  		return;
>  
> -	err = 0;
>  	if (atomic_read(&rbio->error) > rbio->bbio->max_errors)
>  		goto cleanup;
>  
> @@ -1469,7 +1466,7 @@ static void raid_rmw_end_io(struct bio *bio, int err)
>  
>  cleanup:
>  
> -	rbio_orig_end_io(rbio, -EIO, 0);
> +	rbio_orig_end_io(rbio, -EIO);
>  }
>  
>  static void async_rmw_stripe(struct btrfs_raid_bio *rbio)
> @@ -1572,14 +1569,13 @@ static int raid56_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:
> @@ -1964,7 +1960,7 @@ cleanup_io:
>  		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;
> @@ -1976,7 +1972,7 @@ cleanup_io:
>  		else
>  			BUG();
>  	} else {
> -		rbio_orig_end_io(rbio, err, 0);
> +		rbio_orig_end_io(rbio, err);
>  	}
>  }
>  
> @@ -1984,7 +1980,7 @@ cleanup_io:
>   * 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;
>  
> @@ -1992,7 +1988,7 @@ static void raid_recover_end_io(struct bio *bio, int err)
>  	 * 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);
> @@ -2002,7 +1998,7 @@ static void raid_recover_end_io(struct bio *bio, int err)
>  		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);
>  }
> @@ -2094,7 +2090,6 @@ static int __raid56_parity_recover(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);
>  	}
>  out:
> @@ -2102,7 +2097,7 @@ out:
>  
>  cleanup:
>  	if (rbio->operation == BTRFS_RBIO_READ_REBUILD)
> -		rbio_orig_end_io(rbio, -EIO, 0);
> +		rbio_orig_end_io(rbio, -EIO);
>  	return -EIO;
>  }
>  
> @@ -2277,11 +2272,12 @@ static int alloc_rbio_essential_pages(struct btrfs_raid_bio *rbio)
>   * 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);
> @@ -2294,7 +2290,7 @@ static void raid_write_parity_end_io(struct bio *bio, int err)
>  	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,
> @@ -2437,7 +2433,7 @@ submit_write:
>  	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;
>  	}
>  
> @@ -2450,13 +2446,12 @@ submit_write:
>  
>  		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)
> @@ -2524,7 +2519,7 @@ static void validate_rbio_for_parity_scrub(struct btrfs_raid_bio *rbio)
>  	return;
>  
>  cleanup:
> -	rbio_orig_end_io(rbio, -EIO, 0);
> +	rbio_orig_end_io(rbio, -EIO);
>  }
>  
>  /*
> @@ -2535,11 +2530,11 @@ cleanup:
>   * 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);
> @@ -2632,14 +2627,13 @@ static void raid56_parity_scrub_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;
>  
>  cleanup:
> -	rbio_orig_end_io(rbio, -EIO, 0);
> +	rbio_orig_end_io(rbio, -EIO);
>  	return;
>  
>  finish:
> diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
> index 94db0fa..ebb8260 100644
> --- a/fs/btrfs/scrub.c
> +++ b/fs/btrfs/scrub.c
> @@ -278,7 +278,7 @@ static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
>  		       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,
> @@ -295,7 +295,7 @@ static void scrub_free_wr_ctx(struct scrub_wr_ctx *wr_ctx);
>  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);
> @@ -1429,11 +1429,11 @@ struct scrub_bio_ret {
>  	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);
>  }
>  
> @@ -1790,12 +1790,12 @@ static void scrub_wr_submit(struct scrub_ctx *sctx)
>  	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,
> @@ -2098,7 +2098,7 @@ static void scrub_submit(struct scrub_ctx *sctx)
>  		 */
>  		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);
>  	}
> @@ -2260,12 +2260,12 @@ leave_nomem:
>  	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);
> @@ -2672,11 +2672,11 @@ static void scrub_parity_bio_endio_worker(struct btrfs_work *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);
>  
> diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
> index fbe7c10..8f2ca18 100644
> --- a/fs/btrfs/volumes.c
> +++ b/fs/btrfs/volumes.c
> @@ -5741,23 +5741,23 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
>  	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;
> @@ -5795,17 +5795,16 @@ static void btrfs_end_bio(struct bio *bio, int err)
>  		 * 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);
>  	}
> @@ -5826,7 +5825,7 @@ static noinline void btrfs_schedule_bio(struct btrfs_root *root,
>  	struct btrfs_pending_bios *pending_bios;
>  
>  	if (device->missing || !device->bdev) {
> -		bio_endio(bio, -EIO);
> +		bio_io_error(bio);
>  		return;
>  	}
>  
> @@ -5973,8 +5972,8 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical)
>  
>  		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);
>  	}
>  }
>  
> diff --git a/fs/buffer.c b/fs/buffer.c
> index 1cf7a53..7a49bb8 100644
> --- a/fs/buffer.c
> +++ b/fs/buffer.c
> @@ -2957,14 +2957,14 @@ sector_t generic_block_bmap(struct address_space *mapping, sector_t block,
>  }
>  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);
>  }
>  
> diff --git a/fs/direct-io.c b/fs/direct-io.c
> index 745d234..e1639c8 100644
> --- a/fs/direct-io.c
> +++ b/fs/direct-io.c
> @@ -285,7 +285,7 @@ static int dio_bio_complete(struct dio *dio, struct bio *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;
> @@ -318,7 +318,7 @@ static void dio_bio_end_aio(struct bio *bio, int error)
>   * 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;
> @@ -345,9 +345,9 @@ void dio_end_io(struct bio *bio, int error)
>  	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);
>  
> @@ -457,11 +457,10 @@ static struct bio *dio_await_one(struct dio *dio)
>   */
>  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) {
> @@ -476,7 +475,7 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio)
>  		}
>  		bio_put(bio);
>  	}
> -	return uptodate ? 0 : -EIO;
> +	return bio->bi_error;
>  }
>  
>  /*
> diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
> index 5602450..aa95566 100644
> --- a/fs/ext4/page-io.c
> +++ b/fs/ext4/page-io.c
> @@ -61,7 +61,6 @@ static void buffer_io_error(struct buffer_head *bh)
>  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) {
> @@ -88,7 +87,7 @@ static void ext4_finish_bio(struct bio *bio)
>  		}
>  #endif
>  
> -		if (error) {
> +		if (bio->bi_error) {
>  			SetPageError(page);
>  			set_bit(AS_EIO, &page->mapping->flags);
>  		}
> @@ -107,7 +106,7 @@ static void ext4_finish_bio(struct bio *bio)
>  				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);
> @@ -310,27 +309,25 @@ ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end)
>  }
>  
>  /* 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) {
> diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
> index ec3ef93..5de5b87 100644
> --- a/fs/ext4/readpage.c
> +++ b/fs/ext4/readpage.c
> @@ -98,7 +98,7 @@ static inline bool ext4_bio_encrypted(struct bio *bio)
>   * 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;
> @@ -106,7 +106,7 @@ static void mpage_end_io(struct bio *bio, int err)
>  	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);
> @@ -118,7 +118,7 @@ static void mpage_end_io(struct bio *bio, int err)
>  	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);
> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> index 9bedfa8..8f0baa7 100644
> --- a/fs/f2fs/data.c
> +++ b/fs/f2fs/data.c
> @@ -29,13 +29,13 @@
>  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);
> @@ -46,7 +46,7 @@ static void f2fs_read_end_io(struct bio *bio, int err)
>  	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);
> @@ -57,7 +57,7 @@ static void f2fs_read_end_io(struct bio *bio, int err)
>  	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;
> @@ -68,7 +68,7 @@ static void f2fs_write_end_io(struct bio *bio, int err)
>  
>  		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);
> diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
> index 2c1ae86..c0a1b96 100644
> --- a/fs/gfs2/lops.c
> +++ b/fs/gfs2/lops.c
> @@ -202,22 +202,22 @@ static void gfs2_end_log_write_bh(struct gfs2_sbd *sdp, struct bio_vec *bvec,
>   *
>   */
>  
> -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);
>  	}
> diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
> index 1e3a93f..02586e7 100644
> --- a/fs/gfs2/ops_fstype.c
> +++ b/fs/gfs2/ops_fstype.c
> @@ -171,14 +171,14 @@ static int gfs2_check_sb(struct gfs2_sbd *sdp, int silent)
>  	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);
>  }
>  
> diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
> index bc462dc..d301acf 100644
> --- a/fs/jfs/jfs_logmgr.c
> +++ b/fs/jfs/jfs_logmgr.c
> @@ -2011,7 +2011,7 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp)
>  	/*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);
>  	}
> @@ -2158,7 +2158,7 @@ static void lbmStartIO(struct lbuf * bp)
>  	/* 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);
> @@ -2196,7 +2196,7 @@ static int lbmIOWait(struct lbuf * bp, int flag)
>   *
>   * 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;
> @@ -2212,7 +2212,7 @@ static void lbmIODone(struct bio *bio, int error)
>  
>  	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");
> diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
> index 16a0922..a3eb316 100644
> --- a/fs/jfs/jfs_metapage.c
> +++ b/fs/jfs/jfs_metapage.c
> @@ -276,11 +276,11 @@ static void last_read_complete(struct page *page)
>  	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);
>  	}
> @@ -331,13 +331,13 @@ static void last_write_complete(struct page *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);
>  	}
> diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c
> index 76279e1..cea0cc9 100644
> --- a/fs/logfs/dev_bdev.c
> +++ b/fs/logfs/dev_bdev.c
> @@ -53,16 +53,14 @@ static int bdev_readpage(void *_sb, struct page *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);
> @@ -153,14 +151,12 @@ static void bdev_writeseg(struct super_block *sb, u64 ofs, size_t len)
>  }
>  
>  
> -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))
> diff --git a/fs/mpage.c b/fs/mpage.c
> index ca0244b..abac936 100644
> --- a/fs/mpage.c
> +++ b/fs/mpage.c
> @@ -42,14 +42,14 @@
>   * 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);
> diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
> index d2554fe..9cd4eb3 100644
> --- a/fs/nfs/blocklayout/blocklayout.c
> +++ b/fs/nfs/blocklayout/blocklayout.c
> @@ -116,7 +116,7 @@ bl_submit_bio(int rw, struct bio *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;
>  
> @@ -139,8 +139,7 @@ bl_alloc_init_bio(int npg, struct block_device *bdev, sector_t disk_sector,
>  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 =
> @@ -183,11 +182,11 @@ retry:
>  	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)
> @@ -316,13 +315,12 @@ out:
>  	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);
> diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c
> index 42468e5..550b10e 100644
> --- a/fs/nilfs2/segbuf.c
> +++ b/fs/nilfs2/segbuf.c
> @@ -338,12 +338,11 @@ void nilfs_add_checksums_on_logs(struct list_head *logs, u32 seed)
>  /*
>   * 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);
> diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
> index 16eff45..140de3c 100644
> --- a/fs/ocfs2/cluster/heartbeat.c
> +++ b/fs/ocfs2/cluster/heartbeat.c
> @@ -372,14 +372,13 @@ static void o2hb_wait_on_io(struct o2hb_region *reg,
>  	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);
> diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
> index 3859f5e..3714844 100644
> --- a/fs/xfs/xfs_aops.c
> +++ b/fs/xfs/xfs_aops.c
> @@ -351,12 +351,11 @@ xfs_imap_valid(
>   */
>  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;
> diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
> index a4b7d92..01bd678 100644
> --- a/fs/xfs/xfs_buf.c
> +++ b/fs/xfs/xfs_buf.c
> @@ -1096,8 +1096,7 @@ xfs_bwrite(
>  
>  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;
>  
> @@ -1105,10 +1104,10 @@ xfs_buf_bio_end_io(
>  	 * 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);
>  	}
>  
> diff --git a/include/linux/bio.h b/include/linux/bio.h
> index 5e963a6..6b91817 100644
> --- a/include/linux/bio.h
> +++ b/include/linux/bio.h
> @@ -195,8 +195,6 @@ static inline bool bvec_gap_to_prev(struct bio_vec *bprv, unsigned int offset)
>  	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
> @@ -426,7 +424,14 @@ static inline struct bio *bio_clone_kmalloc(struct bio *bio, gfp_t gfp_mask)
>  
>  }
>  
> -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 *);
>  
> @@ -717,7 +722,7 @@ extern void bio_integrity_free(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);
> diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
> index 7303b34..6164fb8 100644
> --- a/include/linux/blk_types.h
> +++ b/include/linux/blk_types.h
> @@ -14,7 +14,7 @@ struct page;
>  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 *);
>  
>  /*
> @@ -53,6 +53,7 @@ struct bio {
>  
>  	struct bvec_iter	bi_iter;
>  
> +	int			bi_error;
>  	/* Number of segments in this BIO after
>  	 * physical address coalescing is performed.
>  	 */
> @@ -111,7 +112,6 @@ struct bio {
>  /*
>   * 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 */
> diff --git a/include/linux/swap.h b/include/linux/swap.h
> index 3887472..31496d2 100644
> --- a/include/linux/swap.h
> +++ b/include/linux/swap.h
> @@ -373,9 +373,9 @@ static inline void mem_cgroup_uncharge_swap(swp_entry_t entry)
>  /* 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,
> diff --git a/kernel/power/swap.c b/kernel/power/swap.c
> index 2f30ca9..b2066fb 100644
> --- a/kernel/power/swap.c
> +++ b/kernel/power/swap.c
> @@ -227,27 +227,23 @@ static void hib_init_batch(struct hib_bio_batch *hb)
>  	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);
>  
> diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
> index b3e6b39..90e72a0 100644
> --- a/kernel/trace/blktrace.c
> +++ b/kernel/trace/blktrace.c
> @@ -778,9 +778,6 @@ static void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
>  	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);
>  }
> @@ -887,8 +884,7 @@ static void blk_add_trace_split(void *ignore,
>  
>  		__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);
>  	}
>  }
>  
> @@ -920,8 +916,8 @@ static void blk_add_trace_bio_remap(void *ignore,
>  	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);
>  }
>  
>  /**
> diff --git a/mm/page_io.c b/mm/page_io.c
> index 520baa4..338ce68 100644
> --- a/mm/page_io.c
> +++ b/mm/page_io.c
> @@ -43,12 +43,11 @@ static struct bio *get_swap_bio(gfp_t gfp_flags,
>  	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.
> @@ -69,12 +68,11 @@ void end_swap_bio_write(struct bio *bio, int err)
>  	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",
> @@ -254,7 +252,7 @@ static sector_t swap_page_sector(struct page *page)
>  }
>  
>  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;
> -- 
> 1.9.1
> 

--
dm-devel mailing list
dm-devel@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/dm-devel




[Index of Archives]     [DM Crypt]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Packaging]     [Fedora SELinux]     [Yosemite Discussion]     [KDE Users]     [Fedora Docs]

  Powered by Linux