cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dlmdebug.c (25234B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * dlmdebug.c
      4 *
      5 * debug functionality for the dlm
      6 *
      7 * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
      8 */
      9
     10#include <linux/types.h>
     11#include <linux/slab.h>
     12#include <linux/highmem.h>
     13#include <linux/sysctl.h>
     14#include <linux/spinlock.h>
     15#include <linux/debugfs.h>
     16#include <linux/export.h>
     17
     18#include "../cluster/heartbeat.h"
     19#include "../cluster/nodemanager.h"
     20#include "../cluster/tcp.h"
     21
     22#include "dlmapi.h"
     23#include "dlmcommon.h"
     24#include "dlmdomain.h"
     25#include "dlmdebug.h"
     26
     27#define MLOG_MASK_PREFIX ML_DLM
     28#include "../cluster/masklog.h"
     29
     30static int stringify_lockname(const char *lockname, int locklen, char *buf,
     31			      int len);
     32
     33void dlm_print_one_lock_resource(struct dlm_lock_resource *res)
     34{
     35	spin_lock(&res->spinlock);
     36	__dlm_print_one_lock_resource(res);
     37	spin_unlock(&res->spinlock);
     38}
     39
     40static void dlm_print_lockres_refmap(struct dlm_lock_resource *res)
     41{
     42	int bit;
     43	assert_spin_locked(&res->spinlock);
     44
     45	printk("  refmap nodes: [ ");
     46	bit = 0;
     47	while (1) {
     48		bit = find_next_bit(res->refmap, O2NM_MAX_NODES, bit);
     49		if (bit >= O2NM_MAX_NODES)
     50			break;
     51		printk("%u ", bit);
     52		bit++;
     53	}
     54	printk("], inflight=%u\n", res->inflight_locks);
     55}
     56
     57static void __dlm_print_lock(struct dlm_lock *lock)
     58{
     59	spin_lock(&lock->spinlock);
     60
     61	printk("    type=%d, conv=%d, node=%u, cookie=%u:%llu, "
     62	       "ref=%u, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c), "
     63	       "pending=(conv=%c,lock=%c,cancel=%c,unlock=%c)\n",
     64	       lock->ml.type, lock->ml.convert_type, lock->ml.node,
     65	       dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
     66	       dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
     67	       kref_read(&lock->lock_refs),
     68	       (list_empty(&lock->ast_list) ? 'y' : 'n'),
     69	       (lock->ast_pending ? 'y' : 'n'),
     70	       (list_empty(&lock->bast_list) ? 'y' : 'n'),
     71	       (lock->bast_pending ? 'y' : 'n'),
     72	       (lock->convert_pending ? 'y' : 'n'),
     73	       (lock->lock_pending ? 'y' : 'n'),
     74	       (lock->cancel_pending ? 'y' : 'n'),
     75	       (lock->unlock_pending ? 'y' : 'n'));
     76
     77	spin_unlock(&lock->spinlock);
     78}
     79
     80void __dlm_print_one_lock_resource(struct dlm_lock_resource *res)
     81{
     82	struct dlm_lock *lock;
     83	char buf[DLM_LOCKID_NAME_MAX];
     84
     85	assert_spin_locked(&res->spinlock);
     86
     87	stringify_lockname(res->lockname.name, res->lockname.len,
     88			   buf, sizeof(buf));
     89	printk("lockres: %s, owner=%u, state=%u\n",
     90	       buf, res->owner, res->state);
     91	printk("  last used: %lu, refcnt: %u, on purge list: %s\n",
     92	       res->last_used, kref_read(&res->refs),
     93	       list_empty(&res->purge) ? "no" : "yes");
     94	printk("  on dirty list: %s, on reco list: %s, "
     95	       "migrating pending: %s\n",
     96	       list_empty(&res->dirty) ? "no" : "yes",
     97	       list_empty(&res->recovering) ? "no" : "yes",
     98	       res->migration_pending ? "yes" : "no");
     99	printk("  inflight locks: %d, asts reserved: %d\n",
    100	       res->inflight_locks, atomic_read(&res->asts_reserved));
    101	dlm_print_lockres_refmap(res);
    102	printk("  granted queue:\n");
    103	list_for_each_entry(lock, &res->granted, list) {
    104		__dlm_print_lock(lock);
    105	}
    106	printk("  converting queue:\n");
    107	list_for_each_entry(lock, &res->converting, list) {
    108		__dlm_print_lock(lock);
    109	}
    110	printk("  blocked queue:\n");
    111	list_for_each_entry(lock, &res->blocked, list) {
    112		__dlm_print_lock(lock);
    113	}
    114}
    115
    116void dlm_print_one_lock(struct dlm_lock *lockid)
    117{
    118	dlm_print_one_lock_resource(lockid->lockres);
    119}
    120EXPORT_SYMBOL_GPL(dlm_print_one_lock);
    121
    122static const char *dlm_errnames[] = {
    123	[DLM_NORMAL] =			"DLM_NORMAL",
    124	[DLM_GRANTED] =			"DLM_GRANTED",
    125	[DLM_DENIED] =			"DLM_DENIED",
    126	[DLM_DENIED_NOLOCKS] =		"DLM_DENIED_NOLOCKS",
    127	[DLM_WORKING] =			"DLM_WORKING",
    128	[DLM_BLOCKED] =			"DLM_BLOCKED",
    129	[DLM_BLOCKED_ORPHAN] =		"DLM_BLOCKED_ORPHAN",
    130	[DLM_DENIED_GRACE_PERIOD] =	"DLM_DENIED_GRACE_PERIOD",
    131	[DLM_SYSERR] =			"DLM_SYSERR",
    132	[DLM_NOSUPPORT] =		"DLM_NOSUPPORT",
    133	[DLM_CANCELGRANT] =		"DLM_CANCELGRANT",
    134	[DLM_IVLOCKID] =		"DLM_IVLOCKID",
    135	[DLM_SYNC] =			"DLM_SYNC",
    136	[DLM_BADTYPE] =			"DLM_BADTYPE",
    137	[DLM_BADRESOURCE] =		"DLM_BADRESOURCE",
    138	[DLM_MAXHANDLES] =		"DLM_MAXHANDLES",
    139	[DLM_NOCLINFO] =		"DLM_NOCLINFO",
    140	[DLM_NOLOCKMGR] =		"DLM_NOLOCKMGR",
    141	[DLM_NOPURGED] =		"DLM_NOPURGED",
    142	[DLM_BADARGS] =			"DLM_BADARGS",
    143	[DLM_VOID] =			"DLM_VOID",
    144	[DLM_NOTQUEUED] =		"DLM_NOTQUEUED",
    145	[DLM_IVBUFLEN] =		"DLM_IVBUFLEN",
    146	[DLM_CVTUNGRANT] =		"DLM_CVTUNGRANT",
    147	[DLM_BADPARAM] =		"DLM_BADPARAM",
    148	[DLM_VALNOTVALID] =		"DLM_VALNOTVALID",
    149	[DLM_REJECTED] =		"DLM_REJECTED",
    150	[DLM_ABORT] =			"DLM_ABORT",
    151	[DLM_CANCEL] =			"DLM_CANCEL",
    152	[DLM_IVRESHANDLE] =		"DLM_IVRESHANDLE",
    153	[DLM_DEADLOCK] =		"DLM_DEADLOCK",
    154	[DLM_DENIED_NOASTS] =		"DLM_DENIED_NOASTS",
    155	[DLM_FORWARD] =			"DLM_FORWARD",
    156	[DLM_TIMEOUT] =			"DLM_TIMEOUT",
    157	[DLM_IVGROUPID] =		"DLM_IVGROUPID",
    158	[DLM_VERS_CONFLICT] =		"DLM_VERS_CONFLICT",
    159	[DLM_BAD_DEVICE_PATH] =		"DLM_BAD_DEVICE_PATH",
    160	[DLM_NO_DEVICE_PERMISSION] =	"DLM_NO_DEVICE_PERMISSION",
    161	[DLM_NO_CONTROL_DEVICE ] =	"DLM_NO_CONTROL_DEVICE ",
    162	[DLM_RECOVERING] =		"DLM_RECOVERING",
    163	[DLM_MIGRATING] =		"DLM_MIGRATING",
    164	[DLM_MAXSTATS] =		"DLM_MAXSTATS",
    165};
    166
    167static const char *dlm_errmsgs[] = {
    168	[DLM_NORMAL] = 			"request in progress",
    169	[DLM_GRANTED] = 		"request granted",
    170	[DLM_DENIED] = 			"request denied",
    171	[DLM_DENIED_NOLOCKS] = 		"request denied, out of system resources",
    172	[DLM_WORKING] = 		"async request in progress",
    173	[DLM_BLOCKED] = 		"lock request blocked",
    174	[DLM_BLOCKED_ORPHAN] = 		"lock request blocked by a orphan lock",
    175	[DLM_DENIED_GRACE_PERIOD] = 	"topological change in progress",
    176	[DLM_SYSERR] = 			"system error",
    177	[DLM_NOSUPPORT] = 		"unsupported",
    178	[DLM_CANCELGRANT] = 		"can't cancel convert: already granted",
    179	[DLM_IVLOCKID] = 		"bad lockid",
    180	[DLM_SYNC] = 			"synchronous request granted",
    181	[DLM_BADTYPE] = 		"bad resource type",
    182	[DLM_BADRESOURCE] = 		"bad resource handle",
    183	[DLM_MAXHANDLES] = 		"no more resource handles",
    184	[DLM_NOCLINFO] = 		"can't contact cluster manager",
    185	[DLM_NOLOCKMGR] = 		"can't contact lock manager",
    186	[DLM_NOPURGED] = 		"can't contact purge daemon",
    187	[DLM_BADARGS] = 		"bad api args",
    188	[DLM_VOID] = 			"no status",
    189	[DLM_NOTQUEUED] = 		"NOQUEUE was specified and request failed",
    190	[DLM_IVBUFLEN] = 		"invalid resource name length",
    191	[DLM_CVTUNGRANT] = 		"attempted to convert ungranted lock",
    192	[DLM_BADPARAM] = 		"invalid lock mode specified",
    193	[DLM_VALNOTVALID] = 		"value block has been invalidated",
    194	[DLM_REJECTED] = 		"request rejected, unrecognized client",
    195	[DLM_ABORT] = 			"blocked lock request cancelled",
    196	[DLM_CANCEL] = 			"conversion request cancelled",
    197	[DLM_IVRESHANDLE] = 		"invalid resource handle",
    198	[DLM_DEADLOCK] = 		"deadlock recovery refused this request",
    199	[DLM_DENIED_NOASTS] = 		"failed to allocate AST",
    200	[DLM_FORWARD] = 		"request must wait for primary's response",
    201	[DLM_TIMEOUT] = 		"timeout value for lock has expired",
    202	[DLM_IVGROUPID] = 		"invalid group specification",
    203	[DLM_VERS_CONFLICT] = 		"version conflicts prevent request handling",
    204	[DLM_BAD_DEVICE_PATH] = 	"Locks device does not exist or path wrong",
    205	[DLM_NO_DEVICE_PERMISSION] = 	"Client has insufficient perms for device",
    206	[DLM_NO_CONTROL_DEVICE] = 	"Cannot set options on opened device ",
    207	[DLM_RECOVERING] = 		"lock resource being recovered",
    208	[DLM_MIGRATING] = 		"lock resource being migrated",
    209	[DLM_MAXSTATS] = 		"invalid error number",
    210};
    211
    212const char *dlm_errmsg(enum dlm_status err)
    213{
    214	if (err >= DLM_MAXSTATS || err < 0)
    215		return dlm_errmsgs[DLM_MAXSTATS];
    216	return dlm_errmsgs[err];
    217}
    218EXPORT_SYMBOL_GPL(dlm_errmsg);
    219
    220const char *dlm_errname(enum dlm_status err)
    221{
    222	if (err >= DLM_MAXSTATS || err < 0)
    223		return dlm_errnames[DLM_MAXSTATS];
    224	return dlm_errnames[err];
    225}
    226EXPORT_SYMBOL_GPL(dlm_errname);
    227
    228/* NOTE: This function converts a lockname into a string. It uses knowledge
    229 * of the format of the lockname that should be outside the purview of the dlm.
    230 * We are adding only to make dlm debugging slightly easier.
    231 *
    232 * For more on lockname formats, please refer to dlmglue.c and ocfs2_lockid.h.
    233 */
    234static int stringify_lockname(const char *lockname, int locklen, char *buf,
    235			      int len)
    236{
    237	int out = 0;
    238	__be64 inode_blkno_be;
    239
    240#define OCFS2_DENTRY_LOCK_INO_START	18
    241	if (*lockname == 'N') {
    242		memcpy((__be64 *)&inode_blkno_be,
    243		       (char *)&lockname[OCFS2_DENTRY_LOCK_INO_START],
    244		       sizeof(__be64));
    245		out += scnprintf(buf + out, len - out, "%.*s%08x",
    246				OCFS2_DENTRY_LOCK_INO_START - 1, lockname,
    247				(unsigned int)be64_to_cpu(inode_blkno_be));
    248	} else
    249		out += scnprintf(buf + out, len - out, "%.*s",
    250				locklen, lockname);
    251	return out;
    252}
    253
    254static int stringify_nodemap(unsigned long *nodemap, int maxnodes,
    255			     char *buf, int len)
    256{
    257	int out = 0;
    258	int i = -1;
    259
    260	while ((i = find_next_bit(nodemap, maxnodes, i + 1)) < maxnodes)
    261		out += scnprintf(buf + out, len - out, "%d ", i);
    262
    263	return out;
    264}
    265
    266static int dump_mle(struct dlm_master_list_entry *mle, char *buf, int len)
    267{
    268	int out = 0;
    269	char *mle_type;
    270
    271	if (mle->type == DLM_MLE_BLOCK)
    272		mle_type = "BLK";
    273	else if (mle->type == DLM_MLE_MASTER)
    274		mle_type = "MAS";
    275	else
    276		mle_type = "MIG";
    277
    278	out += stringify_lockname(mle->mname, mle->mnamelen, buf + out, len - out);
    279	out += scnprintf(buf + out, len - out,
    280			"\t%3s\tmas=%3u\tnew=%3u\tevt=%1d\tuse=%1d\tref=%3d\n",
    281			mle_type, mle->master, mle->new_master,
    282			!list_empty(&mle->hb_events),
    283			!!mle->inuse,
    284			kref_read(&mle->mle_refs));
    285
    286	out += scnprintf(buf + out, len - out, "Maybe=");
    287	out += stringify_nodemap(mle->maybe_map, O2NM_MAX_NODES,
    288				 buf + out, len - out);
    289	out += scnprintf(buf + out, len - out, "\n");
    290
    291	out += scnprintf(buf + out, len - out, "Vote=");
    292	out += stringify_nodemap(mle->vote_map, O2NM_MAX_NODES,
    293				 buf + out, len - out);
    294	out += scnprintf(buf + out, len - out, "\n");
    295
    296	out += scnprintf(buf + out, len - out, "Response=");
    297	out += stringify_nodemap(mle->response_map, O2NM_MAX_NODES,
    298				 buf + out, len - out);
    299	out += scnprintf(buf + out, len - out, "\n");
    300
    301	out += scnprintf(buf + out, len - out, "Node=");
    302	out += stringify_nodemap(mle->node_map, O2NM_MAX_NODES,
    303				 buf + out, len - out);
    304	out += scnprintf(buf + out, len - out, "\n");
    305
    306	out += scnprintf(buf + out, len - out, "\n");
    307
    308	return out;
    309}
    310
    311void dlm_print_one_mle(struct dlm_master_list_entry *mle)
    312{
    313	char *buf;
    314
    315	buf = (char *) get_zeroed_page(GFP_ATOMIC);
    316	if (buf) {
    317		dump_mle(mle, buf, PAGE_SIZE - 1);
    318		free_page((unsigned long)buf);
    319	}
    320}
    321
    322#ifdef CONFIG_DEBUG_FS
    323
    324static struct dentry *dlm_debugfs_root;
    325
    326#define DLM_DEBUGFS_DIR				"o2dlm"
    327#define DLM_DEBUGFS_DLM_STATE			"dlm_state"
    328#define DLM_DEBUGFS_LOCKING_STATE		"locking_state"
    329#define DLM_DEBUGFS_MLE_STATE			"mle_state"
    330#define DLM_DEBUGFS_PURGE_LIST			"purge_list"
    331
    332/* begin - utils funcs */
    333static int debug_release(struct inode *inode, struct file *file)
    334{
    335	free_page((unsigned long)file->private_data);
    336	return 0;
    337}
    338
    339static ssize_t debug_read(struct file *file, char __user *buf,
    340			  size_t nbytes, loff_t *ppos)
    341{
    342	return simple_read_from_buffer(buf, nbytes, ppos, file->private_data,
    343				       i_size_read(file->f_mapping->host));
    344}
    345/* end - util funcs */
    346
    347/* begin - purge list funcs */
    348static int debug_purgelist_print(struct dlm_ctxt *dlm, char *buf, int len)
    349{
    350	struct dlm_lock_resource *res;
    351	int out = 0;
    352	unsigned long total = 0;
    353
    354	out += scnprintf(buf + out, len - out,
    355			"Dumping Purgelist for Domain: %s\n", dlm->name);
    356
    357	spin_lock(&dlm->spinlock);
    358	list_for_each_entry(res, &dlm->purge_list, purge) {
    359		++total;
    360		if (len - out < 100)
    361			continue;
    362		spin_lock(&res->spinlock);
    363		out += stringify_lockname(res->lockname.name,
    364					  res->lockname.len,
    365					  buf + out, len - out);
    366		out += scnprintf(buf + out, len - out, "\t%ld\n",
    367				(jiffies - res->last_used)/HZ);
    368		spin_unlock(&res->spinlock);
    369	}
    370	spin_unlock(&dlm->spinlock);
    371
    372	out += scnprintf(buf + out, len - out, "Total on list: %lu\n", total);
    373
    374	return out;
    375}
    376
    377static int debug_purgelist_open(struct inode *inode, struct file *file)
    378{
    379	struct dlm_ctxt *dlm = inode->i_private;
    380	char *buf = NULL;
    381
    382	buf = (char *) get_zeroed_page(GFP_NOFS);
    383	if (!buf)
    384		goto bail;
    385
    386	i_size_write(inode, debug_purgelist_print(dlm, buf, PAGE_SIZE - 1));
    387
    388	file->private_data = buf;
    389
    390	return 0;
    391bail:
    392	return -ENOMEM;
    393}
    394
    395static const struct file_operations debug_purgelist_fops = {
    396	.open =		debug_purgelist_open,
    397	.release =	debug_release,
    398	.read =		debug_read,
    399	.llseek =	generic_file_llseek,
    400};
    401/* end - purge list funcs */
    402
    403/* begin - debug mle funcs */
    404static int debug_mle_print(struct dlm_ctxt *dlm, char *buf, int len)
    405{
    406	struct dlm_master_list_entry *mle;
    407	struct hlist_head *bucket;
    408	int i, out = 0;
    409	unsigned long total = 0, longest = 0, bucket_count = 0;
    410
    411	out += scnprintf(buf + out, len - out,
    412			"Dumping MLEs for Domain: %s\n", dlm->name);
    413
    414	spin_lock(&dlm->master_lock);
    415	for (i = 0; i < DLM_HASH_BUCKETS; i++) {
    416		bucket = dlm_master_hash(dlm, i);
    417		hlist_for_each_entry(mle, bucket, master_hash_node) {
    418			++total;
    419			++bucket_count;
    420			if (len - out < 200)
    421				continue;
    422			out += dump_mle(mle, buf + out, len - out);
    423		}
    424		longest = max(longest, bucket_count);
    425		bucket_count = 0;
    426	}
    427	spin_unlock(&dlm->master_lock);
    428
    429	out += scnprintf(buf + out, len - out,
    430			"Total: %lu, Longest: %lu\n", total, longest);
    431	return out;
    432}
    433
    434static int debug_mle_open(struct inode *inode, struct file *file)
    435{
    436	struct dlm_ctxt *dlm = inode->i_private;
    437	char *buf = NULL;
    438
    439	buf = (char *) get_zeroed_page(GFP_NOFS);
    440	if (!buf)
    441		goto bail;
    442
    443	i_size_write(inode, debug_mle_print(dlm, buf, PAGE_SIZE - 1));
    444
    445	file->private_data = buf;
    446
    447	return 0;
    448bail:
    449	return -ENOMEM;
    450}
    451
    452static const struct file_operations debug_mle_fops = {
    453	.open =		debug_mle_open,
    454	.release =	debug_release,
    455	.read =		debug_read,
    456	.llseek =	generic_file_llseek,
    457};
    458
    459/* end - debug mle funcs */
    460
    461/* begin - debug lockres funcs */
    462static int dump_lock(struct dlm_lock *lock, int list_type, char *buf, int len)
    463{
    464	int out;
    465
    466#define DEBUG_LOCK_VERSION	1
    467	spin_lock(&lock->spinlock);
    468	out = scnprintf(buf, len, "LOCK:%d,%d,%d,%d,%d,%d:%lld,%d,%d,%d,%d,%d,"
    469		       "%d,%d,%d,%d\n",
    470		       DEBUG_LOCK_VERSION,
    471		       list_type, lock->ml.type, lock->ml.convert_type,
    472		       lock->ml.node,
    473		       dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
    474		       dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
    475		       !list_empty(&lock->ast_list),
    476		       !list_empty(&lock->bast_list),
    477		       lock->ast_pending, lock->bast_pending,
    478		       lock->convert_pending, lock->lock_pending,
    479		       lock->cancel_pending, lock->unlock_pending,
    480		       kref_read(&lock->lock_refs));
    481	spin_unlock(&lock->spinlock);
    482
    483	return out;
    484}
    485
    486static int dump_lockres(struct dlm_lock_resource *res, char *buf, int len)
    487{
    488	struct dlm_lock *lock;
    489	int i;
    490	int out = 0;
    491
    492	out += scnprintf(buf + out, len - out, "NAME:");
    493	out += stringify_lockname(res->lockname.name, res->lockname.len,
    494				  buf + out, len - out);
    495	out += scnprintf(buf + out, len - out, "\n");
    496
    497#define DEBUG_LRES_VERSION	1
    498	out += scnprintf(buf + out, len - out,
    499			"LRES:%d,%d,%d,%ld,%d,%d,%d,%d,%d,%d,%d\n",
    500			DEBUG_LRES_VERSION,
    501			res->owner, res->state, res->last_used,
    502			!list_empty(&res->purge),
    503			!list_empty(&res->dirty),
    504			!list_empty(&res->recovering),
    505			res->inflight_locks, res->migration_pending,
    506			atomic_read(&res->asts_reserved),
    507			kref_read(&res->refs));
    508
    509	/* refmap */
    510	out += scnprintf(buf + out, len - out, "RMAP:");
    511	out += stringify_nodemap(res->refmap, O2NM_MAX_NODES,
    512				 buf + out, len - out);
    513	out += scnprintf(buf + out, len - out, "\n");
    514
    515	/* lvb */
    516	out += scnprintf(buf + out, len - out, "LVBX:");
    517	for (i = 0; i < DLM_LVB_LEN; i++)
    518		out += scnprintf(buf + out, len - out,
    519					"%02x", (unsigned char)res->lvb[i]);
    520	out += scnprintf(buf + out, len - out, "\n");
    521
    522	/* granted */
    523	list_for_each_entry(lock, &res->granted, list)
    524		out += dump_lock(lock, 0, buf + out, len - out);
    525
    526	/* converting */
    527	list_for_each_entry(lock, &res->converting, list)
    528		out += dump_lock(lock, 1, buf + out, len - out);
    529
    530	/* blocked */
    531	list_for_each_entry(lock, &res->blocked, list)
    532		out += dump_lock(lock, 2, buf + out, len - out);
    533
    534	out += scnprintf(buf + out, len - out, "\n");
    535
    536	return out;
    537}
    538
    539static void *lockres_seq_start(struct seq_file *m, loff_t *pos)
    540{
    541	struct debug_lockres *dl = m->private;
    542	struct dlm_ctxt *dlm = dl->dl_ctxt;
    543	struct dlm_lock_resource *oldres = dl->dl_res;
    544	struct dlm_lock_resource *res = NULL, *iter;
    545	struct list_head *track_list;
    546
    547	spin_lock(&dlm->track_lock);
    548	if (oldres)
    549		track_list = &oldres->tracking;
    550	else {
    551		track_list = &dlm->tracking_list;
    552		if (list_empty(track_list)) {
    553			dl = NULL;
    554			spin_unlock(&dlm->track_lock);
    555			goto bail;
    556		}
    557	}
    558
    559	list_for_each_entry(iter, track_list, tracking) {
    560		if (&iter->tracking != &dlm->tracking_list) {
    561			dlm_lockres_get(iter);
    562			res = iter;
    563		}
    564		break;
    565	}
    566	spin_unlock(&dlm->track_lock);
    567
    568	if (oldres)
    569		dlm_lockres_put(oldres);
    570
    571	dl->dl_res = res;
    572
    573	if (res) {
    574		spin_lock(&res->spinlock);
    575		dump_lockres(res, dl->dl_buf, dl->dl_len - 1);
    576		spin_unlock(&res->spinlock);
    577	} else
    578		dl = NULL;
    579
    580bail:
    581	/* passed to seq_show */
    582	return dl;
    583}
    584
    585static void lockres_seq_stop(struct seq_file *m, void *v)
    586{
    587}
    588
    589static void *lockres_seq_next(struct seq_file *m, void *v, loff_t *pos)
    590{
    591	return NULL;
    592}
    593
    594static int lockres_seq_show(struct seq_file *s, void *v)
    595{
    596	struct debug_lockres *dl = (struct debug_lockres *)v;
    597
    598	seq_printf(s, "%s", dl->dl_buf);
    599
    600	return 0;
    601}
    602
    603static const struct seq_operations debug_lockres_ops = {
    604	.start =	lockres_seq_start,
    605	.stop =		lockres_seq_stop,
    606	.next =		lockres_seq_next,
    607	.show =		lockres_seq_show,
    608};
    609
    610static int debug_lockres_open(struct inode *inode, struct file *file)
    611{
    612	struct dlm_ctxt *dlm = inode->i_private;
    613	struct debug_lockres *dl;
    614	void *buf;
    615
    616	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
    617	if (!buf)
    618		goto bail;
    619
    620	dl = __seq_open_private(file, &debug_lockres_ops, sizeof(*dl));
    621	if (!dl)
    622		goto bailfree;
    623
    624	dl->dl_len = PAGE_SIZE;
    625	dl->dl_buf = buf;
    626
    627	dlm_grab(dlm);
    628	dl->dl_ctxt = dlm;
    629
    630	return 0;
    631
    632bailfree:
    633	kfree(buf);
    634bail:
    635	mlog_errno(-ENOMEM);
    636	return -ENOMEM;
    637}
    638
    639static int debug_lockres_release(struct inode *inode, struct file *file)
    640{
    641	struct seq_file *seq = file->private_data;
    642	struct debug_lockres *dl = (struct debug_lockres *)seq->private;
    643
    644	if (dl->dl_res)
    645		dlm_lockres_put(dl->dl_res);
    646	dlm_put(dl->dl_ctxt);
    647	kfree(dl->dl_buf);
    648	return seq_release_private(inode, file);
    649}
    650
    651static const struct file_operations debug_lockres_fops = {
    652	.open =		debug_lockres_open,
    653	.release =	debug_lockres_release,
    654	.read =		seq_read,
    655	.llseek =	seq_lseek,
    656};
    657/* end - debug lockres funcs */
    658
    659/* begin - debug state funcs */
    660static int debug_state_print(struct dlm_ctxt *dlm, char *buf, int len)
    661{
    662	int out = 0;
    663	struct dlm_reco_node_data *node;
    664	char *state;
    665	int cur_mles = 0, tot_mles = 0;
    666	int i;
    667
    668	spin_lock(&dlm->spinlock);
    669
    670	switch (dlm->dlm_state) {
    671	case DLM_CTXT_NEW:
    672		state = "NEW"; break;
    673	case DLM_CTXT_JOINED:
    674		state = "JOINED"; break;
    675	case DLM_CTXT_IN_SHUTDOWN:
    676		state = "SHUTDOWN"; break;
    677	case DLM_CTXT_LEAVING:
    678		state = "LEAVING"; break;
    679	default:
    680		state = "UNKNOWN"; break;
    681	}
    682
    683	/* Domain: xxxxxxxxxx  Key: 0xdfbac769 */
    684	out += scnprintf(buf + out, len - out,
    685			"Domain: %s  Key: 0x%08x  Protocol: %d.%d\n",
    686			dlm->name, dlm->key, dlm->dlm_locking_proto.pv_major,
    687			dlm->dlm_locking_proto.pv_minor);
    688
    689	/* Thread Pid: xxx  Node: xxx  State: xxxxx */
    690	out += scnprintf(buf + out, len - out,
    691			"Thread Pid: %d  Node: %d  State: %s\n",
    692			task_pid_nr(dlm->dlm_thread_task), dlm->node_num, state);
    693
    694	/* Number of Joins: xxx  Joining Node: xxx */
    695	out += scnprintf(buf + out, len - out,
    696			"Number of Joins: %d  Joining Node: %d\n",
    697			dlm->num_joins, dlm->joining_node);
    698
    699	/* Domain Map: xx xx xx */
    700	out += scnprintf(buf + out, len - out, "Domain Map: ");
    701	out += stringify_nodemap(dlm->domain_map, O2NM_MAX_NODES,
    702				 buf + out, len - out);
    703	out += scnprintf(buf + out, len - out, "\n");
    704
    705	/* Exit Domain Map: xx xx xx */
    706	out += scnprintf(buf + out, len - out, "Exit Domain Map: ");
    707	out += stringify_nodemap(dlm->exit_domain_map, O2NM_MAX_NODES,
    708				 buf + out, len - out);
    709	out += scnprintf(buf + out, len - out, "\n");
    710
    711	/* Live Map: xx xx xx */
    712	out += scnprintf(buf + out, len - out, "Live Map: ");
    713	out += stringify_nodemap(dlm->live_nodes_map, O2NM_MAX_NODES,
    714				 buf + out, len - out);
    715	out += scnprintf(buf + out, len - out, "\n");
    716
    717	/* Lock Resources: xxx (xxx) */
    718	out += scnprintf(buf + out, len - out,
    719			"Lock Resources: %d (%d)\n",
    720			atomic_read(&dlm->res_cur_count),
    721			atomic_read(&dlm->res_tot_count));
    722
    723	for (i = 0; i < DLM_MLE_NUM_TYPES; ++i)
    724		tot_mles += atomic_read(&dlm->mle_tot_count[i]);
    725
    726	for (i = 0; i < DLM_MLE_NUM_TYPES; ++i)
    727		cur_mles += atomic_read(&dlm->mle_cur_count[i]);
    728
    729	/* MLEs: xxx (xxx) */
    730	out += scnprintf(buf + out, len - out,
    731			"MLEs: %d (%d)\n", cur_mles, tot_mles);
    732
    733	/*  Blocking: xxx (xxx) */
    734	out += scnprintf(buf + out, len - out,
    735			"  Blocking: %d (%d)\n",
    736			atomic_read(&dlm->mle_cur_count[DLM_MLE_BLOCK]),
    737			atomic_read(&dlm->mle_tot_count[DLM_MLE_BLOCK]));
    738
    739	/*  Mastery: xxx (xxx) */
    740	out += scnprintf(buf + out, len - out,
    741			"  Mastery: %d (%d)\n",
    742			atomic_read(&dlm->mle_cur_count[DLM_MLE_MASTER]),
    743			atomic_read(&dlm->mle_tot_count[DLM_MLE_MASTER]));
    744
    745	/*  Migration: xxx (xxx) */
    746	out += scnprintf(buf + out, len - out,
    747			"  Migration: %d (%d)\n",
    748			atomic_read(&dlm->mle_cur_count[DLM_MLE_MIGRATION]),
    749			atomic_read(&dlm->mle_tot_count[DLM_MLE_MIGRATION]));
    750
    751	/* Lists: Dirty=Empty  Purge=InUse  PendingASTs=Empty  ... */
    752	out += scnprintf(buf + out, len - out,
    753			"Lists: Dirty=%s  Purge=%s  PendingASTs=%s  "
    754			"PendingBASTs=%s\n",
    755			(list_empty(&dlm->dirty_list) ? "Empty" : "InUse"),
    756			(list_empty(&dlm->purge_list) ? "Empty" : "InUse"),
    757			(list_empty(&dlm->pending_asts) ? "Empty" : "InUse"),
    758			(list_empty(&dlm->pending_basts) ? "Empty" : "InUse"));
    759
    760	/* Purge Count: xxx  Refs: xxx */
    761	out += scnprintf(buf + out, len - out,
    762			"Purge Count: %d  Refs: %d\n", dlm->purge_count,
    763			kref_read(&dlm->dlm_refs));
    764
    765	/* Dead Node: xxx */
    766	out += scnprintf(buf + out, len - out,
    767			"Dead Node: %d\n", dlm->reco.dead_node);
    768
    769	/* What about DLM_RECO_STATE_FINALIZE? */
    770	if (dlm->reco.state == DLM_RECO_STATE_ACTIVE)
    771		state = "ACTIVE";
    772	else
    773		state = "INACTIVE";
    774
    775	/* Recovery Pid: xxxx  Master: xxx  State: xxxx */
    776	out += scnprintf(buf + out, len - out,
    777			"Recovery Pid: %d  Master: %d  State: %s\n",
    778			task_pid_nr(dlm->dlm_reco_thread_task),
    779			dlm->reco.new_master, state);
    780
    781	/* Recovery Map: xx xx */
    782	out += scnprintf(buf + out, len - out, "Recovery Map: ");
    783	out += stringify_nodemap(dlm->recovery_map, O2NM_MAX_NODES,
    784				 buf + out, len - out);
    785	out += scnprintf(buf + out, len - out, "\n");
    786
    787	/* Recovery Node State: */
    788	out += scnprintf(buf + out, len - out, "Recovery Node State:\n");
    789	list_for_each_entry(node, &dlm->reco.node_data, list) {
    790		switch (node->state) {
    791		case DLM_RECO_NODE_DATA_INIT:
    792			state = "INIT";
    793			break;
    794		case DLM_RECO_NODE_DATA_REQUESTING:
    795			state = "REQUESTING";
    796			break;
    797		case DLM_RECO_NODE_DATA_DEAD:
    798			state = "DEAD";
    799			break;
    800		case DLM_RECO_NODE_DATA_RECEIVING:
    801			state = "RECEIVING";
    802			break;
    803		case DLM_RECO_NODE_DATA_REQUESTED:
    804			state = "REQUESTED";
    805			break;
    806		case DLM_RECO_NODE_DATA_DONE:
    807			state = "DONE";
    808			break;
    809		case DLM_RECO_NODE_DATA_FINALIZE_SENT:
    810			state = "FINALIZE-SENT";
    811			break;
    812		default:
    813			state = "BAD";
    814			break;
    815		}
    816		out += scnprintf(buf + out, len - out, "\t%u - %s\n",
    817				node->node_num, state);
    818	}
    819
    820	spin_unlock(&dlm->spinlock);
    821
    822	return out;
    823}
    824
    825static int debug_state_open(struct inode *inode, struct file *file)
    826{
    827	struct dlm_ctxt *dlm = inode->i_private;
    828	char *buf = NULL;
    829
    830	buf = (char *) get_zeroed_page(GFP_NOFS);
    831	if (!buf)
    832		goto bail;
    833
    834	i_size_write(inode, debug_state_print(dlm, buf, PAGE_SIZE - 1));
    835
    836	file->private_data = buf;
    837
    838	return 0;
    839bail:
    840	return -ENOMEM;
    841}
    842
    843static const struct file_operations debug_state_fops = {
    844	.open =		debug_state_open,
    845	.release =	debug_release,
    846	.read =		debug_read,
    847	.llseek =	generic_file_llseek,
    848};
    849/* end  - debug state funcs */
    850
    851/* files in subroot */
    852void dlm_debug_init(struct dlm_ctxt *dlm)
    853{
    854	/* for dumping dlm_ctxt */
    855	debugfs_create_file(DLM_DEBUGFS_DLM_STATE, S_IFREG|S_IRUSR,
    856			    dlm->dlm_debugfs_subroot, dlm, &debug_state_fops);
    857
    858	/* for dumping lockres */
    859	debugfs_create_file(DLM_DEBUGFS_LOCKING_STATE, S_IFREG|S_IRUSR,
    860			    dlm->dlm_debugfs_subroot, dlm, &debug_lockres_fops);
    861
    862	/* for dumping mles */
    863	debugfs_create_file(DLM_DEBUGFS_MLE_STATE, S_IFREG|S_IRUSR,
    864			    dlm->dlm_debugfs_subroot, dlm, &debug_mle_fops);
    865
    866	/* for dumping lockres on the purge list */
    867	debugfs_create_file(DLM_DEBUGFS_PURGE_LIST, S_IFREG|S_IRUSR,
    868			    dlm->dlm_debugfs_subroot, dlm,
    869			    &debug_purgelist_fops);
    870}
    871
    872/* subroot - domain dir */
    873void dlm_create_debugfs_subroot(struct dlm_ctxt *dlm)
    874{
    875	dlm->dlm_debugfs_subroot = debugfs_create_dir(dlm->name,
    876						      dlm_debugfs_root);
    877}
    878
    879void dlm_destroy_debugfs_subroot(struct dlm_ctxt *dlm)
    880{
    881	debugfs_remove_recursive(dlm->dlm_debugfs_subroot);
    882}
    883
    884/* debugfs root */
    885void dlm_create_debugfs_root(void)
    886{
    887	dlm_debugfs_root = debugfs_create_dir(DLM_DEBUGFS_DIR, NULL);
    888}
    889
    890void dlm_destroy_debugfs_root(void)
    891{
    892	debugfs_remove(dlm_debugfs_root);
    893}
    894#endif	/* CONFIG_DEBUG_FS */