]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.39/patches.fixes/dm-path-selector-ref-count
Fix oinkmaster patch.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.fixes / dm-path-selector-ref-count
CommitLineData
2cb7cef9
BS
1From: "Jun'ichi Nomura" <j-nomura@ce.jp.nec.com>
2Subject: dm-path-selector: fix refcount corruption
3
4Hi,
5
6Refcounting of path-selector module is not safe in SMP environment.
7The counter may corrupt and trigger BUG() like this:
8 kernel BUG at linux-2.6.29-rc3/drivers/md/dm-path-selector.c:90!
9though it's rare under normal usage.
10
11The bug is here:
12 void dm_put_path_selector(struct path_selector_type *pst)
13 {
14 ...
15 down_read(&_ps_lock);
16 psi = __find_path_selector_type(pst->name);
17 if (!psi)
18 goto out;
19
20 if (--psi->use == 0)
21 module_put(psi->pst.module);
22
23 BUG_ON(psi->use < 0);
24
25The code manipulates the counter without exclusive lock or atomic ops.
26So if 2 processors come in, the counter may corrupt.
27
28While it could be fixed using atomic ops for the counter manipulation,
29we can just drop the 'use' counter like Cheng Renquan did for dm-target:
30https://www.redhat.com/archives/dm-devel/2008-December/msg00075.html
31
32(Actually, without his patch, dm-target.c hits the same problem.)
33
34Signed-off-by: Hannes Reinecke <hare@suse.de>
35
36--
37Jun'ichi Nomura, NEC Corporation
38
39
40Fix refcount corruption in dm-path-selector
41
42Refcounting with non-atomic ops under shared lock will corrupt the counter
43in multi-processor system and may trigger BUG_ON().
44Use module refcount.
45# same approach as dm-target-use-module-refcount-directly.patch here
46# https://www.redhat.com/archives/dm-devel/2008-December/msg00075.html
47
48Typical oops:
49 kernel BUG at linux-2.6.29-rc3/drivers/md/dm-path-selector.c:90!
50 Pid: 11148, comm: dmsetup Not tainted 2.6.29-rc3-nm #1
51 dm_put_path_selector+0x4d/0x61 [dm_multipath]
52 Call Trace:
53 [<ffffffffa031d3f9>] free_priority_group+0x33/0xb3 [dm_multipath]
54 [<ffffffffa031d4aa>] free_multipath+0x31/0x67 [dm_multipath]
55 [<ffffffffa031d50d>] multipath_dtr+0x2d/0x32 [dm_multipath]
56 [<ffffffffa015d6c2>] dm_table_destroy+0x64/0xd8 [dm_mod]
57 [<ffffffffa015b73a>] __unbind+0x46/0x4b [dm_mod]
58 [<ffffffffa015b79f>] dm_swap_table+0x60/0x14d [dm_mod]
59 [<ffffffffa015f963>] dev_suspend+0xfd/0x177 [dm_mod]
60 [<ffffffffa0160250>] dm_ctl_ioctl+0x24c/0x29c [dm_mod]
61 [<ffffffff80288cd3>] ? get_page_from_freelist+0x49c/0x61d
62 [<ffffffffa015f866>] ? dev_suspend+0x0/0x177 [dm_mod]
63 [<ffffffff802bf05c>] vfs_ioctl+0x2a/0x77
64 [<ffffffff802bf4f1>] do_vfs_ioctl+0x448/0x4a0
65 [<ffffffff802bf5a0>] sys_ioctl+0x57/0x7a
66 [<ffffffff8020c05b>] system_call_fastpath+0x16/0x1b
67
68Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
69---
70 drivers/md/dm-path-selector.c | 21 +++------------------
71 1 file changed, 3 insertions(+), 18 deletions(-)
72
73--- a/drivers/md/dm-path-selector.c
74+++ b/drivers/md/dm-path-selector.c
75@@ -16,9 +16,7 @@
76
77 struct ps_internal {
78 struct path_selector_type pst;
79-
80 struct list_head list;
81- long use;
82 };
83
84 #define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst)
85@@ -44,12 +42,8 @@ static struct ps_internal *get_path_sele
86
87 down_read(&_ps_lock);
88 psi = __find_path_selector_type(name);
89- if (psi) {
90- if ((psi->use == 0) && !try_module_get(psi->pst.module))
91- psi = NULL;
92- else
93- psi->use++;
94- }
95+ if (psi && !try_module_get(psi->pst.module))
96+ psi = NULL;
97 up_read(&_ps_lock);
98
99 return psi;
100@@ -83,11 +77,7 @@ void dm_put_path_selector(struct path_se
101 if (!psi)
102 goto out;
103
104- if (--psi->use == 0)
105- module_put(psi->pst.module);
106-
107- BUG_ON(psi->use < 0);
108-
109+ module_put(psi->pst.module);
110 out:
111 up_read(&_ps_lock);
112 }
113@@ -135,11 +125,6 @@ int dm_unregister_path_selector(struct p
114 return -EINVAL;
115 }
116
117- if (psi->use) {
118- up_write(&_ps_lock);
119- return -ETXTBSY;
120- }
121-
122 list_del(&psi->list);
123
124 up_write(&_ps_lock);