+++ /dev/null
-From: Hannes Reinecke <hare@suse.de>
-Subject: Kernel oops in free_bio_clone()
-References: bnc#472360
-
-Bug is here:
-
-static int setup_clone(struct request *clone, struct request *rq,
- struct dm_rq_target_io *tio)
-{
- int r;
-
- blk_rq_init(NULL, clone);
-
- r = clone_request_bios(clone, rq, tio->md);
- if (r)
- return r;
-
- copy_request_info(clone, rq);
- clone->start_time = jiffies;
- clone->end_io = end_clone_request;
- clone->end_io_data = tio;
-
- return 0;
-}
-
-clone_request_bios() might end up calling free_bio_clone(), which references:
-
-static void free_bio_clone(struct request *clone)
-{
- struct dm_rq_target_io *tio = clone->end_io_data;
- struct mapped_device *md = tio->md;
-...
-
-but end_io_data will be set only _after_ the call to clone_request_bios().
-So we should be passing the 'md' argument directly here to avoid this
-bug and several pointless derefencings.
-
-Signed-off-by: Hannes Reinecke <hare@suse.de>
-
---- linux-2.6.27-SLE11_BRANCH/drivers/md/dm.c.orig 2009-02-04 10:33:22.656627650 +0100
-+++ linux-2.6.27-SLE11_BRANCH/drivers/md/dm.c 2009-02-05 11:03:35.843251773 +0100
-@@ -709,10 +709,8 @@ static void end_clone_bio(struct bio *cl
- blk_update_request(tio->orig, 0, nr_bytes);
- }
-
--static void free_bio_clone(struct request *clone)
-+static void free_bio_clone(struct request *clone, struct mapped_device *md)
- {
-- struct dm_rq_target_io *tio = clone->end_io_data;
-- struct mapped_device *md = tio->md;
- struct bio *bio;
-
- while ((bio = clone->bio) != NULL) {
-@@ -743,7 +741,7 @@ static void dm_unprep_request(struct req
- rq->special = NULL;
- rq->cmd_flags &= ~REQ_DONTPREP;
-
-- free_bio_clone(clone);
-+ free_bio_clone(clone, tio->md);
- dec_rq_pending(tio);
- free_rq_tio(tio->md, tio);
- }
-@@ -820,7 +818,7 @@ static void dm_end_request(struct reques
- rq->sense_len = clone->sense_len;
- }
-
-- free_bio_clone(clone);
-+ free_bio_clone(clone, tio->md);
- dec_rq_pending(tio);
- free_rq_tio(tio->md, tio);
-
-@@ -1406,7 +1404,7 @@ static int clone_request_bios(struct req
- return 0;
-
- free_and_out:
-- free_bio_clone(clone);
-+ free_bio_clone(clone, md);
-
- return -ENOMEM;
- }