Whamcloud - gitweb
LU-12461 contrib: Add epython scripts for crash dump analysis
[fs/lustre-release.git] / contrib / debug_tools / epython_scripts / ldlm_dumplocks.py
diff --git a/contrib/debug_tools/epython_scripts/ldlm_dumplocks.py b/contrib/debug_tools/epython_scripts/ldlm_dumplocks.py
new file mode 100644 (file)
index 0000000..2f695d2
--- /dev/null
@@ -0,0 +1,157 @@
+#!/usr/bin/env python
+
+"""
+Copyright 2015-2019 Cray Inc.  All Rights Reserved
+Utility to list granted and waiting ldlm locks.
+"""
+
+from pykdump.API import *
+import argparse
+import os
+
+import lustrelib as ll
+from crashlib.input import toint
+
+from traceback import print_exc
+
+description = "Dumps lists of granted and waiting ldlm locks for each namespace."
+
+''' Lock Types '''
+enum_LDLM_PLAIN = 10
+enum_LDLM_EXTENT = 11
+enum_LDLM_FLOCK = 12
+enum_LDLM_IBITS = 13
+
+LOCKMODES = {
+    0:"--",
+    1:"EX",
+    2:"PW",
+    4:"PR",
+    8:"CW",
+    16:"CR",
+    32:"NL",
+    64:"GROUP"
+}
+
+def lockmode2str(mode):
+    return LOCKMODES.get(mode, "??")
+
+def ldlm_dump_lock(lock, pos, lstname):
+    obd = None
+    imp = None
+    if(lock == None):
+        print "   NULL LDLM lock"
+        return
+    print "   -- Lock: (ldlm_lock) %#x/%#x (rc: %d) (pos: %d/%s) (pid: %d)" % \
+          (Addr(lock), lock.l_handle.h_cookie, lock.l_refc.counter,
+          pos, lstname, lock.l_pid)
+    if(lock.l_conn_export):
+        obd = lock.l_conn_export.exp_obd
+    if(lock.l_export and lock.l_export.exp_connection):
+        print "       Node: NID %s (remote: %#x) export" % \
+              (ll.nid2str(lock.l_export.exp_connection.c_peer.nid),
+              lock.l_remote_handle.cookie)
+    elif(obd == None):
+        print "       Node: local"
+    else:
+        imp = obd.u.cli.cl_import
+        print "       Node: NID %s (remote: %#x) import " % \
+              (ll.nid2str(imp.imp_connection.c_peer.nid),
+              lock.l_remote_handle.cookie)
+
+    res = lock.l_resource
+    print "       Resource: %#x [0x%x:0x%x:0x%x].%x" % \
+          (Addr(res),
+          res.lr_name.name[0],
+          res.lr_name.name[1],
+          res.lr_name.name[2],
+          res.lr_name.name[3])
+
+    print "       Req mode: %s, grant mode: %s, rc: %d, read: %d, \
+          write: %d flags: %#x" % (lockmode2str(lock.l_req_mode),
+          lockmode2str(lock.l_granted_mode),
+          lock.l_refc.counter, lock.l_readers, lock.l_writers,
+          lock.l_flags)
+
+    lr_type = lock.l_resource.lr_type
+    if(lr_type == enum_LDLM_EXTENT):
+        print "       Extent: %d -> %d (req %d-%d)" % \
+              (lock.l_policy_data.l_extent.start,
+              lock.l_policy_data.l_extent.end,
+              lock.l_req_extent.start, lock.l_req_extent.end)
+    elif(lr_type == enum_LDLM_FLOCK):
+        print "       Pid: %d Flock: 0x%x -> 0x%x" % \
+              (lock.l_policy_data.l_flock.pid,
+              lock.l_policy_data.l_flock.start,
+              lock.l_policy_data.l_flock.end)
+    elif(lr_type == enum_LDLM_IBITS):
+        print "       Bits: %#x" % \
+              (lock.l_policy_data.l_inodebits.bits)
+
+def ldlm_dump_resource(res):
+    res_lr_granted = readSU('struct list_head', Addr(res.lr_granted))
+    res_lr_waiting = readSU('struct list_head', Addr(res.lr_waiting))
+    print "-- Resource: (ldlm_resource) %#x [0x%x:0x%x:0x%x].%x (rc: %d)" % \
+          (Addr(res), res.lr_name.name[0], res.lr_name.name[1],
+           res.lr_name.name[2], res.lr_name.name[3], res.lr_refcount.counter)
+    if not ll.list_empty(res_lr_granted):
+        pos = 0
+        print "   Granted locks: "
+        tmp = res_lr_granted.next
+        while(tmp != res_lr_granted):
+            pos += 1
+            lock = readSU('struct ldlm_lock',
+                          Addr(tmp)-member_offset('struct ldlm_lock', 'l_res_link'))
+            ldlm_dump_lock(lock, pos, "grnt")
+            tmp = tmp.next
+    if not ll.list_empty(res_lr_waiting):
+        pos = 0
+        print "   Waiting locks: "
+        tmp = res_lr_waiting.next
+        while(tmp != res_lr_waiting):
+            pos += 1
+            lock = readSU('struct ldlm_lock',
+                          Addr(tmp)-member_offset('struct ldlm_lock', 'l_res_link'))
+            ldlm_dump_lock(lock, pos, "wait")
+            tmp = tmp.next
+
+def print_namespace(ns, client_server):
+    print "Namespace: (ldlm_namespace) %#x, %s\t(rc: %d, side: %s)\tpoolcnt: %d unused: %d" % \
+          (Addr(ns), ll.obd2str(ns.ns_obd), ns.ns_bref.counter,
+          client_server, ns.ns_pool.pl_granted.counter, ns.ns_nr_unused)
+
+def ldlm_dump_ns_resources(ns):
+    if args.nflag:
+        return
+    for hnode in ll.cfs_hash_get_nodes(ns.ns_rs_hash):
+        offset = member_offset('struct ldlm_resource', 'lr_hash')
+        res = readSU('struct ldlm_resource', Addr(hnode) - offset)
+        ldlm_dump_resource(res)
+
+def ldlm_dump_all_namespaces(ns_name, client_server):
+    ns_list = readSymbol(ns_name)
+    for ns in readSUListFromHead(ns_list, 'ns_list_chain', 'struct ldlm_namespace'):
+        print_namespace(ns, client_server)
+        ldlm_dump_ns_resources(ns)
+
+def ldlm_dumplocks():
+    if args.ns_addr:
+        ns = readSU('struct ldlm_namespace', args.ns_addr)
+        print_namespace(ns, "")
+        ldlm_dump_ns_resources(ns)
+    else:
+        ldlm_dump_all_namespaces('ldlm_srv_namespace_list', "server")
+        ldlm_dump_all_namespaces('ldlm_cli_active_namespace_list', "client")
+        ldlm_dump_all_namespaces('ldlm_cli_inactive_namespace_list', "inactive")
+
+if __name__ == "__main__":
+    description = "Dumps lists of granted and waiting locks for each namespace. " + \
+                  "Requires Lustre .ko files to be loaded (see mod command)."
+    parser = argparse.ArgumentParser(description=description)
+    parser.add_argument("-n", dest="nflag", action='store_true',
+        help="Print only namespace information")
+    parser.add_argument("ns_addr", nargs="?", default=[], type=toint,
+        help="Print only locks under namespace at given address")
+    args = parser.parse_args()
+
+    ldlm_dumplocks()