linux/drivers/edac
Harry Ciao d519c8d9cc edac: fix edac core deadlock when removing a device
When deleting an edac device, we have to wait for its edac_dev.work to be
completed before deleting the whole edac_dev structure.  Since we have no
idea which work in current edac_poller's workqueue is the work we are
conerned about, we wait for all work in the edac_poller's workqueue to be
proceseed.  This is done via flush_cpu_workqueue() which inserts a
wq_barrier into the tail of the workqueue and then sleeping on the
completion of this wq_barrier.  The edac_poller will wake up sleepers when
it is found.

EDAC core creates only one kernel worker thread, edac_poller, to run the
works of all current edac devices.  They share the same callback function
of edac_device_workq_function(), which would grab the mutex of
device_ctls_mutex first before it checks the device.  This is exactly
where edac_poller and rmmod would have a great chance to deadlock.

In below call trace of rmmod > ... >
edac_device_del_device >
edac_device_workq_teardown > flush_workqueue > flush_cpu_workqueue,

device_ctls_mutex would have already been grabbed by
edac_device_del_device().  So, on one hand rmmod would sleep on the
completion of a wq_barrier, holding device_ctls_mutex; on the other hand
edac_poller would be blocked on the same mutex when it's running any one
of works of existing edac evices(Note, this edac_dev.work is likely to be
totally irrelevant to the one that is being removed right now)and never
would have a chance to run the work of above wq_barrier to wake rmmod up.

edac_device_workq_teardown() should not be called within the critical
region of device_ctls_mutex.  Just like is done in edac_pci_del_device()
and edac_mc_del_mc(), where edac_pci_workq_teardown() and
edac_mc_workq_teardown() are called after related mutex are released.

Moreover, an edac_dev.work should check first if it is being removed.  If
this is the case, then it should bail out immediately.  Since not all of
existing edac devices are to be removed, this "shutting flag" should be
contained to edac device being removed.  The current edac_dev.op_state can
be used to serve this purpose.

The original deadlock problem and the solution have been witnessed and
tested on actual hardware.  Without the solution, rmmod an edac driver
would result in below deadlock:

root@localhost:/root> rmmod mv64x60_edac
EDAC DEBUG: mv64x60_dma_err_remove()
EDAC DEBUG: edac_device_del_device()
EDAC DEBUG: find_edac_device_by_dev()

(hang for a moment)

INFO: task edac-poller:2030 blocked for more than 120 seconds.
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
edac-poller   D 00000000     0  2030      2
Call Trace:
[df159dc0] [c0071e3c] free_hot_cold_page+0x17c/0x304 (unreliable)
[df159e80] [c000a024] __switch_to+0x6c/0xa0
[df159ea0] [c03587d8] schedule+0x2f4/0x4d8
[df159f00] [c03598a8] __mutex_lock_slowpath+0xa0/0x174
[df159f40] [e1030434] edac_device_workq_function+0x28/0xd8 [edac_core]
[df159f60] [c003beb4] run_workqueue+0x114/0x218
[df159f90] [c003c674] worker_thread+0x5c/0xc8
[df159fd0] [c004106c] kthread+0x5c/0xa0
[df159ff0] [c0013538] original_kernel_thread+0x44/0x60
INFO: task rmmod:2062 blocked for more than 120 seconds.
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
rmmod         D 0ff2c9fc     0  2062   1839
Call Trace:
[df119c00] [c0437a74] 0xc0437a74 (unreliable)
[df119cc0] [c000a024] __switch_to+0x6c/0xa0
[df119ce0] [c03587d8] schedule+0x2f4/0x4d8
[df119d40] [c03591dc] schedule_timeout+0xb0/0xf4

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-12-23 15:58:21 -08:00
..
amd76x_edac.c edac: fix module initialization on several modules 2nd time 2008-04-29 08:06:26 -07:00
cell_edac.c edac: fix enabling of polling cell module 2008-10-30 11:38:46 -07:00
e7xxx_edac.c edac: fix module initialization on several modules 2nd time 2008-04-29 08:06:26 -07:00
e752x_edac.c edac: e752x fix too loud on nonmemory errors 2008-07-25 10:53:49 -07:00
edac_core.h removed unused #include <linux/version.h>'s 2008-08-23 12:14:12 -07:00
edac_device_sysfs.c Kobject: convert drivers/* from kobject_unregister() to kobject_put() 2008-01-24 20:40:40 -08:00
edac_device.c edac: fix edac core deadlock when removing a device 2008-12-23 15:58:21 -08:00
edac_mc_sysfs.c edac: core fix added newline to sysfs dimm labels 2008-07-25 10:53:49 -07:00
edac_mc.c dev_name introduction fall out fix 2008-05-05 15:08:38 -07:00
edac_module.c Driver core: change sysdev classes to use dynamic kobject names 2008-01-24 20:40:40 -08:00
edac_module.h edac: remove unneeded functions and add static accessor 2008-04-29 08:06:26 -07:00
edac_pci_sysfs.c edac: core fix to use dynamic kobject 2008-07-25 10:53:48 -07:00
edac_pci.c dev_name introduction fall out fix 2008-05-05 15:08:38 -07:00
edac_stub.c drivers/edac: code tidying on export-gpl 2007-07-19 10:04:57 -07:00
i3000_edac.c edac: fix module initialization on several modules 2nd time 2008-04-29 08:06:26 -07:00
i5000_edac.c i5000-edac: hold reference to mci kobject 2008-11-12 17:17:16 -08:00
i5100_edac.c edac: i5100: cleanup 2008-07-25 10:53:48 -07:00
i82443bxgx_edac.c edac: make i82443bxgx_edac coexist with intel_agp 2008-10-16 11:21:48 -07:00
i82860_edac.c edac: fix module initialization on several modules 2nd time 2008-04-29 08:06:26 -07:00
i82875p_edac.c i82875p_edac: fix module remove 2008-12-01 19:55:25 -08:00
i82975x_edac.c edac: fix module initialization on several modules 2nd time 2008-04-29 08:06:26 -07:00
Kconfig edac x38: new MC driver module 2008-10-30 11:38:45 -07:00
Makefile edac x38: new MC driver module 2008-10-30 11:38:45 -07:00
mpc85xx_edac.c edac mpc85xx: add support for mpc8572 2008-10-16 11:21:48 -07:00
mpc85xx_edac.h drivers-edac: add freescale mpc85xx driver 2008-02-07 08:42:23 -08:00
mv64x60_edac.c edac: mv64x60 add pci fixup 2008-07-25 10:53:49 -07:00
mv64x60_edac.h drivers-edac: add marvell mv64x60 driver 2008-02-07 08:42:23 -08:00
pasemi_edac.c pasemi_edac needs to include linux/edac.h 2008-04-29 19:06:57 -07:00
r82600_edac.c edac: fix module initialization on several modules 2nd time 2008-04-29 08:06:26 -07:00
x38_edac.c edac x38: new MC driver module 2008-10-30 11:38:45 -07:00