Skip to content

Commit

Permalink
block: add a bi_error field to struct bio
Browse files Browse the repository at this point in the history
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.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: NeilBrown <neilb@suse.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
  • Loading branch information
Christoph Hellwig authored and axboe committed Jul 29, 2015
1 parent 0034af0 commit 4246a0b
Show file tree
Hide file tree
Showing 95 changed files with 622 additions and 682 deletions.
2 changes: 1 addition & 1 deletion Documentation/block/biodoc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion arch/m68k/emu/nfblock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/sysdev/axonram.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand Down
12 changes: 3 additions & 9 deletions arch/xtensa/platforms/iss/simdisk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
11 changes: 5 additions & 6 deletions block/bio-integrity.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand All @@ -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);

Expand All @@ -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;
}
Expand Down
43 changes: 18 additions & 25 deletions block/bio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}

/**
Expand Down Expand Up @@ -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;

Expand All @@ -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;
}
}
Expand Down
15 changes: 8 additions & 7 deletions block/blk-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -1673,7 +1672,8 @@ static void blk_queue_bio(struct request_queue *q, struct bio *bio)
*/
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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
30 changes: 13 additions & 17 deletions block/blk-lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion block/blk-map.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
6 changes: 3 additions & 3 deletions block/blk-mq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
Loading

0 comments on commit 4246a0b

Please sign in to comment.