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)