]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
ctdb-scripts: Simplify logic in debug_via_proc_locks()
authorMartin Schwenke <martin@meltin.net>
Mon, 4 Jan 2021 02:35:11 +0000 (13:35 +1100)
committerAmitay Isaacs <amitay@samba.org>
Fri, 28 May 2021 06:46:29 +0000 (06:46 +0000)
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 <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
ctdb/config/debug_locks.sh
ctdb/tests/UNIT/eventscripts/scripts/debug_locks.sh
ctdb/tests/UNIT/eventscripts/stubs/stat

index 892889e86beab6e296f012014589cc135b7d7ee5..1fcb2f70d17bcb7bef5e3be11c66cc604e9f0902 100755 (executable)
@@ -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}"
 }
 
 (
index d9c3df76d573ec935d5089fad1e0c9ddabe2d07e..162dc21b2ac74a70dc21b8fbbff70fe3f08414fb 100644 (file)
@@ -168,25 +168,26 @@ EOF
 '
        _db="locking.tdb.${FAKE_CTDB_PNN}"
 
-       _pids=''
+       if [ -n "$_helper_lock" ] ; then
+               read -r _ _ _ _ _pid _ _start _end <<EOF
+$_helper_lock
+EOF
+               _out="Waiter:${_nl}"
+               _out="${_out}${_pid} ctdb_lock_helpe ${_db} ${_start} ${_end}"
+       fi
+
        # fake lock info
+       _pids=''
+       _out="${_out:+${_out}${_nl}}Lock holders:"
        while read -r _ _ _  _pid _ _start _end ; do
                _comm="smbd"
-               _out="${_out:+${_out}${_nl}}"
+               _out="${_out}${_nl}"
                _out="${_out}${_pid} smbd ${_db} ${_start} ${_end}"
                _pids="${_pids:+${_pids} }${_pid}"
        done <<EOF
 $_holder_lock
 EOF
 
-       if [ -n "$_helper_lock" ] ; then
-               read -r _ _ _ _ _pid _ _start _end <<EOF
-$_helper_lock
-EOF
-               _out="${_out}${_nl}"
-               _out="${_out}${_pid} ctdb_lock_helpe ${_db} ${_start} ${_end} W"
-       fi
-
        # fake stack traces
        for _pid in $_pids ; do
                _comm="smbd"
index 04c654883d25638171e11cb3c803649af33301ff..71508f6795df635d9f8250bf39f4c5844565131e 100755 (executable)
@@ -16,6 +16,19 @@ while getopts "c:h:?" opt ; do
 done
 shift $((OPTIND - 1))
 
+fake_device_id ()
+{
+       _path="$1"
+
+       _t=$(echo "$FAKE_FILE_ID_MAP" |
+            awk -v path="${_path}" '$1 == path { print $2 }')
+       _major_minor="${_t%:*}"
+       _major="0x${_major_minor%:*}"
+       _minor="0x${_major_minor#*:}"
+       _device_id=$((_major * 256 + _minor))
+       echo "$_device_id"
+}
+
 fake_inode ()
 {
        _path="$1"
@@ -40,6 +53,11 @@ if [ -n "$format" ] ; then
                        inode=$(fake_inode "$path")
                        echo "s#[0-9a-f]*:[0-9a-f]*:${inode} #${f} #"
                        ;;
+               "%d:%i")
+                       device_id=$(fake_device_id "$path")
+                       inode=$(fake_inode "$path")
+                       echo "${device_id}:${inode}"
+                       ;;
                *)
                        echo "Unsupported format \"${format}\""
                        usage