diff options
author | Mikulas Patocka <mpatocka@redhat.com> | 2009-12-10 18:51:52 -0500 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2009-12-10 18:51:52 -0500 |
commit | 6076905b5ef39e0ea58db32583c9e0036c05e47b (patch) | |
tree | 918a8da9778d93e8ff6aff6497eb698d7a45edab /drivers/md/dm-uevent.c | |
parent | 3067e02f8f3ae2f3f02ba76400d03b8bcb4942b0 (diff) |
dm: avoid _hash_lock deadlock
Fix a reported deadlock if there are still unprocessed multipath events
on a device that is being removed.
_hash_lock is held during dev_remove while trying to send the
outstanding events. Sending the events requests the _hash_lock
again in dm_copy_name_and_uuid.
This patch introduces a separate lock around regions that modify the
link to the hash table (dm_set_mdptr) or the name or uuid so that
dm_copy_name_and_uuid no longer needs _hash_lock.
Additionally, dm_copy_name_and_uuid can only be called if md exists
so we can drop the dm_get() and dm_put() which can lead to a BUG()
while md is being freed.
The deadlock:
#0 [ffff8106298dfb48] schedule at ffffffff80063035
#1 [ffff8106298dfc20] __down_read at ffffffff8006475d
#2 [ffff8106298dfc60] dm_copy_name_and_uuid at ffffffff8824f740
#3 [ffff8106298dfc90] dm_send_uevents at ffffffff88252685
#4 [ffff8106298dfcd0] event_callback at ffffffff8824c678
#5 [ffff8106298dfd00] dm_table_event at ffffffff8824dd01
#6 [ffff8106298dfd10] __hash_remove at ffffffff882507ad
#7 [ffff8106298dfd30] dev_remove at ffffffff88250865
#8 [ffff8106298dfd60] ctl_ioctl at ffffffff88250d80
#9 [ffff8106298dfee0] do_ioctl at ffffffff800418c4
#10 [ffff8106298dff00] vfs_ioctl at ffffffff8002fab9
#11 [ffff8106298dff40] sys_ioctl at ffffffff8004bdaf
#12 [ffff8106298dff80] tracesys at ffffffff8005d28d (via system_call)
Cc: stable@kernel.org
Reported-by: guy keren <choo@actcom.co.il>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md/dm-uevent.c')
-rw-r--r-- | drivers/md/dm-uevent.c | 9 |
1 files changed, 4 insertions, 5 deletions
diff --git a/drivers/md/dm-uevent.c b/drivers/md/dm-uevent.c index 6f65883aef12..c7c555a8c7b2 100644 --- a/drivers/md/dm-uevent.c +++ b/drivers/md/dm-uevent.c | |||
@@ -139,14 +139,13 @@ void dm_send_uevents(struct list_head *events, struct kobject *kobj) | |||
139 | list_del_init(&event->elist); | 139 | list_del_init(&event->elist); |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * Need to call dm_copy_name_and_uuid from here for now. | 142 | * When a device is being removed this copy fails and we |
143 | * Context of previous var adds and locking used for | 143 | * discard these unsent events. |
144 | * hash_cell not compatable. | ||
145 | */ | 144 | */ |
146 | if (dm_copy_name_and_uuid(event->md, event->name, | 145 | if (dm_copy_name_and_uuid(event->md, event->name, |
147 | event->uuid)) { | 146 | event->uuid)) { |
148 | DMERR("%s: dm_copy_name_and_uuid() failed", | 147 | DMINFO("%s: skipping sending uevent for lost device", |
149 | __func__); | 148 | __func__); |
150 | goto uevent_free; | 149 | goto uevent_free; |
151 | } | 150 | } |
152 | 151 | ||