diff -ur -X exclude /opt/kernel/linux-2.5.1-pre6/drivers/block/elevator.c linux/drivers/block/elevator.c --- /opt/kernel/linux-2.5.1-pre6/drivers/block/elevator.c Fri Dec 7 02:09:30 2001 +++ linux/drivers/block/elevator.c Fri Dec 7 09:27:29 2001 @@ -61,6 +61,12 @@ BUG_ON(next_rq->flags & REQ_STARTED); /* + * not a sector based request + */ + if (!(next_rq->flags & REQ_CMD)) + return 0; + + /* * if the device is different (not a normal case) just check if * bio is after rq */ @@ -95,6 +101,9 @@ */ inline int elv_rq_merge_ok(struct request *rq, struct bio *bio) { + if (!(rq->flags & REQ_CMD)) + return 0; + /* * different data direction or already started, don't merge */ @@ -133,6 +142,8 @@ break; if (__rq->flags & (REQ_BARRIER | REQ_STARTED)) break; + if (!(__rq->flags & REQ_CMD)) + continue; if (!*req && bio_rq_in_between(bio, __rq, &q->queue_head)) *req = __rq; @@ -225,6 +236,9 @@ if (__rq->flags & (REQ_BARRIER | REQ_STARTED)) break; + + if (!(__rq->flags & REQ_CMD)) + continue; if (!elv_rq_merge_ok(__rq, bio)) continue; diff -ur -X exclude /opt/kernel/linux-2.5.1-pre6/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- /opt/kernel/linux-2.5.1-pre6/drivers/block/ll_rw_blk.c Fri Dec 7 02:09:30 2001 +++ linux/drivers/block/ll_rw_blk.c Fri Dec 7 09:30:16 2001 @@ -291,13 +291,13 @@ if (!(rq->flags & REQ_CMD)) return 0; + memset(rq->cmd, 0, sizeof(rq->cmd)); + if (rq_data_dir(rq) == READ) rq->cmd[0] = READ_10; else rq->cmd[0] = WRITE_10; - rq->cmd[1] = 0; - /* * fill in lba */ @@ -305,7 +305,6 @@ rq->cmd[3] = (block >> 16) & 0xff; rq->cmd[4] = (block >> 8) & 0xff; rq->cmd[5] = block & 0xff; - rq->cmd[6] = 0; /* * and transfer length @@ -347,7 +346,7 @@ unsigned long long lastend; struct bio_vec *bvec; struct bio *bio; - int nsegs, i, cluster, j; + int nsegs, i, cluster; nsegs = 0; bio = rq->bio; @@ -357,9 +356,7 @@ /* * for each bio in rq */ - j = 0; rq_for_each_bio(bio, rq) { - j++; /* * for each segment in bio */ @@ -386,7 +383,6 @@ new_segment: if (nsegs > q->max_segments) { printk("map: %d >= %d\n", nsegs, q->max_segments); - printk("map %d, %d, bio_sectors %d, vcnt %d\n", i, j, bio_sectors(bio), bio->bi_vcnt); BUG(); } @@ -411,7 +407,7 @@ static inline int ll_new_segment(request_queue_t *q, struct request *req, struct bio *bio) { - if (req->nr_segments + bio->bi_vcnt < q->max_segments) { + if (req->nr_segments + bio->bi_vcnt <= q->max_segments) { req->nr_segments += bio->bi_vcnt; return 1; } @@ -480,9 +476,17 @@ */ static inline void __generic_unplug_device(request_queue_t *q) { - if (test_and_clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) - if (!elv_queue_empty(q)) - q->request_fn(q); + /* + * not plugged + */ + if (!test_and_clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) + return; + + /* + * was plugged, fire request_fn if queue has stuff to do + */ + if (!elv_queue_empty(q)) + q->request_fn(q); } /** diff -ur -X exclude /opt/kernel/linux-2.5.1-pre6/fs/bio.c linux/fs/bio.c --- /opt/kernel/linux-2.5.1-pre6/fs/bio.c Fri Dec 7 02:09:31 2001 +++ linux/fs/bio.c Fri Dec 7 09:59:52 2001 @@ -377,7 +377,7 @@ /* * iterate iovec list and alloc pages + copy data */ - bio_for_each_segment(bv, bio, i) { + __bio_for_each_segment(bv, bio, i, 0) { struct bio_vec *bbv = &b->bi_io_vec[i]; char *vfrom, *vto; @@ -392,8 +392,7 @@ vfrom = kmap(bv->bv_page); vto = kmap(bbv->bv_page); } else { - __save_flags(flags); - __cli(); + local_irq_save(flags); vfrom = kmap_atomic(bv->bv_page, KM_BIO_IRQ); vto = kmap_atomic(bbv->bv_page, KM_BIO_IRQ); } @@ -405,7 +404,7 @@ } else { kunmap_atomic(vto, KM_BIO_IRQ); kunmap_atomic(vfrom, KM_BIO_IRQ); - __restore_flags(flags); + local_irq_restore(flags); } fill_in: @@ -424,10 +423,8 @@ return b; oom: - while (i >= 0) { + while (--i >= 0) __free_page(b->bi_io_vec[i].bv_page); - i--; - } bio_pool_put(b); return NULL; @@ -613,6 +610,11 @@ if (err) kio->errno = err; + /* + * final atomic_dec of io_count to match our initial setting of 1. + * I/O may or may not have completed at this point, final completion + * handler is only run on last decrement. + */ end_kio_request(kio, !err); } diff -ur -X exclude /opt/kernel/linux-2.5.1-pre6/include/linux/bio.h linux/include/linux/bio.h --- /opt/kernel/linux-2.5.1-pre6/include/linux/bio.h Fri Dec 7 02:09:31 2001 +++ linux/include/linux/bio.h Fri Dec 7 10:14:18 2001 @@ -100,7 +100,6 @@ #define bio_iovec_idx(bio, idx) (&((bio)->bi_io_vec[(idx)])) #define bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_idx) #define bio_page(bio) bio_iovec((bio))->bv_page -#define __bio_offset(bio, idx) bio_iovec_idx((bio), (idx))->bv_offset #define bio_offset(bio) bio_iovec((bio))->bv_offset #define bio_sectors(bio) ((bio)->bi_size >> 9) #define bio_data(bio) (page_address(bio_page((bio))) + bio_offset((bio))) @@ -136,10 +135,17 @@ #define bio_io_error(bio) bio_endio((bio), 0, bio_sectors((bio))) -#define bio_for_each_segment(bvl, bio, i) \ - for (bvl = bio_iovec((bio)), i = (bio)->bi_idx; \ +/* + * drivers should not use the __ version unless they _really_ want to + * run through the entire bio and not just pending pieces + */ +#define __bio_for_each_segment(bvl, bio, i, start_idx) \ + for (bvl = bio_iovec_idx((bio), (start_idx)), i = (start_idx); \ i < (bio)->bi_vcnt; \ bvl++, i++) + +#define bio_for_each_segment(bvl, bio, i) \ + __bio_for_each_segment(bvl, bio, i, (bio)->bi_idx) /* * get a reference to a bio, so it won't disappear. the intended use is diff -ur -X exclude /opt/kernel/linux-2.5.1-pre6/mm/highmem.c linux/mm/highmem.c --- /opt/kernel/linux-2.5.1-pre6/mm/highmem.c Fri Dec 7 09:16:24 2001 +++ linux/mm/highmem.c Fri Dec 7 10:28:44 2001 @@ -214,7 +214,7 @@ struct bio_vec *tovec, *fromvec; int i; - bio_for_each_segment(tovec, to, i) { + __bio_for_each_segment(tovec, to, i, 0) { fromvec = &from->bi_io_vec[i]; /* @@ -225,12 +225,11 @@ vfrom = page_address(fromvec->bv_page) + fromvec->bv_offset; - __save_flags(flags); - __cli(); + local_irq_save(flags); vto = kmap_atomic(tovec->bv_page, KM_BOUNCE_READ); - memcpy(vto + tovec->bv_offset, vfrom, to->bi_size); + memcpy(vto + tovec->bv_offset, vfrom, tovec->bv_len); kunmap_atomic(vto, KM_BOUNCE_READ); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -263,28 +262,39 @@ static inline int bounce_end_io (struct bio *bio, int nr_sectors) { struct bio *bio_orig = bio->bi_private; - struct page *page = bio_page(bio); + struct bio_vec *bvec, *org_vec; unsigned long flags; - int ret; + int ret, i; - if (test_bit(BIO_UPTODATE, &bio->bi_flags)) - set_bit(BIO_UPTODATE, &bio_orig->bi_flags); + if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) + goto out_eio; - ret = bio_orig->bi_end_io(bio_orig, nr_sectors); + set_bit(BIO_UPTODATE, &bio_orig->bi_flags); + /* + * free up bounce indirect pages used + */ spin_lock_irqsave(&emergency_lock, flags); - if (nr_emergency_pages >= POOL_SIZE) { - spin_unlock_irqrestore(&emergency_lock, flags); - __free_page(page); - } else { - /* - * We are abusing page->list to manage - * the highmem emergency pool: - */ - list_add(&page->list, &emergency_pages); - nr_emergency_pages++; - spin_unlock_irqrestore(&emergency_lock, flags); + __bio_for_each_segment(bvec, bio, i, 0) { + org_vec = &bio_orig->bi_io_vec[i]; + if (bvec->bv_page == org_vec->bv_page) + continue; + + if (nr_emergency_pages >= POOL_SIZE) + __free_page(bvec->bv_page); + else { + /* + * We are abusing page->list to manage + * the highmem emergency pool: + */ + list_add(&bvec->bv_page->list, &emergency_pages); + nr_emergency_pages++; + } } + spin_unlock_irqrestore(&emergency_lock, flags); + +out_eio: + ret = bio_orig->bi_end_io(bio_orig, nr_sectors); bio_put(bio); return ret;