aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoaz Harrosh <bharrosh@panasas.com>2009-03-24 07:35:07 -0400
committerJens Axboe <jens.axboe@oracle.com>2009-03-26 06:01:23 -0400
commit1cd96c242a829d52f7a5ae98f554ca9775429685 (patch)
tree018d3ab9fa0d6e2bcd739483ac2693f6f71db96b
parentf028f3b2f987ebc61cef382ab7a5c449917b728e (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.c3
-rw-r--r--block/blk-merge.c2
-rw-r--r--block/scsi_ioctl.c21
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 */
221static 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
228static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, 217static 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
264static int sg_io(struct request_queue *q, struct gendisk *bd_disk, 251static int sg_io(struct request_queue *q, struct gendisk *bd_disk,