The current -Exyz errors are not descriptive enough to allow upper layers like DM and MD to decide how to handle IO errors. In many cases all we get is a -EIO. The following path introduces BLK* error values for use with the bio_endio and end_that_request* functions (end_request keeps uptodate). I converted all the users in this patch except scsi and dm. Those will be in the next patches. This patch will break all out of tree drivers. I was not sure if it was better to start clean or keep support for 1, 0, Exyz and whatever else some drivers were sending sometimes. If you want I can just redefine the BLKERR values to fit into the existing tests then have driver like dm-multipath check for both BLKERR and -Exyz errors. This is just a RFC and it has actually been sent to lkml in the past so since I really want to make sure it will work for SCSI amd dm-multipath I am just sending it here. I will break this patch up and send it to lkml and the maintainers of these drivers in the future. Signed-off-by: Mike Christie <michaelc@xxxxxxxxxxx> diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -3471,9 +3471,9 @@ static inline boolean DAC960_ProcessComp struct request *Request = Command->Request; int UpToDate; - UpToDate = 0; + UpToDate = BLKERR_IO; if (SuccessfulIO) - UpToDate = 1; + UpToDate = BLK_SUCCESS; pci_unmap_sg(Command->Controller->PCIDevice, Command->cmd_sglist, Command->SegmentCount, Command->DmaDirection); diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -133,7 +133,7 @@ aoeblk_make_request(request_queue_t *q, if (buf == NULL) { printk(KERN_INFO "aoe: aoeblk_make_request: buf allocation " "failure\n"); - bio_endio(bio, bio->bi_size, -ENOMEM); + bio_endio(bio, bio->bi_size, BLKERR_RETRY_DRV); return 0; } memset(buf, 0, sizeof(*buf)); @@ -153,7 +153,7 @@ aoeblk_make_request(request_queue_t *q, d->aoemajor, d->aoeminor); spin_unlock_irqrestore(&d->lock, flags); mempool_free(buf, d->bufpool); - bio_endio(bio, bio->bi_size, -ENXIO); + bio_endio(bio, bio->bi_size, BLKERR_FATAL_DEV); return 0; } diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -478,7 +478,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) disk_stat_add(disk, read_sectors, n_sect); } disk_stat_add(disk, io_ticks, duration); - n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; + n = (buf->flags & BUFFL_FAIL) ? BLKERR_IO : BLK_SUCCESS; bio_endio(buf->bio, buf->bio->bi_size, n); mempool_free(buf, d->bufpool); } diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -79,7 +79,7 @@ aoedev_downdev(struct aoedev *d) bio = buf->bio; if (--buf->nframesout == 0) { mempool_free(buf, d->bufpool); - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, bio->bi_size, BLKERR_IO); } } d->inprocess = NULL; @@ -89,7 +89,7 @@ aoedev_downdev(struct aoedev *d) list_del(d->bufq.next); bio = buf->bio; mempool_free(buf, d->bufpool); - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, bio->bi_size, BLKERR_IO); } if (d->nopen) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1913,7 +1913,8 @@ static inline void complete_buffers(stru bio->bi_next = NULL; blk_finished_io(len); - bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); + bio_endio(bio, nr_sectors << 9, + status ? BLK_SUCCESS : BLKERR_IO); bio = xbh; } diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -992,7 +992,7 @@ static inline void complete_buffers(stru bio->bi_next = NULL; blk_finished_io(nr_sectors); - bio_endio(bio, nr_sectors << 9, ok ? 0 : -EIO); + bio_endio(bio, nr_sectors << 9, ok ? BLK_SUCCESS : BLKERR_IO); bio = xbh; } diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -404,7 +404,7 @@ struct request *elv_next_request(request blkdev_dequeue_request(rq); rq->flags |= REQ_QUIET; - end_that_request_chunk(rq, 0, nr_bytes); + end_that_request_chunk(rq, BLKERR_IO, nr_bytes); end_that_request_last(rq); } else { printk(KERN_ERR "%s: bad return=%d\n", __FUNCTION__, diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2290,11 +2290,14 @@ static int do_format(int drive, struct f static void floppy_end_request(struct request *req, int uptodate) { unsigned int nr_sectors = current_count_sectors; + int err = BLK_SUCCESS; /* current_count_sectors can be zero if transfer failed */ - if (!uptodate) + if (!uptodate) { + err = BLKERR_IO; nr_sectors = req->current_nr_sectors; - if (end_that_request_first(req, uptodate, nr_sectors)) + } + if (end_that_request_first(req, err, nr_sectors)) return; add_disk_randomness(req->rq_disk); floppy_off((long)req->rq_disk->private_data); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -2551,7 +2551,7 @@ static int __make_request(request_queue_ barrier = bio_barrier(bio); if (unlikely(barrier) && (q->ordered == QUEUE_ORDERED_NONE)) { - err = -EOPNOTSUPP; + err = BLKERR_NOTSUPP; goto end_io; } @@ -2860,7 +2860,7 @@ void generic_make_request(struct bio *bi bdevname(bio->bi_bdev, b), (long long) bio->bi_sector); end_io: - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, bio->bi_size, BLKERR_IO); break; } @@ -2996,29 +2996,23 @@ static void blk_recalc_rq_sectors(struct } } -static int __end_that_request_first(struct request *req, int uptodate, +static int __end_that_request_first(struct request *req, int error, int nr_bytes) { - int total_bytes, bio_nbytes, error, next_idx = 0; + int total_bytes, bio_nbytes, next_idx = 0; struct bio *bio; /* - * extend uptodate bool to allow < 0 value to be direct io error - */ - error = 0; - if (end_io_error(uptodate)) - error = !uptodate ? -EIO : uptodate; - - /* * for a REQ_BLOCK_PC request, we want to carry any eventual * sense key with us all the way through */ if (!blk_pc_request(req)) req->errors = 0; - if (!uptodate) { + if (error != BLK_SUCCESS) { if (blk_fs_request(req) && !(req->flags & REQ_QUIET)) - printk("end_request: I/O error, dev %s, sector %llu\n", + printk("end_request: I/O error %d, dev %s, sector " + "%llu\n", error, req->rq_disk ? req->rq_disk->disk_name : "?", (unsigned long long)req->sector); } @@ -3099,7 +3093,7 @@ static int __end_that_request_first(stru /** * end_that_request_first - end I/O on a request * @req: the request being processed - * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error + * @uptodate: a block layer error value * @nr_sectors: number of sectors to end I/O on * * Description: @@ -3120,7 +3114,7 @@ EXPORT_SYMBOL(end_that_request_first); /** * end_that_request_chunk - end I/O on a request * @req: the request being processed - * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error + * @uptodate: a block layer error value * @nr_bytes: number of bytes to complete * * Description: @@ -3174,7 +3168,9 @@ EXPORT_SYMBOL(end_that_request_last); void end_request(struct request *req, int uptodate) { - if (!end_that_request_first(req, uptodate, req->hard_cur_sectors)) { + int err = uptodate ? BLK_SUCCESS : BLKERR_IO; + + if (!end_that_request_first(req, err, req->hard_cur_sectors)) { add_disk_randomness(req->rq_disk); blkdev_dequeue_request(req); end_that_request_last(req); diff --git a/drivers/block/loop.c b/drivers/block/loop.c --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -549,7 +549,7 @@ static inline void loop_handle_bio(struc do_loop_switch(lo, bio->bi_private); bio_put(bio); } else { - int ret = do_bio_filebacked(lo, bio); + int ret = do_bio_filebacked(lo, bio) ? BLKERR_IO : BLK_SUCCESS; bio_endio(bio, bio->bi_size, ret); } } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -127,15 +127,15 @@ static const char *nbdcmd_to_ascii(int c static void nbd_end_request(struct request *req) { - int uptodate = (req->errors == 0) ? 1 : 0; + int err = (req->errors == 0) ? BLK_SUCCESS : BLKERR_IO; request_queue_t *q = req->q; unsigned long flags; dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name, - req, uptodate? "done": "failed"); + req, err == BLK_SUCCESS ? "done": "failed"); spin_lock_irqsave(q->queue_lock, flags); - if (!end_that_request_first(req, uptodate, req->nr_sectors)) { + if (!end_that_request_first(req, err, req->nr_sectors)) { end_that_request_last(req); } spin_unlock_irqrestore(q->queue_lock, flags); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -678,7 +678,7 @@ static int pkt_end_io_read(struct bio *b VPRINTK("pkt_end_io_read: bio=%p sec0=%llx sec=%llx err=%d\n", bio, (unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err); - if (err) + if (err != BLK_SUCCESS) atomic_inc(&pkt->io_errors); if (atomic_dec_and_test(&pkt->io_wait)) { atomic_inc(&pkt->run_sm); @@ -1049,7 +1049,6 @@ static void pkt_start_write(struct pktcd pkt->w_bio->bi_max_vecs = PACKET_MAX_SIZE; pkt->w_bio->bi_sector = pkt->sector; pkt->w_bio->bi_bdev = pd->bdev; - pkt->w_bio->bi_end_io = pkt_end_io_packet_write; pkt->w_bio->bi_private = pkt; for (f = 0; f < pkt->frames; f++) { if ((f + 1 < pkt->frames) && (pages[f + 1] == pages[f]) && @@ -1081,7 +1080,8 @@ static void pkt_finish_packet(struct pac while (bio) { next = bio->bi_next; bio->bi_next = NULL; - bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO); + bio_endio(bio, bio->bi_size, + uptodate ? BLK_SUCCESS : BLKERR_IO); bio = next; } pkt->orig_bios = pkt->orig_bios_tail = NULL; diff --git a/drivers/block/rd.c b/drivers/block/rd.c --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -288,7 +288,7 @@ static int rd_make_request(request_queue if (ret) goto fail; - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, bio->bi_size, BLK_SUCCESS); return 0; fail: bio_io_error(bio, bio->bi_size); diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -790,7 +790,7 @@ static inline void carm_round_robin(stru static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq, int is_ok) { - carm_end_request_queued(host, crq, is_ok); + carm_end_request_queued(host, crq, is_ok ? BLK_SUCCESS : BLKERR_IO); if (CARM_MAX_Q == 1) carm_round_robin(host); else if ((host->n_msgs <= CARM_MSG_LOW_WATER) && diff --git a/drivers/block/ub.c b/drivers/block/ub.c --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -765,7 +765,7 @@ static int ub_bd_rq_fn_1(struct ub_lun * if (atomic_read(&sc->poison) || lun->changed) { blkdev_dequeue_request(rq); - ub_end_rq(rq, 0); + ub_end_rq(rq, BLKERR_IO); return 0; } @@ -782,7 +782,7 @@ static int ub_bd_rq_fn_1(struct ub_lun * } if (rc != 0) { ub_put_cmd(lun, cmd); - ub_end_rq(rq, 0); + ub_end_rq(rq, BLKERR_IO); return 0; } cmd->state = UB_CMDST_INIT; @@ -793,7 +793,7 @@ static int ub_bd_rq_fn_1(struct ub_lun * cmd->tag = sc->tagcnt++; if ((rc = ub_submit_scsi(sc, cmd)) != 0) { ub_put_cmd(lun, cmd); - ub_end_rq(rq, 0); + ub_end_rq(rq, BLKERR_IO); return 0; } @@ -823,7 +823,7 @@ static int ub_cmd_build_block(struct ub_ n_elem = blk_rq_map_sg(q, rq, sg); if (n_elem <= 0) { ub_put_cmd(lun, cmd); - ub_end_rq(rq, 0); + ub_end_rq(rq, BLKERR_IO); blk_start_queue(q); return 0; /* request with no s/g entries? */ } @@ -832,7 +832,7 @@ static int ub_cmd_build_block(struct ub_ printk(KERN_WARNING "%s: request with %d segments\n", sc->name, n_elem); ub_put_cmd(lun, cmd); - ub_end_rq(rq, 0); + ub_end_rq(rq, BLKERR_IO); blk_start_queue(q); return 0; } @@ -930,9 +930,9 @@ static void ub_rw_cmd_done(struct ub_dev } if (cmd->error == 0) - uptodate = 1; + uptodate = BLK_SUCCESS; else - uptodate = 0; + uptodate = BLKERR_IO; ub_put_cmd(lun, cmd); ub_end_rq(rq, uptodate); diff --git a/drivers/block/umem.c b/drivers/block/umem.c --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -543,7 +543,7 @@ static void process_page(unsigned long d return_bio = bio->bi_next; bio->bi_next = NULL; - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, bio->bi_size, BLK_SUCCESS); } } diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -445,12 +445,14 @@ static void do_viodasd_request(request_q blkdev_dequeue_request(req); /* check that request contains a valid command */ if (!blk_fs_request(req)) { - viodasd_end_request(req, 0, req->hard_nr_sectors); + viodasd_end_request(req, BLKERR_IO, + req->hard_nr_sectors); continue; } /* Try sending the request */ if (send_request(req) != 0) - viodasd_end_request(req, 0, req->hard_nr_sectors); + viodasd_end_request(req, BLKERR_IO, + req->hard_nr_sectors); } } @@ -656,7 +658,7 @@ static int viodasd_handle_read_write(str } qlock = req->q->queue_lock; spin_lock_irqsave(qlock, irq_flags); - viodasd_end_request(req, !error, num_sect); + viodasd_end_request(req, error ? BLKERR_IO : BLK_SUCCESS, num_sect); spin_unlock_irqrestore(qlock, irq_flags); /* Finally, try to get more requests off of this device's queue */ diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -1399,7 +1399,7 @@ static void do_cdu31a_request(request_qu read_data_block(req->buffer, block, nblock, res_reg, &res_size); if (res_reg[0] != 0x20) { - if (!end_that_request_first(req, 1, nblock)) { + if (!end_that_request_first(req, BLK_SUCCESS, nblock)) { spin_lock_irq(q->queue_lock); blkdev_dequeue_request(req); end_that_request_last(req); diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -613,7 +613,8 @@ static void cdrom_end_request (ide_drive * now end failed request */ spin_lock_irqsave(&ide_lock, flags); - end_that_request_chunk(failed, 0, failed->data_len); + end_that_request_chunk(failed, BLKERR_IO, + failed->data_len); end_that_request_last(failed); spin_unlock_irqrestore(&ide_lock, flags); } @@ -1636,7 +1637,7 @@ static ide_startstop_t cdrom_newpc_intr( return ide_error(drive, "dma error", stat); } - end_that_request_chunk(rq, 1, rq->data_len); + end_that_request_chunk(rq, BLK_SUCCESS, rq->data_len); rq->data_len = 0; goto end_request; } @@ -1710,7 +1711,7 @@ static ide_startstop_t cdrom_newpc_intr( rq->data_len -= blen; if (rq->bio) - end_that_request_chunk(rq, 1, blen); + end_that_request_chunk(rq, BLK_SUCCESS, blen); else rq->data += blen; } diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -58,6 +58,7 @@ int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate, int nr_sectors) { + int err = uptodate ? BLK_SUCCESS : BLKERR_IO; int ret = 1; BUG_ON(!(rq->flags & REQ_STARTED)); @@ -66,10 +67,10 @@ int __ide_end_request(ide_drive_t *drive * if failfast is set on a request, override number of sectors and * complete the whole request right now */ - if (blk_noretry_request(rq) && end_io_error(uptodate)) + if (blk_noretry_request(rq) && err != BLK_SUCCESS) nr_sectors = rq->hard_nr_sectors; - if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors) + if (!blk_fs_request(rq) && (err != BLK_SUCCESS) && !rq->errors) rq->errors = -EIO; /* @@ -81,7 +82,7 @@ int __ide_end_request(ide_drive_t *drive HWGROUP(drive)->hwif->ide_dma_on(drive); } - if (!end_that_request_first(rq, uptodate, nr_sectors)) { + if (!end_that_request_first(rq, err, nr_sectors)) { add_disk_randomness(rq->rq_disk); if (blk_rq_tagged(rq)) diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -76,7 +76,7 @@ static int faulty_fail(struct bio *bio, bio_put(bio); clear_bit(BIO_UPTODATE, &b->bi_flags); - return (b->bi_end_io)(b, bytes_done, -EIO); + return (b->bi_end_io)(b, bytes_done, BLKERR_IO); } typedef struct faulty_conf { @@ -179,7 +179,7 @@ static int make_request(request_queue_t /* special case - don't decrement, don't generic_make_request, * just fail immediately */ - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, bio->bi_size, BLKERR_IO); return 0; } diff --git a/drivers/md/md.c b/drivers/md/md.c --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -333,7 +333,7 @@ static int super_written(struct bio *bio if (bio->bi_size) return 1; - if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) + if (error != BLK_SUCCESS || !test_bit(BIO_UPTODATE, &bio->bi_flags)) md_error(rdev->mddev, rdev); if (atomic_dec_and_test(&rdev->mddev->pending_writes)) diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -115,7 +115,7 @@ static int multipath_end_request(struct return 1; if (uptodate) - multipath_end_bh_io(mp_bh, 0); + multipath_end_bh_io(mp_bh, BLK_SUCCESS); else if (!bio_rw_ahead(bio)) { /* * oops, IO error: @@ -184,7 +184,7 @@ static int multipath_make_request (reque mp_bh->path = multipath_map(conf); if (mp_bh->path < 0) { - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, bio->bi_size, BLKERR_IO); mempool_free(mp_bh, conf->pool); return 0; } @@ -405,7 +405,7 @@ static void multipathd (mddev_t *mddev) " error for block %llu\n", bdevname(bio->bi_bdev,b), (unsigned long long)bio->bi_sector); - multipath_end_bh_io(mp_bh, -EIO); + multipath_end_bh_io(mp_bh, BLKERR_IO); } else { printk(KERN_ERR "multipath: %s: redirecting sector %llu" " to another IO path\n", diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -223,7 +223,7 @@ static void raid_end_bio_io(r1bio_t *r1_ struct bio *bio = r1_bio->master_bio; bio_endio(bio, bio->bi_size, - test_bit(R1BIO_Uptodate, &r1_bio->state) ? 0 : -EIO); + test_bit(R1BIO_Uptodate, &r1_bio->state) ? BLK_SUCCESS : BLKERR_IO); free_r1bio(r1_bio); } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -238,7 +238,7 @@ static void raid_end_bio_io(r10bio_t *r1 struct bio *bio = r10_bio->master_bio; bio_endio(bio, bio->bi_size, - test_bit(R10BIO_Uptodate, &r10_bio->state) ? 0 : -EIO); + test_bit(R10BIO_Uptodate, &r10_bio->state) ? BLK_SUCCESS : BLKERR_IO); free_r10bio(r10_bio); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1249,7 +1249,7 @@ static void handle_stripe(struct stripe_ return_bi = bi->bi_next; bi->bi_next = NULL; bi->bi_size = 0; - bi->bi_end_io(bi, bytes, 0); + bi->bi_end_io(bi, bytes, BLK_SUCCESS); } for (i=disks; i-- ;) { int rw; @@ -1469,7 +1469,7 @@ static int make_request (request_queue_t if ( bio_data_dir(bi) == WRITE ) md_write_end(mddev); bi->bi_size = 0; - bi->bi_end_io(bi, bytes, 0); + bi->bi_end_io(bi, bytes, BLK_SUCCESS); } spin_unlock_irq(&conf->device_lock); return 0; diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -1408,7 +1408,7 @@ static void handle_stripe(struct stripe_ return_bi = bi->bi_next; bi->bi_next = NULL; bi->bi_size = 0; - bi->bi_end_io(bi, bytes, 0); + bi->bi_end_io(bi, bytes, BLK_SUCCESS); } for (i=disks; i-- ;) { int rw; @@ -1628,7 +1628,7 @@ static int make_request (request_queue_t if ( bio_data_dir(bi) == WRITE ) md_write_end(mddev); bi->bi_size = 0; - bi->bi_end_io(bi, bytes, 0); + bi->bi_end_io(bi, bytes, BLK_SUCCESS); } spin_unlock_irq(&conf->device_lock); return 0; diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -438,7 +438,7 @@ static void i2o_block_delayed_request_fn /** * i2o_block_end_request - Post-processing of completed commands * @req: request which should be completed - * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error + * @uptodate: A BLKERR_* value or BLK_SUCCESS * @nr_bytes: number of bytes to complete * * Mark the request as complete. The lock must not be held when entering. @@ -458,8 +458,8 @@ static void i2o_block_end_request(struct if (blk_pc_request(req)) leftover = req->data_len; - if (end_io_error(uptodate)) - end_that_request_chunk(req, 0, leftover); + if (uptodate != BLK_SUCCESS) + end_that_request_chunk(req, uptodate, leftover); } add_disk_randomness(req->rq_disk); @@ -494,7 +494,7 @@ static int i2o_block_reply(struct i2o_co struct i2o_message *msg) { struct request *req; - int uptodate = 1; + int uptodate = BLK_SUCCESS; req = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt)); if (unlikely(!req)) { @@ -527,7 +527,7 @@ static int i2o_block_reply(struct i2o_co req->errors++; - uptodate = 0; + uptodate = BLKERR_IO; } i2o_block_end_request(req, uptodate, le32_to_cpu(msg->body[1])); diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -247,7 +247,8 @@ static int mmc_blk_issue_rq(struct mmc_q * A block was successfully transferred. */ spin_lock_irq(&md->lock); - ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); + ret = end_that_request_chunk(req, BLK_SUCCESS, + brq.data.bytes_xfered); if (!ret) { /* * The whole request completed successfully. @@ -274,7 +275,7 @@ static int mmc_blk_issue_rq(struct mmc_q */ spin_lock_irq(&md->lock); do { - ret = end_that_request_chunk(req, 0, + ret = end_that_request_chunk(req, BLKERR_IO, req->current_nr_sectors << 9); } while (ret); diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1036,7 +1036,9 @@ dasd_int_handler(struct ccw_device *cdev static inline void dasd_end_request(struct request *req, int uptodate) { - if (end_that_request_first(req, uptodate, req->hard_nr_sectors)) + int err = !uptodate ? BLKERR_IO : BLK_SUCCESS; + + if (end_that_request_first(req, err, req->hard_nr_sectors)) BUG(); add_disk_randomness(req->rq_disk); end_that_request_last(req); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -675,7 +675,7 @@ dcssblk_make_request(request_queue_t *q, } bytes_done += bvec->bv_len; } - bio_endio(bio, bytes_done, 0); + bio_endio(bio, bytes_done, BLK_SUCCESS); return 0; fail: bio_io_error(bio, bio->bi_size); diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -321,7 +321,7 @@ static int xpram_make_request(request_qu set_bit(BIO_UPTODATE, &bio->bi_flags); bytes = bio->bi_size; bio->bi_size = 0; - bio->bi_end_io(bio, bytes, 0); + bio->bi_end_io(bio, bytes, BLK_SUCCESS); return 0; fail: bio_io_error(bio, bio->bi_size); diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -91,7 +91,7 @@ __tapeblock_end_request(struct tape_requ device = ccw_req->device; req = (struct request *) data; - tapeblock_end_request(req, ccw_req->rc == 0); + tapeblock_end_request(req, ccw_req->rc == 0 ? BLK_SUCCESS : BLKERR_IO); if (ccw_req->rc == 0) /* Update position. */ device->blk_data.block_position = @@ -119,7 +119,7 @@ tapeblock_start_request(struct tape_devi ccw_req = device->discipline->bread(device, req); if (IS_ERR(ccw_req)) { DBF_EVENT(1, "TBLOCK: bread failed\n"); - tapeblock_end_request(req, 0); + tapeblock_end_request(req, BLKERR_IO); return PTR_ERR(ccw_req); } ccw_req->callback = __tapeblock_end_request; @@ -132,7 +132,7 @@ tapeblock_start_request(struct tape_devi * Start/enqueueing failed. No retries in * this case. */ - tapeblock_end_request(req, 0); + tapeblock_end_request(req, BLKERR_IO); device->discipline->free_bread(ccw_req); } @@ -175,7 +175,7 @@ tapeblock_requeue(void *data) { if (rq_data_dir(req) == WRITE) { DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); blkdev_dequeue_request(req); - tapeblock_end_request(req, 0); + tapeblock_end_request(req, BLKERR_IO); continue; } spin_unlock_irq(&device->blk_data.request_queue_lock); diff --git a/fs/bio.c b/fs/bio.c --- a/fs/bio.c +++ b/fs/bio.c @@ -664,7 +664,7 @@ struct bio *bio_map_user(request_queue_t /* * don't support partial mappings */ - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, bio->bi_size, BLK_SUCCESS); bio_unmap_user(bio); return ERR_PTR(-EINVAL); } @@ -837,14 +837,13 @@ void bio_check_pages_dirty(struct bio *b * bio_endio() will end I/O on @bytes_done number of bytes. This may be * just a partial part of the bio, or it may be the whole bio. bio_endio() * is the preferred way to end I/O on a bio, it takes care of decrementing - * bi_size and 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. Noone should call bi_end_io() directly on + * bi_size and clearing BIO_UPTODATE on error. @error is a block layer error + * value defined in blkdev.h. Noone 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, unsigned int bytes_done, int error) { - if (error) + if (error != BLK_SUCCESS) clear_bit(BIO_UPTODATE, &bio->bi_flags); if (unlikely(bytes_done > bio->bi_size)) { @@ -874,7 +873,7 @@ static int bio_pair_end_1(struct bio * b { struct bio_pair *bp = container_of(bi, struct bio_pair, bio1); - if (err) + if (err != BLK_SUCCESS) bp->error = err; if (bi->bi_size) @@ -888,7 +887,7 @@ static int bio_pair_end_2(struct bio * b { struct bio_pair *bp = container_of(bi, struct bio_pair, bio2); - if (err) + if (err != BLK_SUCCESS) bp->error = err; if (bi->bi_size) @@ -912,7 +911,7 @@ struct bio_pair *bio_split(struct bio *b BUG_ON(bi->bi_vcnt != 1); BUG_ON(bi->bi_idx != 0); atomic_set(&bp->cnt, 3); - bp->error = 0; + bp->error = BLK_SUCCESS; bp->bio1 = *bi; bp->bio2 = *bi; bp->bio2.bi_sector += first_sectors; diff --git a/fs/buffer.c b/fs/buffer.c --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2733,7 +2733,7 @@ static int end_bio_bh_io_sync(struct bio if (bio->bi_size) return 1; - if (err == -EOPNOTSUPP) { + if (err == BLKERR_NOTSUPP) { set_bit(BIO_EOPNOTSUPP, &bio->bi_flags); set_bit(BH_Eopnotsupp, &bh->b_state); } diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -2157,7 +2157,7 @@ static void lbmStartIO(struct lbuf * bp) /* check if journaling to disk has been disabled */ if (log->no_integrity) { bio->bi_size = 0; - lbmIODone(bio, 0, 0); + lbmIODone(bio, 0, BLKERR_IO); } else { submit_bio(WRITE_SYNC, bio); INCREMENT(lmStat.submitted); diff --git a/include/linux/bio.h b/include/linux/bio.h --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -222,7 +222,7 @@ struct bio { #define BIO_SEG_BOUNDARY(q, b1, b2) \ BIOVEC_SEG_BOUNDARY((q), __BVEC_END((b1)), __BVEC_START((b2))) -#define bio_io_error(bio, bytes) bio_endio((bio), (bytes), -EIO) +#define bio_io_error(bio, bytes) bio_endio((bio), (bytes), BLKERR_IO) /* * drivers should not use the __ version unless they _really_ want to diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -599,12 +599,21 @@ extern void end_that_request_last(struct extern void end_request(struct request *req, int uptodate); /* - * end_that_request_first/chunk() takes an uptodate argument. we account - * any value <= as an io error. 0 means -EIO for compatability reasons, - * any other < 0 value is the direct error type. An uptodate value of - * 1 indicates successful io completion + * Error values that users of end_that_request_first/chunk, + * bio_endio/bi_end_io should use to indicate I/O completion status. */ -#define end_io_error(uptodate) (unlikely((uptodate) <= 0)) +enum { + BLK_SUCCESS = 0, /* Must be zero for compat with old usage */ + BLKERR_IO, /* Generic I/O error */ + BLKERR_NOTSUPP, /* Operation is not supported */ + BLKERR_WOULDBLOCK, /* Operation would block */ + BLKERR_FATAL_DRV, /* Fatal driver error */ + BLKERR_FATAL_DEV, /* Fatal device error */ + BLKERR_FATAL_XPT, /* Fatal transport error */ + BLKERR_RETRY_DRV, /* Driver error, I/O may be retried */ + BLKERR_RETRY_DEV, /* Device error, I/O may be retried */ + BLKERR_RETRY_XPT, /* Transport error, I/O may retried */ +}; static inline void blkdev_dequeue_request(struct request *req) { - : send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html