]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From 5fd3a17ed456637a224cf4ca82b9ad9d005bc8d4 Mon Sep 17 00:00:00 2001 |
2 | From: Dan Williams <dan.j.williams@intel.com> | |
3 | Date: Wed, 4 Mar 2009 00:57:25 -0700 | |
4 | Subject: [PATCH] md: fix deadlock when stopping arrays | |
5 | ||
6 | Resolve a deadlock when stopping redundant arrays, i.e. ones that | |
7 | require a call to sysfs_remove_group when shutdown. The deadlock is | |
8 | summarized below: | |
9 | ||
10 | Thread1 Thread2 | |
11 | ------- ------- | |
12 | read sysfs attribute stop array | |
13 | take mddev lock | |
14 | sysfs_remove_group | |
15 | sysfs_get_active | |
16 | wait for mddev lock | |
17 | wait for active | |
18 | ||
19 | Sysrq-w: | |
20 | -------- | |
21 | mdmon S 00000017 2212 4163 1 | |
22 | f1982ea8 00000046 2dcf6b85 00000017 c0b23100 f2f83ed0 c0b23100 f2f8413c | |
23 | c0b23100 c0b23100 c0b1fb98 f2f8413c 00000000 f2f8413c c0b23100 f2291ecc | |
24 | 00000002 c0b23100 00000000 00000017 f2f83ed0 f1982eac 00000046 c044d9dd | |
25 | Call Trace: | |
26 | [<c044d9dd>] ? debug_mutex_add_waiter+0x1d/0x58 | |
27 | [<c06ef451>] __mutex_lock_common+0x1d9/0x338 | |
28 | [<c06ef451>] ? __mutex_lock_common+0x1d9/0x338 | |
29 | [<c06ef5e3>] mutex_lock_interruptible_nested+0x33/0x3a | |
30 | [<c0634553>] ? mddev_lock+0x14/0x16 | |
31 | [<c0634553>] mddev_lock+0x14/0x16 | |
32 | [<c0634eda>] md_attr_show+0x2a/0x49 | |
33 | [<c04e9997>] sysfs_read_file+0x93/0xf9 | |
34 | mdadm D 00000017 2812 4177 1 | |
35 | f0401d78 00000046 430456f8 00000017 f0401d58 f0401d20 c0b23100 f2da2c4c | |
36 | c0b23100 c0b23100 c0b1fb98 f2da2c4c 0a10fc36 00000000 c0b23100 f0401d70 | |
37 | 00000003 c0b23100 00000000 00000017 f2da29e0 00000001 00000002 00000000 | |
38 | Call Trace: | |
39 | [<c06eed1b>] schedule_timeout+0x1b/0x95 | |
40 | [<c06eed1b>] ? schedule_timeout+0x1b/0x95 | |
41 | [<c06eeb97>] ? wait_for_common+0x34/0xdc | |
42 | [<c044fa8a>] ? trace_hardirqs_on_caller+0x18/0x145 | |
43 | [<c044fbc2>] ? trace_hardirqs_on+0xb/0xd | |
44 | [<c06eec03>] wait_for_common+0xa0/0xdc | |
45 | [<c0428c7c>] ? default_wake_function+0x0/0x12 | |
46 | [<c06eeccc>] wait_for_completion+0x17/0x19 | |
47 | [<c04ea620>] sysfs_addrm_finish+0x19f/0x1d1 | |
48 | [<c04e920e>] sysfs_hash_and_remove+0x42/0x55 | |
49 | [<c04eb4db>] sysfs_remove_group+0x57/0x86 | |
50 | [<c0638086>] do_md_stop+0x13a/0x499 | |
51 | ||
52 | This has been there for a while, but is easier to trigger now that mdmon | |
53 | is closely watching sysfs. | |
54 | ||
55 | Cc: <stable@kernel.org> | |
56 | Reported-by: Jacek Danecki <jacek.danecki@intel.com> | |
57 | Signed-off-by: Dan Williams <dan.j.williams@intel.com> | |
58 | Acked-by: NeilBrown <neilb@suse.de> | |
59 | --- | |
60 | drivers/md/md.c | 10 +++++++--- | |
61 | 1 file changed, 7 insertions(+), 3 deletions(-) | |
62 | ||
63 | --- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c | |
64 | +++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c | |
65 | @@ -305,9 +305,14 @@ static inline int mddev_trylock(mddev_t | |
66 | return mutex_trylock(&mddev->reconfig_mutex); | |
67 | } | |
68 | ||
69 | +static struct attribute_group md_redundancy_group; | |
70 | static inline void mddev_unlock(mddev_t * mddev) | |
71 | { | |
72 | mutex_unlock(&mddev->reconfig_mutex); | |
73 | + if (unlikely(mddev->private == &md_redundancy_group)) { | |
74 | + sysfs_remove_group(&mddev->kobj, &md_redundancy_group); | |
75 | + mddev->private = NULL; | |
76 | + } | |
77 | ||
78 | md_wakeup_thread(mddev->thread); | |
79 | } | |
80 | @@ -3905,10 +3910,9 @@ static int do_md_stop(mddev_t * mddev, i | |
81 | mddev->queue->merge_bvec_fn = NULL; | |
82 | mddev->queue->unplug_fn = NULL; | |
83 | mddev->queue->backing_dev_info.congested_fn = NULL; | |
84 | - if (mddev->pers->sync_request) | |
85 | - sysfs_remove_group(&mddev->kobj, &md_redundancy_group); | |
86 | - | |
87 | module_put(mddev->pers->owner); | |
88 | + if (mddev->pers->sync_request) | |
89 | + mddev->private = &md_redundancy_group; | |
90 | mddev->pers = NULL; | |
91 | /* tell userspace to handle 'inactive' */ | |
92 | sysfs_notify(&mddev->kobj, NULL, "array_state"); |