block: WARN in __blk_put_request() for potential bio leak
Boaz Harrosh [Tue, 24 Mar 2009 11:35:07 +0000 (12:35 +0100)]
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>

block/blk-core.c
block/blk-merge.c
block/scsi_ioctl.c

index 7b63c9b..996ed90 100644 (file)
@@ -1062,6 +1062,9 @@ void __blk_put_request(struct request_queue *q, struct request *req)
 
        elv_completed_request(q, req);
 
+       /* this is a bio leak */
+       WARN_ON(req->bio != NULL);
+
        /*
         * Request may not have originated from ll_rw_blk. if not,
         * it didn't come out of our reserved rq pools
index 5a244f0..e39cb24 100644 (file)
@@ -403,6 +403,8 @@ static int attempt_merge(struct request_queue *q, struct request *req,
        if (blk_rq_cpu_valid(next))
                req->cpu = next->cpu;
 
+       /* owner-ship of bio passed from next to req */
+       next->bio = NULL;
        __blk_put_request(q, next);
        return 1;
 }
index ee9c67d..626ee27 100644 (file)
@@ -214,21 +214,10 @@ static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq,
        return 0;
 }
 
-/*
- * unmap a request that was previously mapped to this sg_io_hdr. handles
- * both sg and non-sg sg_io_hdr.
- */
-static int blk_unmap_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr)
-{
-       blk_rq_unmap_user(rq->bio);
-       blk_put_request(rq);
-       return 0;
-}
-
 static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
                                 struct bio *bio)
 {
-       int r, ret = 0;
+       int ret = 0;
 
        /*
         * fill in all the output members
@@ -253,12 +242,10 @@ static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
                        ret = -EFAULT;
        }
 
-       rq->bio = bio;
-       r = blk_unmap_sghdr_rq(rq, hdr);
-       if (ret)
-               r = ret;
+       blk_rq_unmap_user(bio);
+       blk_put_request(rq);
 
-       return r;
+       return ret;
 }
 
 static int sg_io(struct request_queue *q, struct gendisk *bd_disk,