]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - 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
CommitLineData
2cb7cef9
BS
1Patch-mainline: 2.6.30
2References: bnc#486430
3X-Git: 570b9d968bf9b16974252ef7cbce73fa6dac34f3 Mon Sep 17 00:00:00 2001
4From: Alasdair G Kergon <agk@redhat.com>
5Date: Thu, 2 Apr 2009 19:55:28 +0100
6Subject: [PATCH] dm table: fix upgrade mode race
7
8upgrade_mode() sets bdev to NULL temporarily, and does not have any
9locking to exclude anything from seeing that NULL.
10
11In dm_table_any_congested() bdev_get_queue() can dereference that NULL and
12cause a reported oops.
13
14Fix this by not changing that field during the mode upgrade.
15
16Cc: stable@kernel.org
17Cc: Neil Brown <neilb@suse.de>
18Signed-off-by: Alasdair G Kergon <agk@redhat.com>
19Acked-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 /*