Note: "permalinks" may not be as permanent as we would like,
direct links of old sources may well be a few messages off.
Hello, This patch splits cross-boundary bio with bi_vcnt >1 into smaller pieces. Don't know if it is proper solution, but it works fine on my system so far. --- drbd.orig/drbd/drbd_req.c 2007-02-28 21:21:14.000000000 +0100 +++ drbd/drbd/drbd_req.c 2007-04-01 16:35:29.920664086 +0200 @@ -1076,6 +1076,17 @@ return 0; } +/* helper function to gather partial request status + */ +static int bio_partial_end(struct bio * bi, unsigned int done, int err) +{ + if (err) + *(int *)bi->bi_private = err; + if (bi->bi_size) + return 1; + return 0; +} + int drbd_make_request_26(request_queue_t *q, struct bio *bio) { unsigned int s_enr,e_enr; @@ -1115,32 +1126,63 @@ #endif if(unlikely(s_enr != e_enr)) { - /* This bio crosses some boundary, so we have to split it. - * [So far, only XFS is known to do this...] */ - struct bio_pair *bp; + if (bio->bi_vcnt == 1) { + /* This bio crosses some boundary, so we have to split it. + * [So far, only XFS is known to do this...] */ + struct bio_pair *bp; #if 1 - /* works for the "do not cross hash slot boundaries" case - * e.g. sector 262269, size 4096 - * s_enr = 262269 >> 6 = 4097 - * e_enr = (262269+8-1) >> 6 = 4098 - * HT_SHIFT = 6 - * sps = 64, mask = 63 - * first_sectors = 64 - (262269 & 63) = 3 - */ - const sector_t sect = bio->bi_sector; - const int sps = 1<<HT_SHIFT; /* sectors per slot */ - const int mask = sps -1; - const sector_t first_sectors = sps - (sect & mask); - bp = bio_split(bio, bio_split_pool, first_sectors); + /* works for the "do not cross hash slot boundaries" case + * e.g. sector 262269, size 4096 + * s_enr = 262269 >> 6 = 4097 + * e_enr = (262269+8-1) >> 6 = 4098 + * HT_SHIFT = 6 + * sps = 64, mask = 63 + * first_sectors = 64 - (262269 & 63) = 3 + */ + const sector_t sect = bio->bi_sector; + const int sps = 1<<HT_SHIFT; /* sectors per slot */ + const int mask = sps -1; + const sector_t first_sectors = sps - (sect & mask); + bp = bio_split(bio, bio_split_pool, first_sectors); #else - /* works for the al-extent boundary case */ - bp = bio_split(bio, bio_split_pool, - (e_enr<<(AL_EXTENT_SIZE_B-9)) - bio->bi_sector); + /* works for the al-extent boundary case */ + bp = bio_split(bio, bio_split_pool, + (e_enr<<(AL_EXTENT_SIZE_B-9)) - bio->bi_sector); #endif - drbd_make_request_26(q,&bp->bio1); - drbd_make_request_26(q,&bp->bio2); - bio_pair_release(bp); - return 0; + drbd_make_request_26(q,&bp->bio1); + drbd_make_request_26(q,&bp->bio2); + bio_pair_release(bp); + return 0; + } else { + /* This bio crosses boundary and have >1 + * bio_vec parts, so we can't use bio_split. + * Break it into one bio_vec per bio */ + struct bio_vec *bvec; + int i, error = 0; + unsigned int offset = 0; + /* cannot handle partially completed bio */ + D_ASSERT(bio->bi_idx == 0); + bio_for_each_segment(bvec, bio, i) { + struct bio *partial; + partial = bio_alloc(GFP_NOIO, 1); + if (!partial) { + error = -ENOMEM; + break; + } + partial->bi_io_vec = bvec; + partial->bi_sector = bio->bi_sector + (offset >> 9); + partial->bi_bdev = bio->bi_bdev; + partial->bi_rw = bio->bi_rw; + partial->bi_vcnt = 1; + partial->bi_size = bvec->bv_len; + partial->bi_private = &error; + partial->bi_end_io = bio_partial_end; + offset += bvec->bv_len; + drbd_make_request_26(q, partial); + } + bio_endio(bio, bio->bi_size, error); + return 0; + } } return drbd_make_request_common(mdev,bio_rw(bio),bio->bi_size, Regards, Kupson -- Great software without the knowledge to run it is pretty useless. (Linux Gazette #1)