2014-08-13 13:52:34 +00:00
|
|
|
#!/usr/bin/stap --ldd -d /usr/sbin/libvirtd -c libvirtd
|
|
|
|
#
|
|
|
|
# Usage with installed libvirt daemon:
|
|
|
|
# stap --ldd -d /usr/sbin/libvirtd -c libvirtd \
|
|
|
|
# lock-debug.stp /usr/lib/libvirt.so
|
|
|
|
#
|
|
|
|
# If made executable; simple './lock-debug.stp' should work too.
|
|
|
|
#
|
|
|
|
# TODOs:
|
|
|
|
#
|
|
|
|
# Document usage with uninstalled daemon and libs. Assuming CWD is toplevel
|
|
|
|
# source git directory, it should be only slight modification to the following:
|
|
|
|
#
|
2018-07-07 11:57:30 +00:00
|
|
|
# ./run stap --ldd -c src/libvirtd -d src/libvirtd
|
2020-05-28 00:40:50 +00:00
|
|
|
# examples/systemtap/lock-debug.stp src/libvirt.so
|
2014-08-13 13:52:34 +00:00
|
|
|
#
|
|
|
|
# Debug RWLock mechanisms as well.
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
|
|
global mx_tolock
|
|
|
|
global mx_locked
|
|
|
|
|
|
|
|
|
|
|
|
function filter()
|
|
|
|
{
|
|
|
|
if (pid() != target())
|
|
|
|
return 1
|
|
|
|
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
probe library = process( %( $# > 0 %? @1 %: "/usr/lib/libvirt.so" %) )
|
|
|
|
{
|
|
|
|
if (filter()) next
|
|
|
|
}
|
|
|
|
|
|
|
|
probe lock = library.function("virMutexLock")
|
|
|
|
{
|
|
|
|
lockname = usymdata($m)
|
|
|
|
}
|
|
|
|
|
|
|
|
probe unlock = library.function("virMutexUnlock")
|
|
|
|
{
|
|
|
|
lockname = usymdata($m)
|
|
|
|
}
|
|
|
|
|
|
|
|
probe begin
|
|
|
|
{
|
|
|
|
%( $# > 1 %? println("error: Too many parameters"); exit();
|
2015-03-19 15:53:00 +00:00
|
|
|
%: print("Started, press ^C when the process hangs\n"); %)
|
2014-08-13 13:52:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
probe lock.call
|
|
|
|
{
|
|
|
|
mx_tolock[lockname, tid()] = sprint_usyms(ubacktrace())
|
|
|
|
}
|
|
|
|
|
|
|
|
probe lock.return
|
|
|
|
{
|
|
|
|
if ([lockname, tid()] in mx_tolock) {
|
|
|
|
mx_locked[lockname, tid()] = mx_tolock[lockname, tid()]
|
|
|
|
delete mx_tolock[lockname, tid()]
|
|
|
|
} else {
|
|
|
|
printf("internal error: lock acquired unwillingly?\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
probe unlock.call
|
|
|
|
{
|
|
|
|
found = 0
|
|
|
|
|
|
|
|
foreach ([lock, tid] in mx_locked) {
|
|
|
|
if (lock != lockname)
|
|
|
|
continue
|
|
|
|
if (tid != tid()) {
|
|
|
|
printf("Warning: lock released on different thread that locked it.\n")
|
|
|
|
printf("Lock trace:\n%s\n", mx_locked[lock, tid])
|
|
|
|
printf("Unlock trace:\n%s\n", sprint_usyms(ubacktrace()))
|
|
|
|
}
|
|
|
|
|
|
|
|
found = tid
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found && [lockname, found] in mx_locked)
|
|
|
|
delete mx_locked[lockname, found]
|
|
|
|
}
|
|
|
|
|
|
|
|
probe end
|
|
|
|
{
|
|
|
|
tmp = 0
|
|
|
|
|
|
|
|
printf("\n=============\n")
|
|
|
|
|
|
|
|
foreach (bt1 = [lock1, tid1] in mx_tolock) {
|
|
|
|
deadlock = 0
|
|
|
|
|
|
|
|
foreach (bt2 = [lock2, tid2] in mx_tolock) {
|
|
|
|
if (lock1 == lock2) {
|
|
|
|
if (!tmp++)
|
|
|
|
printf("The following locks cannot be acquired:\n")
|
|
|
|
|
|
|
|
if (!deadlock++)
|
|
|
|
printf("Lock %s was locked in thread %d with this trace:\n%s\n",
|
|
|
|
lock1, tid1, bt1)
|
|
|
|
|
|
|
|
printf("and is waiting to be locked by thread %d here:\n%s\n",
|
|
|
|
tid2, bt2)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (deadlock)
|
|
|
|
printf("---\n")
|
|
|
|
}
|
|
|
|
if (!tmp)
|
|
|
|
printf("No deadlocks found, sorry.\n")
|
|
|
|
}
|