ctdb-scripts: Be careful when generating unique pids for stack traces
[obnox/samba/samba-obnox.git] / ctdb / config / debug_locks.sh
1 #!/bin/sh
2
3 # This script parses /proc/locks and finds the processes that are holding
4 # locks on CTDB databases.  For all those processes the script dumps a
5 # stack trace using gstack.
6 #
7 # This script can be used only if Samba is configured to use fcntl locks
8 # rather than mutex locks.
9
10 [ -n "$CTDB_BASE" ] || \
11     export CTDB_BASE=$(cd -P $(dirname "$0") ; echo "$PWD")
12
13 . "$CTDB_BASE/functions"
14
15 # Default fallback location for database directories.
16 # These can be overwritten from CTDB configuration
17 CTDB_DBDIR="${CTDB_VARDIR}"
18 CTDB_DBDIR_PERSISTENT="${CTDB_VARDIR}/persistent"
19
20 loadconfig ctdb
21
22 (
23     flock -n 9 || exit 1
24
25     echo "===== Start of debug locks PID=$$ ====="
26
27     # Create sed expression to convert inodes to names
28     sed_cmd=$( ls -li "$CTDB_DBDIR"/*.tdb.* "$CTDB_DBDIR_PERSISTENT"/*.tdb.* |
29            sed -e "s#${CTDB_DBDIR}/\(.*\)#\1#" \
30                -e "s#${CTDB_DBDIR_PERSISTENT}/\(.*\)#\1#" |
31            awk '{printf "s#[0-9]*:[0-9]*:%s #%s #\n", $1, $10}' )
32
33     # Parse /proc/locks and extract following information
34     #    pid process_name tdb_name offsets [W]
35     out=$( cat /proc/locks |
36     grep -F "POSIX  ADVISORY  WRITE" |
37     awk '{ if($2 == "->") { print $6, $7, $8, $9, "W" } else { print $5, $6, $7, $8 } }' |
38     while read pid rest ; do
39         pname=$(readlink /proc/$pid/exe)
40         echo $pid $pname $rest
41     done | sed -e "$sed_cmd" | grep "\.tdb" )
42
43     if [ -n "$out" ]; then
44         # Log information about locks
45         echo "$out"
46
47         # Find processes that are waiting for locks
48         dbs=$(echo "$out" | grep "W$" | awk '{print $3}')
49         all_pids=""
50         for db in $dbs ; do
51             pids=$(echo "$out" | grep -v "W$" | grep "$db" | grep -v ctdbd | awk '{print $1}')
52             all_pids="$all_pids $pids"
53         done
54         pids=$(echo $all_pids | tr " " "\n" | sort -u)
55
56         # For each process waiting, log stack trace
57         for pid in $pids ; do
58             echo "----- Stack trace for PID=$pid -----"
59             gstack $pid
60             # gcore -o /var/log/core-deadlock-ctdb $pid
61         done
62     fi
63
64     echo "===== End of debug locks PID=$$ ====="
65
66 ) 9>"${CTDB_VARDIR}/debug_locks.lock" | script_log "ctdbd-lock"
67
68 exit 0