]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Hannes Reinecke <hare@suse.de> |
2 | Subject: Kernel oops in free_bio_clone() | |
3 | References: bnc#472360 | |
4 | ||
5 | Bug is here: | |
6 | ||
7 | static int setup_clone(struct request *clone, struct request *rq, | |
8 | struct dm_rq_target_io *tio) | |
9 | { | |
10 | int r; | |
11 | ||
12 | blk_rq_init(NULL, clone); | |
13 | ||
14 | r = clone_request_bios(clone, rq, tio->md); | |
15 | if (r) | |
16 | return r; | |
17 | ||
18 | copy_request_info(clone, rq); | |
19 | clone->start_time = jiffies; | |
20 | clone->end_io = end_clone_request; | |
21 | clone->end_io_data = tio; | |
22 | ||
23 | return 0; | |
24 | } | |
25 | ||
26 | clone_request_bios() might end up calling free_bio_clone(), which references: | |
27 | ||
28 | static void free_bio_clone(struct request *clone) | |
29 | { | |
30 | struct dm_rq_target_io *tio = clone->end_io_data; | |
31 | struct mapped_device *md = tio->md; | |
32 | ... | |
33 | ||
34 | but end_io_data will be set only _after_ the call to clone_request_bios(). | |
35 | So we should be passing the 'md' argument directly here to avoid this | |
36 | bug and several pointless derefencings. | |
37 | ||
38 | Signed-off-by: Hannes Reinecke <hare@suse.de> | |
39 | ||
40 | --- linux-2.6.27-SLE11_BRANCH/drivers/md/dm.c.orig 2009-02-04 10:33:22.656627650 +0100 | |
41 | +++ linux-2.6.27-SLE11_BRANCH/drivers/md/dm.c 2009-02-05 11:03:35.843251773 +0100 | |
42 | @@ -709,10 +709,8 @@ static void end_clone_bio(struct bio *cl | |
43 | blk_update_request(tio->orig, 0, nr_bytes); | |
44 | } | |
45 | ||
46 | -static void free_bio_clone(struct request *clone) | |
47 | +static void free_bio_clone(struct request *clone, struct mapped_device *md) | |
48 | { | |
49 | - struct dm_rq_target_io *tio = clone->end_io_data; | |
50 | - struct mapped_device *md = tio->md; | |
51 | struct bio *bio; | |
52 | ||
53 | while ((bio = clone->bio) != NULL) { | |
54 | @@ -743,7 +741,7 @@ static void dm_unprep_request(struct req | |
55 | rq->special = NULL; | |
56 | rq->cmd_flags &= ~REQ_DONTPREP; | |
57 | ||
58 | - free_bio_clone(clone); | |
59 | + free_bio_clone(clone, tio->md); | |
60 | dec_rq_pending(tio); | |
61 | free_rq_tio(tio->md, tio); | |
62 | } | |
63 | @@ -820,7 +818,7 @@ static void dm_end_request(struct reques | |
64 | rq->sense_len = clone->sense_len; | |
65 | } | |
66 | ||
67 | - free_bio_clone(clone); | |
68 | + free_bio_clone(clone, tio->md); | |
69 | dec_rq_pending(tio); | |
70 | free_rq_tio(tio->md, tio); | |
71 | ||
72 | @@ -1406,7 +1404,7 @@ static int clone_request_bios(struct req | |
73 | return 0; | |
74 | ||
75 | free_and_out: | |
76 | - free_bio_clone(clone); | |
77 | + free_bio_clone(clone, md); | |
78 | ||
79 | return -ENOMEM; | |
80 | } |