1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00
samba-mirror/ctdb/config/debug_locks.sh

109 lines
2.9 KiB
Bash
Raw Normal View History

#!/bin/sh
# This script parses /proc/locks and finds the processes that are holding
# locks on CTDB databases. For all those processes the script dumps a
# stack trace.
#
# This script can be used only if Samba is configured to use fcntl locks
# rather than mutex locks.
[ -n "$CTDB_BASE" ] || \
CTDB_BASE=$(d=$(dirname "$0") ; cd -P "$d" ; echo "$PWD")
. "${CTDB_BASE}/functions"
# type is at least mentioned in POSIX and more is portable than which(1)
# shellcheck disable=SC2039
if ! type gstack >/dev/null 2>&1 ; then
gstack ()
{
_pid="$1"
gdb -batch --quiet -nx "/proc/${_pid}/exe" "$_pid" \
-ex "thread apply all bt" 2>/dev/null |
grep '^\(#\|Thread \)'
}
fi
# Load/cache database options from configuration file
ctdb_get_db_options
dump_stack ()
{
_pid="$1"
echo "----- Stack trace for PID=${_pid} -----"
_state=$(ps -p "$_pid" -o state= | cut -c 1)
if [ "$_state" = "D" ] ; then
# Don't run gstack on a process in D state since
# gstack will hang until the process exits D state.
# Although it is possible for a process to transition
# to D state after this check, it is unlikely because
# if a process is stuck in D state then it is probably
# the reason why this script was called. Note that a
# kernel stack almost certainly won't help diagnose a
# deadlock... but it will probably give us someone to
# blame!
echo "----- Process in D state, printing kernel stack only"
get_proc "${_pid}/stack"
else
gstack "$_pid"
fi
}
dump_stacks ()
{
_pids="$1"
# Use word splitting to squash whitespace
# shellcheck disable=SC2086
_pids=$(echo $_pids | tr ' ' '\n' | sort -u)
for _pid in $_pids; do
dump_stack "$_pid"
done
}
(
flock -n 9 || exit 1
echo "===== Start of debug locks PID=$$ ====="
# Create sed expression to convert inodes to names.
# Filenames don't contain dashes and we want basenames
# shellcheck disable=SC2035
sed_cmd=$(cd "$CTDB_DBDIR" &&
stat -c "s#[0-9a-f]*:[0-9a-f]*:%i #%n #" *.tdb.* 2>/dev/null ;
cd "$CTDB_DBDIR_PERSISTENT" &&
stat -c "s#[0-9a-f]*:[0-9a-f]*:%i #%n #" *.tdb.* 2>/dev/null)
# Parse /proc/locks and extract following information
# pid process_name tdb_name offsets [W]
out=$( get_proc "locks" |
grep -F "POSIX ADVISORY WRITE" |
awk '{ if($2 == "->") { print $6, $7, $8, $9, "W" } else { print $5, $6, $7, $8 } }' |
while read pid rest ; do
pname=$(ps -p "$pid" -o comm=)
echo "$pid $pname $rest"
done | sed -e "$sed_cmd" | grep '\.tdb' )
if [ -n "$out" ]; then
# Log information about locks
echo "$out"
# Find processes that are waiting for locks
dbs=$(echo "$out" | grep "W$" | awk '{print $3}')
all_pids=""
for db in $dbs ; do
pids=$(echo "$out" | grep -v "W$" | grep "$db" | grep -v ctdbd | awk '{print $1}')
all_pids="$all_pids $pids"
done
dump_stacks "$all_pids"
fi
echo "===== End of debug locks PID=$$ ====="
)9>"${CTDB_SCRIPT_VARDIR}/debug_locks.lock" | script_log "ctdbd-lock"
exit 0