[DRBD-user] Kernel BUG at fs/bio.c while using drbd 8.0.1

Rafał Kupka rkupka+Listy.Drbd at pronet.com.pl
Sun Apr 1 19:08:53 CEST 2007

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)



More information about the drbd-user mailing list