diff options
author | Boaz Harrosh <bharrosh@panasas.com> | 2009-03-24 07:35:07 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2009-03-26 06:01:23 -0400 |
commit | 1cd96c242a829d52f7a5ae98f554ca9775429685 (patch) | |
tree | 018d3ab9fa0d6e2bcd739483ac2693f6f71db96b | |
parent | f028f3b2f987ebc61cef382ab7a5c449917b728e (diff) |
block: WARN in __blk_put_request() for potential bio leak
Put a WARN_ON in __blk_put_request if it is about to
leak bio(s). This is a serious bug that can happen in error
handling code paths.
For this to work I have fixed a couple of places in block/ where
request->bio != NULL ownership was not honored. And a small cleanup
at sg_io() while at it.
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r-- | block/blk-core.c | 3 | ||||
-rw-r--r-- | block/blk-merge.c | 2 | ||||
-rw-r--r-- | block/scsi_ioctl.c | 21 |
3 files changed, 9 insertions, 17 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index 7b63c9b6333d..996ed906d8ca 100644 --- a/block/blk-core.c +++ b/block/blk-core.c | |||
@@ -1062,6 +1062,9 @@ void __blk_put_request(struct request_queue *q, struct request *req) | |||
1062 | 1062 | ||
1063 | elv_completed_request(q, req); | 1063 | elv_completed_request(q, req); |
1064 | 1064 | ||
1065 | /* this is a bio leak */ | ||
1066 | WARN_ON(req->bio != NULL); | ||
1067 | |||
1065 | /* | 1068 | /* |
1066 | * Request may not have originated from ll_rw_blk. if not, | 1069 | * Request may not have originated from ll_rw_blk. if not, |
1067 | * it didn't come out of our reserved rq pools | 1070 | * it didn't come out of our reserved rq pools |
diff --git a/block/blk-merge.c b/block/blk-merge.c index 5a244f05360f..e39cb24b7679 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c | |||
@@ -403,6 +403,8 @@ static int attempt_merge(struct request_queue *q, struct request *req, | |||
403 | if (blk_rq_cpu_valid(next)) | 403 | if (blk_rq_cpu_valid(next)) |
404 | req->cpu = next->cpu; | 404 | req->cpu = next->cpu; |
405 | 405 | ||
406 | /* owner-ship of bio passed from next to req */ | ||
407 | next->bio = NULL; | ||
406 | __blk_put_request(q, next); | 408 | __blk_put_request(q, next); |
407 | return 1; | 409 | return 1; |
408 | } | 410 | } |
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index ee9c67d7e1be..626ee274c5c4 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c | |||
@@ -214,21 +214,10 @@ static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, | |||
214 | return 0; | 214 | return 0; |
215 | } | 215 | } |
216 | 216 | ||
217 | /* | ||
218 | * unmap a request that was previously mapped to this sg_io_hdr. handles | ||
219 | * both sg and non-sg sg_io_hdr. | ||
220 | */ | ||
221 | static int blk_unmap_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr) | ||
222 | { | ||
223 | blk_rq_unmap_user(rq->bio); | ||
224 | blk_put_request(rq); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, | 217 | static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, |
229 | struct bio *bio) | 218 | struct bio *bio) |
230 | { | 219 | { |
231 | int r, ret = 0; | 220 | int ret = 0; |
232 | 221 | ||
233 | /* | 222 | /* |
234 | * fill in all the output members | 223 | * fill in all the output members |
@@ -253,12 +242,10 @@ static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, | |||
253 | ret = -EFAULT; | 242 | ret = -EFAULT; |
254 | } | 243 | } |
255 | 244 | ||
256 | rq->bio = bio; | 245 | blk_rq_unmap_user(bio); |
257 | r = blk_unmap_sghdr_rq(rq, hdr); | 246 | blk_put_request(rq); |
258 | if (ret) | ||
259 | r = ret; | ||
260 | 247 | ||
261 | return r; | 248 | return ret; |
262 | } | 249 | } |
263 | 250 | ||
264 | static int sg_io(struct request_queue *q, struct gendisk *bd_disk, | 251 | static int sg_io(struct request_queue *q, struct gendisk *bd_disk, |