# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.569 -> 1.570 # drivers/block/ll_rw_blk.c 1.103 -> 1.104 # mm/page_io.c 1.24 -> 1.25 # drivers/block/cpqarray.c 1.52 -> 1.53 # drivers/block/floppy.c 1.39 -> 1.40 # fs/mpage.c 1.18 -> 1.19 # fs/buffer.c 1.148 -> 1.149 # fs/direct-io.c 1.6 -> 1.7 # drivers/block/loop.c 1.55 -> 1.56 # fs/bio.c 1.24 -> 1.25 # drivers/block/rd.c 1.46 -> 1.47 # mm/highmem.c 1.31 -> 1.32 # include/linux/bio.h 1.19 -> 1.20 # drivers/block/cciss.c 1.55 -> 1.56 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/09/18 axboe@burns.home.kernel.dk 1.570 # Make bio->bi_end_io() take nr_bytes and actual error as argument. # This enables partial completion of bio's, which is important for # latency reasons (bio can be huge, for slow media we want page-by-page # completions). # -------------------------------------------- # diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c --- a/drivers/block/cciss.c Wed Sep 18 15:55:16 2002 +++ b/drivers/block/cciss.c Wed Sep 18 15:55:16 2002 @@ -1567,10 +1567,11 @@ { while (bio) { struct bio *xbh = bio->bi_next; + int nr_sectors = bio_sectors(bio); bio->bi_next = NULL; - blk_finished_io(bio_sectors(bio)); - bio_endio(bio, status); + blk_finished_io(len); + bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); bio = xbh; } diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c --- a/drivers/block/cpqarray.c Wed Sep 18 15:55:16 2002 +++ b/drivers/block/cpqarray.c Wed Sep 18 15:55:16 2002 @@ -911,11 +911,13 @@ { struct bio *xbh; while(bio) { + int nr_sectors = bio_sectors(bio); + xbh = bio->bi_next; bio->bi_next = NULL; - blk_finished_io(bio_sectors(bio)); - bio_endio(bio, ok); + blk_finished_io(nr_sectors); + bio_endio(bio, nr_sectors << 9, ok ? 0 : -EIO); bio = xbh; } diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c --- a/drivers/block/floppy.c Wed Sep 18 15:55:16 2002 +++ b/drivers/block/floppy.c Wed Sep 18 15:55:16 2002 @@ -3846,9 +3846,13 @@ * a disk in the drive, and whether that disk is writable. */ -static void floppy_rb0_complete(struct bio *bio) +static int floppy_rb0_complete(struct bio *bio, unsigned int bytes_done, int err) { + if (bio->bi_size) + return 1; + complete((struct completion*)bio->bi_private); + return 0; } static int __floppy_read_block_0(struct block_device *bdev) diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c Wed Sep 18 15:55:16 2002 +++ b/drivers/block/ll_rw_blk.c Wed Sep 18 15:55:16 2002 @@ -1576,10 +1576,8 @@ /* * READA bit set */ - if (bio->bi_rw & (1 << BIO_RW_AHEAD)) { - set_bit(BIO_RW_BLOCK, &bio->bi_flags); + if (bio_flagged(bio, BIO_RW_AHEAD)) goto end_io; - } freereq = get_request_wait(q, rw); spin_lock_irq(q->queue_lock); @@ -1616,7 +1614,7 @@ return 0; end_io: - bio->bi_end_io(bio); + bio_endio(bio, nr_sectors << 9, -EWOULDBLOCK); return 0; } @@ -1705,7 +1703,7 @@ bdevname(bio->bi_bdev), (long long) bio->bi_sector); end_io: - bio->bi_end_io(bio); + bio_endio(bio, 0, -EIO); break; } @@ -1825,6 +1823,7 @@ total_nsect = 0; while ((bio = req->bio)) { nsect = bio_iovec(bio)->bv_len >> 9; + total_nsect += nsect; BIO_BUG_ON(bio_iovec(bio)->bv_len > bio->bi_size); @@ -1834,38 +1833,31 @@ if (unlikely(nsect > nr_sectors)) { int partial = nr_sectors << 9; - bio->bi_size -= partial; bio_iovec(bio)->bv_offset += partial; bio_iovec(bio)->bv_len -= partial; - blk_recalc_rq_sectors(req, nr_sectors); + blk_recalc_rq_sectors(req, total_nsect); blk_recalc_rq_segments(req); + bio_endio(bio, partial, !uptodate ? -EIO : 0); return 1; } /* - * account transfer + * if bio->bi_end_io returns 0, this bio is done. move on */ - bio->bi_size -= bio_iovec(bio)->bv_len; - bio->bi_idx++; + req->bio = bio->bi_next; + if (bio_endio(bio, nsect << 9, !uptodate ? -EIO : 0)) { + bio->bi_idx++; + req->bio = bio; + } nr_sectors -= nsect; - total_nsect += nsect; - - if (!bio->bi_size) { - req->bio = bio->bi_next; - - bio_endio(bio, uptodate); - - total_nsect = 0; - } if ((bio = req->bio)) { - blk_recalc_rq_sectors(req, nsect); - /* * end more in this run, or just return 'not-done' */ if (unlikely(nr_sectors <= 0)) { + blk_recalc_rq_sectors(req, total_nsect); blk_recalc_rq_segments(req); return 1; } diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c --- a/drivers/block/loop.c Wed Sep 18 15:55:16 2002 +++ b/drivers/block/loop.c Wed Sep 18 15:55:16 2002 @@ -374,7 +374,7 @@ return ret; } -static void loop_end_io_transfer(struct bio *); +static int loop_end_io_transfer(struct bio *, unsigned int, int); static void loop_put_buffer(struct bio *bio) { /* @@ -382,6 +382,7 @@ */ if (bio && bio->bi_end_io == loop_end_io_transfer) { int i; + for (i = 0; i < bio->bi_vcnt; i++) __free_page(bio->bi_io_vec[i].bv_page); @@ -432,19 +433,23 @@ * bi_end_io context (we don't want to do decrypt of a page with irqs * disabled) */ -static void loop_end_io_transfer(struct bio *bio) +static int loop_end_io_transfer(struct bio *bio, unsigned int bytes_done, int err) { struct bio *rbh = bio->bi_private; struct loop_device *lo = &loop_dev[minor(to_kdev_t(rbh->bi_bdev->bd_dev))]; - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); - if (!uptodate || bio_rw(bio) == WRITE) { - bio_endio(rbh, uptodate); + if (bio->bi_size) + return 1; + + if (!err || bio_rw(bio) == WRITE) { + bio_endio(rbh, rbh->bi_size, err); if (atomic_dec_and_test(&lo->lo_pending)) up(&lo->lo_bh_mutex); loop_put_buffer(bio); } else loop_add_bio(lo, bio); + + return 0; } static struct bio *loop_get_buffer(struct loop_device *lo, struct bio *rbh) @@ -553,7 +558,7 @@ up(&lo->lo_bh_mutex); loop_put_buffer(new_bio); out: - bio_io_error(old_bio); + bio_io_error(old_bio, old_bio->bi_size); return 0; inactive: spin_unlock_irq(&lo->lo_lock); @@ -569,13 +574,13 @@ */ if (lo->lo_flags & LO_FLAGS_DO_BMAP) { ret = do_bio_filebacked(lo, bio); - bio_endio(bio, !ret); + bio_endio(bio, bio->bi_size, ret); } else { struct bio *rbh = bio->bi_private; ret = bio_transfer(lo, bio, rbh); - bio_endio(rbh, !ret); + bio_endio(rbh, rbh->bi_size, ret); loop_put_buffer(bio); } } diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c --- a/drivers/block/rd.c Wed Sep 18 15:55:16 2002 +++ b/drivers/block/rd.c Wed Sep 18 15:55:16 2002 @@ -277,11 +277,10 @@ if (rd_blkdev_bio_IO(sbh, minor)) goto fail; - set_bit(BIO_UPTODATE, &sbh->bi_flags); - sbh->bi_end_io(sbh); + bio_endio(sbh, sbh->bi_size, 0); return 0; fail: - bio_io_error(sbh); + bio_io_error(sbh, sbh->bi_size); return 0; } diff -Nru a/fs/bio.c b/fs/bio.c --- a/fs/bio.c Wed Sep 18 15:55:16 2002 +++ b/fs/bio.c Wed Sep 18 15:55:16 2002 @@ -401,12 +401,16 @@ return 0; } -static void bio_end_io_kio(struct bio *bio) +static int bio_end_io_kio(struct bio *bio, unsigned int bytes_done, int error) { struct kiobuf *kio = (struct kiobuf *) bio->bi_private; - end_kio_request(kio, test_bit(BIO_UPTODATE, &bio->bi_flags)); + if (bio->bi_size) + return 1; + + end_kio_request(kio, error); bio_put(bio); + return 0; } /** @@ -519,15 +523,15 @@ end_kio_request(kio, !err); } -void bio_endio(struct bio *bio, int uptodate) +int bio_endio(struct bio *bio, unsigned int bytes_done, int error) { - if (uptodate) + if (!error) set_bit(BIO_UPTODATE, &bio->bi_flags); else clear_bit(BIO_UPTODATE, &bio->bi_flags); - if (bio->bi_end_io) - bio->bi_end_io(bio); + bio->bi_size -= bytes_done; + return bio->bi_end_io(bio, bytes_done, error); } static void __init biovec_init_pools(void) diff -Nru a/fs/buffer.c b/fs/buffer.c --- a/fs/buffer.c Wed Sep 18 15:55:16 2002 +++ b/fs/buffer.c Wed Sep 18 15:55:16 2002 @@ -2413,12 +2413,16 @@ return err ? err : transferred; } -static void end_bio_bh_io_sync(struct bio *bio) +static int end_bio_bh_io_sync(struct bio *bio, unsigned int bytes_done, int err) { struct buffer_head *bh = bio->bi_private; + if (bio->bi_size) + return 1; + bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags)); bio_put(bio); + return 0; } int submit_bh(int rw, struct buffer_head * bh) diff -Nru a/fs/direct-io.c b/fs/direct-io.c --- a/fs/direct-io.c Wed Sep 18 15:55:16 2002 +++ b/fs/direct-io.c Wed Sep 18 15:55:16 2002 @@ -151,17 +151,21 @@ * 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) +static int dio_bio_end_io(struct bio *bio, unsigned int bytes_done, int error) { struct dio *dio = bio->bi_private; unsigned long flags; + if (bio->bi_size) + return 1; + spin_lock_irqsave(&dio->bio_list_lock, flags); bio->bi_private = dio->bio_list; dio->bio_list = bio; if (dio->waiter) wake_up_process(dio->waiter); spin_unlock_irqrestore(&dio->bio_list_lock, flags); + return 0; } static int diff -Nru a/fs/mpage.c b/fs/mpage.c --- a/fs/mpage.c Wed Sep 18 15:55:16 2002 +++ b/fs/mpage.c Wed Sep 18 15:55:16 2002 @@ -36,11 +36,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_read(struct bio *bio) +static int mpage_end_io_read(struct bio *bio, unsigned int bytes_done, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; + if (bio->bi_size) + return 1; + do { struct page *page = bvec->bv_page; @@ -56,13 +59,17 @@ unlock_page(page); } while (bvec >= bio->bi_io_vec); bio_put(bio); + return 0; } -static void mpage_end_io_write(struct bio *bio) +static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; + if (bio->bi_size) + return 1; + do { struct page *page = bvec->bv_page; @@ -74,6 +81,7 @@ end_page_writeback(page); } while (bvec >= bio->bi_io_vec); bio_put(bio); + return 0; } struct bio *mpage_bio_submit(int rw, struct bio *bio) diff -Nru a/include/linux/bio.h b/include/linux/bio.h --- a/include/linux/bio.h Wed Sep 18 15:55:16 2002 +++ b/include/linux/bio.h Wed Sep 18 15:55:16 2002 @@ -51,7 +51,7 @@ }; struct bio; -typedef void (bio_end_io_t) (struct bio *); +typedef int (bio_end_io_t) (struct bio *, unsigned int, int); typedef void (bio_destructor_t) (struct bio *); /* @@ -161,7 +161,7 @@ #define BIO_SEG_BOUNDARY(q, b1, b2) \ BIOVEC_SEG_BOUNDARY((q), __BVEC_END((b1)), __BVEC_START((b2))) -#define bio_io_error(bio) bio_endio((bio), 0) +#define bio_io_error(bio, bytes) bio_endio((bio), (bytes), -EIO) /* * drivers should not use the __ version unless they _really_ want to @@ -194,7 +194,7 @@ extern struct bio *bio_alloc(int, int); extern void bio_put(struct bio *); -extern void bio_endio(struct bio *, int); +extern int bio_endio(struct bio *, unsigned int, int); struct request_queue; extern inline int bio_phys_segments(struct request_queue *, struct bio *); extern inline int bio_hw_segments(struct request_queue *, struct bio *); diff -Nru a/mm/highmem.c b/mm/highmem.c --- a/mm/highmem.c Wed Sep 18 15:55:16 2002 +++ b/mm/highmem.c Wed Sep 18 15:55:16 2002 @@ -291,12 +291,16 @@ } } -static inline void bounce_end_io(struct bio *bio, mempool_t *pool) +static inline int bounce_end_io(struct bio *bio, unsigned int bytes_done, + int error, mempool_t *pool) { struct bio *bio_orig = bio->bi_private; struct bio_vec *bvec, *org_vec; int i; + if (bio->bi_size) + return 1; + if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) goto out_eio; @@ -314,38 +318,43 @@ } out_eio: - bio_orig->bi_end_io(bio_orig); + bio_endio(bio_orig, bytes_done, error); bio_put(bio); + return 0; } -static void bounce_end_io_write(struct bio *bio) +static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done, + int error) { - bounce_end_io(bio, page_pool); + return bounce_end_io(bio, bytes_done, error, page_pool); } -static void bounce_end_io_write_isa(struct bio *bio) +static int bounce_end_io_write_isa(struct bio *bio, unsigned int bytes_done, + int error) { - bounce_end_io(bio, isa_page_pool); + return bounce_end_io(bio, bytes_done, error, isa_page_pool); } -static inline void __bounce_end_io_read(struct bio *bio, mempool_t *pool) +static inline int __bounce_end_io_read(struct bio *bio, unsigned int done, + int error, mempool_t *pool) { struct bio *bio_orig = bio->bi_private; if (test_bit(BIO_UPTODATE, &bio->bi_flags)) copy_to_high_bio_irq(bio_orig, bio); - bounce_end_io(bio, pool); + return bounce_end_io(bio, done, error, pool); } -static void bounce_end_io_read(struct bio *bio) +static int bounce_end_io_read(struct bio *bio, unsigned int bytes_done, int err) { - __bounce_end_io_read(bio, page_pool); + return __bounce_end_io_read(bio, bytes_done, err, page_pool); } -static void bounce_end_io_read_isa(struct bio *bio) +static int bounce_end_io_read_isa(struct bio *bio, unsigned int bytes_done, + int err) { - return __bounce_end_io_read(bio, isa_page_pool); + return __bounce_end_io_read(bio, bytes_done, err, isa_page_pool); } void blk_queue_bounce(request_queue_t *q, struct bio **bio_orig) diff -Nru a/mm/page_io.c b/mm/page_io.c --- a/mm/page_io.c Wed Sep 18 15:55:16 2002 +++ b/mm/page_io.c Wed Sep 18 15:55:16 2002 @@ -47,22 +47,29 @@ return bio; } -static void end_swap_bio_write(struct bio *bio) +static int end_swap_bio_write(struct bio *bio, unsigned int bytes_done, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; + if (bio->bi_size) + return 1; + if (!uptodate) SetPageError(page); end_page_writeback(page); bio_put(bio); + return 0; } -static void end_swap_bio_read(struct bio *bio) +static int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; + if (bio->bi_size) + return 1; + if (!uptodate) { SetPageError(page); ClearPageUptodate(page); @@ -71,6 +78,7 @@ } unlock_page(page); bio_put(bio); + return 0; } /*