From dd5972b69916fa08b114193d644faf3ae58c550b Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 4 Jan 2021 13:35:11 +1100 Subject: ctdb-scripts: Simplify logic in debug_via_proc_locks() The path of the TDB is known, so calculate the file ID (device number + inode number) from it and use this to directly filter /proc/locks to find processes holding locks. Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs --- ctdb/config/debug_locks.sh | 90 ++++++++++++++-------- .../tests/UNIT/eventscripts/scripts/debug_locks.sh | 21 ++--- ctdb/tests/UNIT/eventscripts/stubs/stat | 18 +++++ 3 files changed, 89 insertions(+), 40 deletions(-) (limited to 'ctdb') diff --git a/ctdb/config/debug_locks.sh b/ctdb/config/debug_locks.sh index 892889e86be..1fcb2f70d17 100755 --- a/ctdb/config/debug_locks.sh +++ b/ctdb/config/debug_locks.sh @@ -75,40 +75,70 @@ dump_stacks () done } +get_tdb_file_id () +{ + if ! _device_inode=$(stat -c "%d:%i" "$tdb_path" 2>/dev/null) ; then + die "Unable to stat \"${tdb_path}\"" + fi + _device="${_device_inode%%:*}" + _device_major=$((_device >> 8)) + _device_minor=$((_device & 0xff)) + _inode="${_device_inode#*:}" + printf '%02x:%02x:%u\n' "$_device_major" "$_device_minor" "$_inode" +} + debug_via_proc_locks () { - # 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 + # Get file ID to match relevant column in /proc/locks + _file_id=$(get_tdb_file_id) + + # Log information from /proc/locks about the waiting process + _tdb=$(basename "$tdb_path") + _comm=$(ps -p "$lock_helper_pid" -o comm=) + _out=$(get_proc "locks" | + awk -v pid="$lock_helper_pid" \ + -v file_id="$_file_id" \ + -v file="$_tdb" \ + -v comm="$_comm" \ + '$2 == "->" && + $3 == "POSIX" && + $4 == "ADVISORY" && + $5 == "WRITE" && + $6 == pid && + $7 == file_id { print $6, comm, file, $8, $9 }') + if [ -n "$_out" ] ; then + echo "Waiter:" + echo "$_out" + fi + + # Parse /proc/locks and find process holding locks on $tdb_path + # extract following information + # pid process_name tdb_name offsets + _out=$(get_proc "locks" | + awk -v pid="$lock_helper_pid" \ + -v file_id="$_file_id" \ + -v file="$_tdb" \ + '$2 == "POSIX" && + $3 == "ADVISORY" && + $4 == "WRITE" && + $5 != pid && + $6 == file_id { print $5, file, $7, $8 }' | + while read -r _pid _rest ; do + _pname=$(ps -p "$_pid" -o comm=) + echo "$_pid $_pname $_rest" + done) + + if [ -z "$_out" ]; then + return + fi + # 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 + echo "Lock holders:" + echo "$_out" + + _pids=$(echo "$_out" | awk '{ print $1 }') - lock_holder_pids="${lock_holder_pids:+${lock_holder_pids} }${all_pids}" - fi + lock_holder_pids="${lock_holder_pids:+${lock_holder_pids} }${_pids}" } ( diff --git a/ctdb/tests/UNIT/eventscripts/scripts/debug_locks.sh b/ctdb/tests/UNIT/eventscripts/scripts/debug_locks.sh index d9c3df76d57..162dc21b2ac 100644 --- a/ctdb/tests/UNIT/eventscripts/scripts/debug_locks.sh +++ b/ctdb/tests/UNIT/eventscripts/scripts/debug_locks.sh @@ -168,25 +168,26 @@ EOF ' _db="locking.tdb.${FAKE_CTDB_PNN}" - _pids='' + if [ -n "$_helper_lock" ] ; then + read -r _ _ _ _ _pid _ _start _end <