Skip to contentSkip to conversation

loop: fix aio/dio end of request clearing

PATCH In review Jens Axboe 1 participant 2 messages Apr 12, 2018 – Apr 13, 2018 Block layer

lore
Share & tools
lore

Jens Axboe

author maintainer
#0 lore raw

PATCH 1/1 loop: fix aio/dio end of request clearing

If we read more than the user asked for, we zero fill the last part. But the current code assumes that the request has just one bio, and since that's not guaranteed to be true, we can run into a situation where we attempt to advance a bio by a bigger amount than its size.

Handle the zero filling appropriately, regardless of what bio ends up needing to be cleared.

---

drivers/block/loop.c +15 -2
index c9d04497a415..d3aa96a2f369 100644
@@ -455,9 +455,22 @@ static void lo_complete_rq(struct request *rq)
 	if (unlikely(req_op(cmd->rq) == REQ_OP_READ && cmd->use_aio &&
 		     cmd->ret >= 0 && cmd->ret < blk_rq_bytes(cmd->rq))) {
 		struct bio *bio = cmd->rq->bio;
+		long left = cmd->ret;
 
-		bio_advance(bio, cmd->ret);
-		zero_fill_bio(bio);
+		while (left >= bio->bi_iter.bi_size) {
+			left -= bio->bi_iter.bi_size;
+			bio = bio->bi_next;
+			if (WARN_ON_ONCE(!bio))
+				break;
+		}
+		while (bio) {
+			if (left) {
+				bio_advance(bio, left);
+				left = 0;
+			}
+			zero_fill_bio(bio);
+			bio = bio->bi_next;
+		}
 	}
 
 	blk_mq_end_request(rq, cmd->ret < 0 ? BLK_STS_IOERR : BLK_STS_OK);
Signature · 1 line
Jens Axboe
author maintainer
#1 lore raw
Quoted 30 lines · Jens Axboe

If we read more than the user asked for, we zero fill the last part. But the current code assumes that the request has just one bio, and since that's not guaranteed to be true, we can run into a situation where we attempt to advance a bio by a bigger amount than its size.

Handle the zero filling appropriately, regardless of what bio ends up needing to be cleared.

---

drivers/block/loop.c +6 -2
index c9d04497a415..d3aa96a2f369 100644
@@ -455,9 +455,22 @@ static void lo_complete_rq(struct request *rq)
 	if (unlikely(req_op(cmd->rq) == REQ_OP_READ && cmd->use_aio &&
 		     cmd->ret >= 0 && cmd->ret < blk_rq_bytes(cmd->rq))) {
 		struct bio *bio = cmd->rq->bio;
+		long left = cmd->ret;
 
-		bio_advance(bio, cmd->ret);
-		zero_fill_bio(bio);
+		while (left >= bio->bi_iter.bi_size) {
+			left -= bio->bi_iter.bi_size;
+			bio = bio->bi_next;
+			if (WARN_ON_ONCE(!bio))
+				break;

drivers/block/loop.c static void lo_complete_rq(struct request *rq) · line 474

Quoted 10 lines
drivers/block/loop.c +9 -0
+		}
+		while (bio) {
+			if (left) {
+				bio_advance(bio, left);
+				left = 0;
+			}
+			zero_fill_bio(bio);
+			bio = bio->bi_next;
+		}
 	}

Ignore this one, new version coming.

Signature · 1 line
Jens Axboe