s390/debug: Fix s390dbf lockdep problem in debug_(un)register_view()

The debug_register/unregister_view() functions call debugfs_remove()
while holding the debug_info spinlock. Because debugfs_remove() takes
a mutex and therefore can sleep this is not allowed. To fix the problem
we give up the debug_info lock before calling debugfs_remove().

The following shows the lockdep message:

[ INFO: possible circular locking dependency detected ]
-------------------------------------------------------
rmmod/4379 is trying to acquire lock:
(&sb->s_type->i_mutex_key#2){+.+.+.}, at: [<00000000003acae2>] debugfs_remove+0x5e/0xa

but task is already holding lock:
(&(&rc->lock)->rlock){-.-...}, at: [<000000000010a5ae>] debug_unregister_view+0x3a/0xd

which lock already depends on the new lock.

-> #0 (&sb->s_type->i_mutex_key#2){+.+.+.}:
[<00000000001b1644>] validate_chain+0x880/0x1154
[<00000000001b4d6c>] __lock_acquire+0x414/0xc44
[<00000000001b5c16>] lock_acquire+0xbe/0x178
[<0000000000614016>] mutex_lock_nested+0x66/0x36c
[<00000000003acae2>] debugfs_remove+0x5e/0xac
[<000000000010a620>] debug_unregister_view+0xac/0xd0
[<000003ff8002f140>] qeth_core_exit+0x48/0xf08 [qeth]
[<00000000001c35a4>] SyS_delete_module+0x1a4/0x260
[<0000000000618134>] sysc_noemu+0x22/0x28
[<000003fffd4704da>] 0x3fffd4704da

Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Michael Holzheu 2012-12-20 17:30:52 +01:00 committed by Martin Schwidefsky
parent 2a893f91f5
commit 5a334c082f
1 changed files with 7 additions and 4 deletions

View File

@ -1127,13 +1127,14 @@ debug_register_view(debug_info_t * id, struct debug_view *view)
if (i == DEBUG_MAX_VIEWS) { if (i == DEBUG_MAX_VIEWS) {
pr_err("Registering view %s/%s would exceed the maximum " pr_err("Registering view %s/%s would exceed the maximum "
"number of views %i\n", id->name, view->name, i); "number of views %i\n", id->name, view->name, i);
debugfs_remove(pde);
rc = -1; rc = -1;
} else { } else {
id->views[i] = view; id->views[i] = view;
id->debugfs_entries[i] = pde; id->debugfs_entries[i] = pde;
} }
spin_unlock_irqrestore(&id->lock, flags); spin_unlock_irqrestore(&id->lock, flags);
if (rc)
debugfs_remove(pde);
out: out:
return rc; return rc;
} }
@ -1146,9 +1147,9 @@ EXPORT_SYMBOL(debug_register_view);
int int
debug_unregister_view(debug_info_t * id, struct debug_view *view) debug_unregister_view(debug_info_t * id, struct debug_view *view)
{ {
int rc = 0; struct dentry *dentry = NULL;
int i;
unsigned long flags; unsigned long flags;
int i, rc = 0;
if (!id) if (!id)
goto out; goto out;
@ -1160,10 +1161,12 @@ debug_unregister_view(debug_info_t * id, struct debug_view *view)
if (i == DEBUG_MAX_VIEWS) if (i == DEBUG_MAX_VIEWS)
rc = -1; rc = -1;
else { else {
debugfs_remove(id->debugfs_entries[i]); dentry = id->debugfs_entries[i];
id->views[i] = NULL; id->views[i] = NULL;
id->debugfs_entries[i] = NULL;
} }
spin_unlock_irqrestore(&id->lock, flags); spin_unlock_irqrestore(&id->lock, flags);
debugfs_remove(dentry);
out: out:
return rc; return rc;
} }