A few considerations:
- Drivers which traverse segments directly (rather than
use helpers like blk_rq_map_sg or handle and complete
one segment at a time using end_that_request_first),
would need to account for bi_voffset and bi_endvoffset.
- Preferably use rq_map_buffer() to map the current
segment to a virtual address if needed, or do something
similar to account for the correct offsets. bio_kmap_irq
is gone now (notice that the start of the bio may no longer
be the start of the next portion to submit, which is
the right one to map during request processing)
- Use bio_segsize() to find out the length of the
first bio segment rather than directly rely on the bv_len
field, since the bio could contain just a part of the vec.
- In general remember that bio_startoffset() and
bio_endoffset() could be non-zero.
- Drivers which create/setup bios themselves would
need to ensure correct initialization of bi_voffset
and bi_endvoffset
General:
Since some of the block layer helper routines depend
on nr_sectors, current_nr_sectors, hard_cur_sectors,
nr_bio_segments and nr_bio_sectors, a little care is
needed to avoid inconsistencies amongst the various counts
and pointers at any point. A good option is to make use
of process_that_request_first where applicable/suitable
and have it take care of ensuring this, rather than trying
to do the same by hand.
As mentioned earlier some temporary BUG_ON sanity checks
have been inserted at some places where the drivers didn't
appear to be handle arbitrary bios (i.e. with non-zero
bio_startoffset/bio_endoffset).
No changes have been made to LVM for now. Eventually things like
LVM/EVMS would be the generators of clone bios of the type
allowed by this change.
diff -ur linux-2.5.30-pure/drivers/block/floppy.c linux-2.5.30-bio/drivers/block/floppy.c
--- linux-2.5.30-pure/drivers/block/floppy.c Fri Aug 2 10:08:27 2002
+++ linux-2.5.30-bio/drivers/block/floppy.c Fri Aug 2 10:43:30 2002
@@ -2472,6 +2472,9 @@
size = 0;
rq_for_each_bio(bio, CURRENT) {
+ /* Can't handle arbitrary split bio pieces */
+ BIO_BUG_ON(bio_startoffset(bio) != 0);
+ BIO_BUG_ON(bio_endoffset(bio) != 0);
bio_for_each_segment(bv, bio, i) {
if (page_address(bv->bv_page) + bv->bv_offset != base + size)
break;
@@ -2539,6 +2542,9 @@
size = CURRENT->current_nr_sectors << 9;
rq_for_each_bio(bio, CURRENT) {
+ /* Can't handle arbitrary bio pieces as yet */
+ BIO_BUG_ON(bio_startoffset(bio) != 0);
+ BIO_BUG_ON(bio_endoffset(bio) != 0);
bio_for_each_segment(bv, bio, i) {
if (!remaining)
break;
@@ -3886,6 +3892,9 @@
bio.bi_vcnt = 1;
bio.bi_idx = 0;
bio.bi_size = size;
+ bio.bi_voffset = __BVEC_START(&bio)->bv_offset;
+ bio.bi_endvoffset = __BVEC_END(&bio)->bv_offset +
+ __BVEC_END(&bio)->bv_len;
bio.bi_bdev = bdev;
bio.bi_sector = 0;
init_completion(&complete);
diff -ur linux-2.5.30-pure/drivers/block/loop.c linux-2.5.30-bio/drivers/block/loop.c
--- linux-2.5.30-pure/drivers/block/loop.c Fri Aug 2 10:08:27 2002
+++ linux-2.5.30-bio/drivers/block/loop.c Fri Aug 2 10:43:30 2002
@@ -179,7 +179,8 @@
}
static int
-do_lo_send(struct loop_device *lo, struct bio_vec *bvec, int bsize, loff_t pos)
+do_lo_send(struct loop_device *lo, struct bio_vec *bvec, int bsize, loff_t pos,
+ int startoff, int endoff)
{
struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
@@ -194,8 +195,8 @@
down(&mapping->host->i_sem);
index = pos >> PAGE_CACHE_SHIFT;
offset = pos & (PAGE_CACHE_SIZE - 1);
- data = kmap(bvec->bv_page) + bvec->bv_offset;
- len = bvec->bv_len;
+ data = kmap(bvec->bv_page) + bvec->bv_offset + startoff;
+ len = bvec->bv_len - startoff - endoff;
while (len > 0) {
int IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize;
int transfer_result;
@@ -251,14 +252,19 @@
{
unsigned vecnr;
int ret = 0;
+ int startoff = bio_startoffset(bio), endoff = 0;
for (vecnr = 0; vecnr < bio->bi_vcnt; vecnr++) {
+ /* FIXME: Could be more efficient */
+ if (vecnr == bio->bi_vcnt - 1)
+ endoff = bio_endoffset(bio);
struct bio_vec *bvec = &bio->bi_io_vec[vecnr];
- ret = do_lo_send(lo, bvec, bsize, pos);
+ ret = do_lo_send(lo, bvec, bsize, pos, startoff, endoff);
if (ret < 0)
break;
- pos += bvec->bv_len;
+ pos += bvec->bv_len - startoff - endoff;
+ startoff = 0;
}
return ret;
}
@@ -296,17 +302,17 @@
static int
do_lo_receive(struct loop_device *lo,
- struct bio_vec *bvec, int bsize, loff_t pos)
+ struct bio_vec *bvec, int bsize, loff_t pos, int startoff, int endoff)
{
struct lo_read_data cookie;
read_descriptor_t desc;
struct file *file;
cookie.lo = lo;
- cookie.data = kmap(bvec->bv_page) + bvec->bv_offset;
+ cookie.data = kmap(bvec->bv_page) + bvec->bv_offset + startoff;
cookie.bsize = bsize;
desc.written = 0;
- desc.count = bvec->bv_len;
+ desc.count = bvec->bv_len - startoff - endoff;
desc.buf = (char*)&cookie;
desc.error = 0;
spin_lock_irq(&lo->lo_lock);
@@ -322,14 +328,20 @@
{
unsigned vecnr;
int ret = 0;
+ int startoff = bio_startoffset(bio), endoff = 0;
for (vecnr = 0; vecnr < bio->bi_vcnt; vecnr++) {
struct bio_vec *bvec = &bio->bi_io_vec[vecnr];
- ret = do_lo_receive(lo, bvec, bsize, pos);
+ /* FIXME: Could be more efficient */
+ if (vecnr == bio->bi_vcnt - 1)
+ endoff = bio_endoffset(bio);
+
+ ret = do_lo_receive(lo, bvec, bsize, pos, startoff, endoff);
if (ret < 0)
break;
- pos += bvec->bv_len;
+ pos += bvec->bv_len - startoff - endoff;
+ startoff = 0;
}
return ret;
}
@@ -477,18 +489,29 @@
struct bio_vec *from_bvec, *to_bvec;
char *vto, *vfrom;
int ret = 0, i;
+ int from_start, from_len, to_start;
+ from_start = bio_offset(from_bio);
+ to_start = bio_offset(to_bio);
__bio_for_each_segment(from_bvec, from_bio, i, 0) {
to_bvec = &to_bio->bi_io_vec[i];
+ from_len = from_bvec->bv_len;
+
+ /* FIXME: Could be more efficient */
+ if (i == from_bio->bi_vcnt - 1)
+ from_len -= bio_endoffset(from_bio);
kmap(from_bvec->bv_page);
kmap(to_bvec->bv_page);
- vfrom = page_address(from_bvec->bv_page) + from_bvec->bv_offset;
- vto = page_address(to_bvec->bv_page) + to_bvec->bv_offset;
+ vfrom = page_address(from_bvec->bv_page) + from_bvec->bv_offset
+ + from_start;
+ vto = page_address(to_bvec->bv_page) + to_bvec->bv_offset +
+ to_start;
ret |= lo_do_transfer(lo, bio_data_dir(to_bio), vto, vfrom,
- from_bvec->bv_len, IV);
+ from_len, IV);
kunmap(from_bvec->bv_page);
kunmap(to_bvec->bv_page);
+ from_start = to_start = 0;
}
return ret;
diff -ur linux-2.5.30-pure/drivers/block/nbd.c linux-2.5.30-bio/drivers/block/nbd.c
--- linux-2.5.30-pure/drivers/block/nbd.c Sat Jul 27 08:28:32 2002
+++ linux-2.5.30-bio/drivers/block/nbd.c Fri Aug 2 10:43:30 2002
@@ -180,6 +180,9 @@
* whether to set MSG_MORE or not...
*/
rq_for_each_bio(bio, req) {
+ /* Can't handle arbitrary bio pieces yet */
+ BIO_BUG_ON(bio_startoffset(bio) != 0);
+ BIO_BUG_ON(bio_endoffset(bio) != 0);
struct bio_vec *bvec;
bio_for_each_segment(bvec, bio, i) {
flags = 0;
diff -ur linux-2.5.30-pure/drivers/block/rd.c linux-2.5.30-bio/drivers/block/rd.c
--- linux-2.5.30-pure/drivers/block/rd.c Fri Aug 2 10:08:27 2002
+++ linux-2.5.30-bio/drivers/block/rd.c Fri Aug 2 10:43:30 2002
@@ -227,6 +227,9 @@
sector = bio->bi_sector;
rw = bio_data_dir(bio);
+ /* Can't handle a bio split in the middle of a segment */
+ BIO_BUG_ON(bio_startoffset(bio) > 0);
+ BIO_BUG_ON(bio_offset(bio) > 0);
bio_for_each_segment(bvec, bio, i) {
ret |= rd_blkdev_pagecache_IO(rw, bvec, sector, minor);
sector += bvec->bv_len >> 9;
diff -ur linux-2.5.30-pure/drivers/block/umem.c linux-2.5.30-bio/drivers/block/umem.c
--- linux-2.5.30-pure/drivers/block/umem.c Fri Aug 2 10:08:27 2002
+++ linux-2.5.30-bio/drivers/block/umem.c Fri Aug 2 10:43:30 2002
@@ -423,7 +423,7 @@
if (card->mm_pages[card->Ready].cnt >= DESC_PER_PAGE)
return 0;
- len = bio_iovec(bio)->bv_len;
+ len = bio_segsize(bio);
dma_handle = pci_map_page(card->dev,
bio_page(bio),
bio_offset(bio),
diff -ur linux-2.5.30-pure/drivers/ide/ide-disk.c linux-2.5.30-bio/drivers/ide/ide-disk.c
--- linux-2.5.30-pure/drivers/ide/ide-disk.c Fri Aug 2 10:08:28 2002
+++ linux-2.5.30-bio/drivers/ide/ide-disk.c Fri Aug 2 10:43:30 2002
@@ -45,7 +45,7 @@
static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
{
if (rq->bio)
- return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
+ return rq_map_buffer(rq, flags);
else
return rq->buffer + ((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE;
}
@@ -54,7 +54,7 @@
unsigned long *flags)
{
if (rq->bio)
- bio_kunmap_irq(to, flags);
+ rq_unmap_buffer(to, flags);
}
/*
@@ -293,7 +293,7 @@
nsect = mcount;
mcount -= nsect;
- buf = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
+ buf = ide_map_rq(rq, &flags);
rq->sector += nsect;
rq->nr_sectors -= nsect;
rq->current_nr_sectors -= nsect;
@@ -318,7 +318,7 @@
* last transfer.
*/
ata_write(drive, buf, nsect * SECTOR_WORDS);
- bio_kunmap_irq(buf, &flags);
+ ide_unmap_rq(rq, buf, &flags);
} while (mcount);
ret = ATA_OP_CONTINUES;
diff -ur linux-2.5.30-pure/drivers/ide/ide.c linux-2.5.30-bio/drivers/ide/ide.c
--- linux-2.5.30-pure/drivers/ide/ide.c Fri Aug 2 10:08:28 2002
+++ linux-2.5.30-bio/drivers/ide/ide.c Fri Aug 2 10:43:30 2002
@@ -795,7 +795,9 @@
rq->errors = 0;
if (rq->bio) {
rq->sector = rq->bio->bi_sector;
- rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
+ rq->current_nr_sectors = bio_segsize(rq->bio)
+ >> 9;
+
rq->buffer = NULL;
}
ret = ATA_OP_FINISHED;
diff -ur linux-2.5.30-pure/drivers/ide/pdc4030.c linux-2.5.30-bio/drivers/ide/pdc4030.c
--- linux-2.5.30-pure/drivers/ide/pdc4030.c Sat Jul 27 08:28:32 2002
+++ linux-2.5.30-bio/drivers/ide/pdc4030.c Fri Aug 2 10:43:30 2002
@@ -400,14 +400,14 @@
if (nsect > sectors_avail)
nsect = sectors_avail;
sectors_avail -= nsect;
- to = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
+ to = ide_map_rq(rq, &flags);
promise_read(drive, to, nsect * SECTOR_WORDS);
#ifdef DEBUG_READ
printk(KERN_DEBUG "%s: promise_read: sectors(%ld-%ld), "
"buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
rq->sector+nsect-1, (unsigned long) to, rq->nr_sectors-nsect);
#endif
- bio_kunmap_irq(to, &flags);
+ ide_unmap_rq(rq, to, &flags);
rq->sector += nsect;
rq->errors = 0;
rq->nr_sectors -= nsect;
diff -ur linux-2.5.30-pure/drivers/md/raid1.c linux-2.5.30-bio/drivers/md/raid1.c
--- linux-2.5.30-pure/drivers/md/raid1.c Sat Jul 27 08:28:24 2002
+++ linux-2.5.30-bio/drivers/md/raid1.c Fri Aug 2 10:43:30 2002
@@ -90,6 +90,9 @@
bio->bi_vcnt = RESYNC_PAGES;
bio->bi_idx = 0;
bio->bi_size = RESYNC_BLOCK_SIZE;
+ bio->bi_voffset = __BVEC_START(bio)->bv_offset;
+ bio->bi_endvoffset = __BVEC_END(bio)->bv_offset +
+ __BVEC_END(bio)->bv_len;
bio->bi_end_io = NULL;
atomic_set(&bio->bi_cnt, 1);
diff -ur linux-2.5.30-pure/drivers/md/raid5.c linux-2.5.30-bio/drivers/md/raid5.c
--- linux-2.5.30-pure/drivers/md/raid5.c Sat Jul 27 08:28:31 2002
+++ linux-2.5.30-bio/drivers/md/raid5.c Fri Aug 2 10:43:30 2002
@@ -429,6 +429,8 @@
dev->vec.bv_page = dev->page;
dev->vec.bv_len = STRIPE_SIZE;
dev->vec.bv_offset = 0;
+ dev->req.bi_voffset = 0;
+ dev->req.bi_endvoffset = STRIPE_SIZE;
dev->req.bi_bdev = conf->disks[i].bdev;
dev->req.bi_sector = sh->sector;
@@ -615,6 +617,11 @@
for (;bio && bio->bi_sector < sector+STRIPE_SECTORS;
bio = bio->bi_next) {
int page_offset;
+
+ /* Can't handle arbitrary bio pieces yet */
+ BIO_BUG_ON(bio_startoffset(bio) != 0);
+ BIO_BUG_ON(bio_endoffset(bio) != 0);
+
if (bio->bi_sector >= sector)
page_offset = (signed)(bio->bi_sector - sector) * 512;
else
diff -ur linux-2.5.30-pure/drivers/scsi/ide-scsi.c linux-2.5.30-bio/drivers/scsi/ide-scsi.c
--- linux-2.5.30-pure/drivers/scsi/ide-scsi.c Fri Aug 2 10:08:28 2002
+++ linux-2.5.30-bio/drivers/scsi/ide-scsi.c Fri Aug 2 10:43:30 2002
@@ -592,8 +592,10 @@
while (segments--) {
bh->bi_io_vec[0].bv_page = sg->page;
bh->bi_io_vec[0].bv_len = sg->length;
- bh->bi_io_vec[0].bv_offset = sg->offset;
+ bh->bi_voffset = bh->bi_io_vec[0].bv_offset = sg->offset;
bh->bi_size = sg->length;
+ bh->bi_endvoffset = bh->bi_io_vec[0].bv_offset +
+ bh->bi_io_vec[0].bv_len;
bh = bh->bi_next;
sg++;
}
@@ -605,8 +607,10 @@
#endif
bh->bi_io_vec[0].bv_page = virt_to_page(pc->s.scsi_cmd->request_buffer);
bh->bi_io_vec[0].bv_len = pc->request_transfer;
- bh->bi_io_vec[0].bv_offset = (unsigned long) pc->s.scsi_cmd->request_buffer & ~PAGE_MASK;
+ bh->bi_voffset = bh->bi_io_vec[0].bv_offset = (unsigned long) pc->s.scsi_cmd->request_buffer & ~PAGE_MASK;
bh->bi_size = pc->request_transfer;
+ bh->bi_endvoffset = bh->bi_io_vec[0].bv_offset +
+ bh->bi_io_vec[0].bv_len;
}
return first_bh;
}
diff -ur linux-2.5.30-pure/drivers/scsi/scsi_lib.c linux-2.5.30-bio/drivers/scsi/scsi_lib.c
--- linux-2.5.30-pure/drivers/scsi/scsi_lib.c Sat Jul 27 08:28:38 2002
+++ linux-2.5.30-bio/drivers/scsi/scsi_lib.c Fri Aug 2 10:43:30 2002
@@ -481,10 +481,11 @@
if (SCpnt->buffer != req->buffer) {
if (rq_data_dir(req) == READ) {
unsigned long flags;
- char *to = bio_kmap_irq(req->bio, &flags);
+ /* Todo: check if this is all we need to do */
+ char *to = rq_map_buffer(req, &flags);
memcpy(to, SCpnt->buffer, SCpnt->bufflen);
- bio_kunmap_irq(to, &flags);
+ rq_unmap_buffer(to, &flags);
}
kfree(SCpnt->buffer);
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/