]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - tools/xfsbuflock.py
3 # SPDX-License-Identifier: GPL-2.0+
4 # Copyright (C) 2016 Oracle. All Rights Reserved.
6 # Author: Darrick J. Wong <darrick.wong@oracle.com>
8 # Read ftrace input, looking for XFS buffer deadlocks.
10 # Rough guide to using this script:
11 # Collect ftrace data from a deadlock:
13 # # trace-cmd record -e 'xfs_buf_*lock*' <other traces> &
14 # <run command, hang system>^Z
15 # # killall -INT trace-cmd
16 # <wait for trace-cmd to spit out trace.dat>
18 # Now analyze the captured trace data:
20 # # trace-cmd report | xfsbuflock.py
23 # 3732.005575: xfs_buf_trylock_fail: dev 8:16 bno 0x1 nblks 0x1 hold 4 \
24 # pincount 1 lock 0 flags DONE|KMEM caller 0xc009af36s
26 # dev 8:16 bno 0x64c371 nblks 0x1 lock 1 owner fsx-14956@3732.005567
28 # dev 8:16 bno 0x64c380 nblks 0x8 lock 1 owner fsx-14956@3732.005571
29 # dev 8:16 bno 0x64c378 nblks 0x8 lock 1 owner fsx-14956@3732.005570
32 # 3732.005592: xfs_buf_trylock_fail: dev 8:16 bno 0x64c371 nblks 0x1 hold 4 \
33 # pincount 1 lock 0 flags ASYNC|DONE|KMEM caller 0xc009af36s
35 # dev 8:16 bno 0x8 nblks 0x8 lock 1 owner fsx-14954@3732.005583
36 # dev 8:16 bno 0x1 nblks 0x1 lock 1 owner fsx-14954@3732.005574
40 # dev 8:16 bno 0x10 nblks 0x8 lock 1 owner fsx-14954@3732.005585
42 # As you can see, fsx-14596 is locking AGFs in violation of the locking
47 from collections
import namedtuple
52 def __init__(self
, pid
):
55 self
.locked_bufs
= set()
59 print('=== %s ===' % self
.pid
)
60 for bt
in self
.backtrace
:
61 print('%f: %s' % (bt
.time
, bt
.descr
))
62 print('Locked buffers:')
63 for buf
in self
.locked_bufs
:
67 def __init__(self
, dev
, bno
, blen
):
69 self
.bno
= int(bno
, 0)
70 self
.blen
= int(blen
, 0)
77 def trylock(self
, process
, time
):
79 self
.lockdone(process
, time
)
81 def init(self
, process
, time
):
82 # Buffers are initialized locked, but we could be allocating
83 # a surplus buffer while trying to grab a buffer that may or
84 # may not already exist.
86 self
.lockdone(process
, time
)
88 def lockdone(self
, process
, time
):
90 print('Buffer 0x%x already locked at line %d? (line %d)' % \
91 (self
.bno
, self
.lockline
, nr
))
95 if process
in self
.waiters
:
96 self
.waiters
.remove(process
)
101 process
.locked_bufs
.add(self
)
102 process
.bufs
.add(self
)
103 locked_buffers
.add(self
)
105 def waitlock(self
, process
):
106 self
.waiters
.add(process
)
110 if self
in locked_buffers
:
111 locked_buffers
.remove(self
)
112 if self
.owner
is not None and \
113 self
in self
.owner
.locked_bufs
:
114 self
.owner
.locked_bufs
.remove(self
)
117 if self
.owner
is not None:
118 pid
= '%s@%f (line %d)' % \
119 (self
.owner
.pid
, self
.locktime
, self
.lockline
)
122 print('dev %s bno 0x%x nblks 0x%x lock %d owner %s' % \
123 (self
.dev
, self
.bno
, self
.blen
, self
.locked
, \
125 for proc
in self
.waiters
:
126 print(' waiting: %s' % proc
.pid
)
128 Event
= namedtuple('Event', 'time descr')
130 # Read ftrace input, looking for events and for buffer lock info
133 locked_buffers
= set()
136 if int(toks
[7], 0) == 18446744073709551615:
138 bufkey
= ' '.join(toks
[4:10])
139 if bufkey
in buffers
:
140 return buffers
[bufkey
]
141 buf
= Buffer(toks
[5], toks
[7], toks
[9])
142 buffers
[bufkey
] = buf
146 for line
in fileinput
.input():
153 time
= float(toks
[2][:-1])
159 proc
= processes
[pid
]
162 processes
[pid
] = proc
164 if fn
== 'xfs_buf_unlock' or fn
== 'xfs_buf_item_unlock_stale':
168 elif fn
== 'xfs_buf_lock_done':
171 buf
.lockdone(proc
, time
)
172 elif fn
== 'xfs_buf_lock':
176 elif fn
== 'xfs_buf_trylock':
179 buf
.trylock(proc
, time
)
180 elif fn
== 'xfs_buf_init':
184 elif fn
== 'xfs_buf_item_unlock':
187 e
= Event(time
, ' '.join(toks
[3:]))
188 proc
.backtrace
.append(e
)
189 if len(proc
.backtrace
) > NR_BACKTRACE
:
190 proc
.backtrace
.pop(0)
193 for buf
in locked_buffers
:
194 deadlocked
.add(buf
.owner
)
196 for proc
in deadlocked
:
204 print('dev %s bno 0x%x len 0x%x owner %s' % (buf
.dev
, buf
.bno
, buf
.blen
, buf
.owner
.pid
))
206 print('dev %s bno 0x%x len 0x%x' % (buf
.dev
, buf
.bno
, buf
.blen
))
210 for pid
in processes
:
211 proc
= processes
[pid
]