diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2005-01-14 23:21:27 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-01-14 23:21:27 -0800 |
commit | 451321d6023ff61e143adb9743d31571682e445b (patch) | |
tree | ec4166f93b75710c80313e391c885a0ee11511e9 /arch | |
parent | f1c5697d22fb97119cb4e7c0bc82841056132cb0 (diff) | |
download | history-451321d6023ff61e143adb9743d31571682e445b.tar.gz |
[PATCH] ppc64: make HvLpEvent_unregisterHandler() work
When the iseries_veth driver module is unloaded there is the potential for
an oops and also some memory leakage.
Because the HvLpEvent_unregisterHandler() function did no synchronisation,
it was possible for the handler that was being unregistered to be running
on another CPU *after* HvLpEvent_unregisterHandler() had returned. This
could cause the iseries_veth driver to leave work in the events work queue
after the module had been unloaded. When that work was eventually executed
we got an oops.
In addition some of the data structures in the iseries_veth driver were not
being correctly freed when the module was unloaded.
This is the first patch, which makes HvLpEvent_unregisterHandler() work.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/ppc64/kernel/HvLpEvent.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/arch/ppc64/kernel/HvLpEvent.c b/arch/ppc64/kernel/HvLpEvent.c index 93eea792f907be..9802beefa2177b 100644 --- a/arch/ppc64/kernel/HvLpEvent.c +++ b/arch/ppc64/kernel/HvLpEvent.c @@ -34,10 +34,18 @@ int HvLpEvent_registerHandler( HvLpEvent_Type eventType, LpEventHandler handler int HvLpEvent_unregisterHandler( HvLpEvent_Type eventType ) { int rc = 1; + + might_sleep(); + if ( eventType < HvLpEvent_Type_NumTypes ) { if ( !lpEventHandlerPaths[eventType] ) { lpEventHandler[eventType] = NULL; rc = 0; + + /* We now sleep until all other CPUs have scheduled. This ensures that + * the deletion is seen by all other CPUs, and that the deleted handler + * isn't still running on another CPU when we return. */ + synchronize_kernel(); } } return rc; |