#!/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()