File: debug_locks.sh

package info (click to toggle)
samba 2:4.5.16+dfsg-1+deb9u2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 119,272 kB
  • sloc: ansic: 1,353,805; xml: 120,204; python: 119,437; sh: 36,510; perl: 29,946; asm: 3,281; yacc: 2,332; cpp: 2,225; ada: 1,681; exp: 1,582; makefile: 1,365; pascal: 1,089; cs: 879; lex: 603; awk: 118; csh: 58; sed: 45
file content (87 lines) | stat: -rwxr-xr-x 2,891 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#!/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"

# Default fallback location for database directories.
# These can be overwritten from CTDB configuration
CTDB_DBDIR="${CTDB_VARDIR}"
CTDB_DBDIR_PERSISTENT="${CTDB_VARDIR}/persistent"

loadconfig ctdb

(
    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=$( grep -F "POSIX  ADVISORY  WRITE" /proc/locks |
    awk '{ if($2 == "->") { print $6, $7, $8, $9, "W" } else { print $5, $6, $7, $8 } }' |
    while read pid rest ; do
	pname=$(readlink "/proc/${pid}/exe")
	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
	# Use word splitting to squash whitespace
	# shellcheck disable=SC2086
	pids=$(echo $all_pids | tr " " "\n" | sort -u)

	# For each process waiting, log stack trace
	for pid in $pids ; do
	    echo "----- Stack trace for PID=$pid -----"
	    # x is intentionally ignored
	    # shellcheck disable=SC2034
	    read x x state x <"/proc/${pid}/stat"
	    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"
		cat "/proc/${pid}/stack"
	    else
		gstack "$pid"
		# gcore -o /var/log/core-deadlock-ctdb $pid
	    fi
	done
    fi

    echo "===== End of debug locks PID=$$ ====="
)9>"${CTDB_SCRIPT_VARDIR}/debug_locks.lock" | script_log "ctdbd-lock"

exit 0