]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.39/patches.fixes/dm-table-upgrade-mode-race-fix
Fix oinkmaster patch.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.fixes / dm-table-upgrade-mode-race-fix
1 Patch-mainline: 2.6.30
2 References: bnc#486430
3 X-Git: 570b9d968bf9b16974252ef7cbce73fa6dac34f3 Mon Sep 17 00:00:00 2001
4 From: Alasdair G Kergon <agk@redhat.com>
5 Date: Thu, 2 Apr 2009 19:55:28 +0100
6 Subject: [PATCH] dm table: fix upgrade mode race
7
8 upgrade_mode() sets bdev to NULL temporarily, and does not have any
9 locking to exclude anything from seeing that NULL.
10
11 In dm_table_any_congested() bdev_get_queue() can dereference that NULL and
12 cause a reported oops.
13
14 Fix this by not changing that field during the mode upgrade.
15
16 Cc: stable@kernel.org
17 Cc: Neil Brown <neilb@suse.de>
18 Signed-off-by: Alasdair G Kergon <agk@redhat.com>
19 Acked-by: Neil Brown <neilb@suse.de>
20
21 ---
22 drivers/md/dm-table.c | 32 +++++++++++++++++---------------
23 1 file changed, 17 insertions(+), 15 deletions(-)
24
25 --- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/dm-table.c
26 +++ linux-2.6.27-SLE11_BRANCH/drivers/md/dm-table.c
27 @@ -411,31 +411,33 @@ static int check_device_area(struct dm_d
28 }
29
30 /*
31 - * This upgrades the mode on an already open dm_dev. Being
32 + * This upgrades the mode on an already open dm_dev, being
33 * careful to leave things as they were if we fail to reopen the
34 - * device.
35 + * device and not to touch the existing bdev field in case
36 + * it is accessed concurrently inside dm_table_any_congested().
37 */
38 static int upgrade_mode(struct dm_dev *dd, int new_mode, struct mapped_device *md)
39 {
40 int r;
41 - struct dm_dev dd_copy;
42 - dev_t dev = dd->bdev->bd_dev;
43 + struct dm_dev dd_new, dd_old;
44
45 - dd_copy = *dd;
46 + dd_new = dd_old = *dd;
47
48 - dd->mode = new_mode;
49 - dd->bdev = NULL;
50 - r = open_dev(dd, dev, md);
51 + dd_new.mode = new_mode;
52 + dd_new.bdev = NULL;
53 +
54 + r = open_dev(&dd_new, dd->bdev->bd_dev, md);
55 if (r == -EROFS) {
56 - dd->mode &= ~FMODE_WRITE;
57 - r = open_dev(dd, dev, md);
58 + dd_new.mode &= ~FMODE_WRITE;
59 + r = open_dev(&dd_new, dd->bdev->bd_dev, md);
60 }
61 - if (!r)
62 - close_dev(&dd_copy, md);
63 - else
64 - *dd = dd_copy;
65 + if (r)
66 + return r;
67
68 - return r;
69 + dd->mode |= new_mode;
70 + close_dev(&dd_old, md);
71 +
72 + return 0;
73 }
74
75 /*